1536 lines
65 KiB
C#
1536 lines
65 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity;
|
|
using System.Linq;
|
|
using EnVisage.Models;
|
|
using System.Web.Mvc;
|
|
|
|
namespace EnVisage.Code.BLL
|
|
{
|
|
/// <summary>
|
|
/// Provides ability to manage fiscal calendar.
|
|
/// </summary>
|
|
public class FiscalCalendarManager : IDisposable
|
|
{
|
|
#region Constructors
|
|
|
|
private readonly EnVisageEntities _dbContext;
|
|
private readonly bool _isContexLocal = false;
|
|
|
|
public FiscalCalendarManager(EnVisageEntities dbContext = null)
|
|
{
|
|
if (dbContext == null)
|
|
{
|
|
_dbContext = new EnVisageEntities();
|
|
_isContexLocal = true;
|
|
}
|
|
else
|
|
{
|
|
_dbContext = dbContext;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_isContexLocal)
|
|
_dbContext.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
#region Fiscal Calendar Settings
|
|
|
|
/// <summary>
|
|
/// Returns Fiscal Calendar Settings records
|
|
/// </summary>
|
|
/// <param name="timePoint">Current time point to mark Active, Inactive and Future records</param>
|
|
/// <returns></returns>
|
|
public FiscalCalendarListModel GetCalendarSettingsItems(DateTime timePoint)
|
|
{
|
|
bool activeItemSet = false;
|
|
DateTime validTimePoint = timePoint.Date;
|
|
FiscalCalendarListModel result = new FiscalCalendarListModel();
|
|
|
|
List<FiscalCalendarSetting> items =
|
|
(from FiscalCalendarSetting rec in _dbContext.FiscalCalendarSettings
|
|
orderby rec.EffectiveChangeDate descending
|
|
where true
|
|
select rec).Take(10).ToList();
|
|
|
|
for (int index = 0; index < items.Count; index++)
|
|
{
|
|
FiscalCalendarModel currentItem = (FiscalCalendarModel)items[index];
|
|
result.Items.Add(currentItem);
|
|
|
|
if (currentItem.EffectiveChangeDate.HasValue && (currentItem.EffectiveChangeDate.Value > validTimePoint))
|
|
{
|
|
currentItem.Status = FiscalCalendarModel.FiscalCalendarSettingStatus.Future;
|
|
}
|
|
else
|
|
{
|
|
if (!activeItemSet)
|
|
{
|
|
currentItem.Status = FiscalCalendarModel.FiscalCalendarSettingStatus.Active;
|
|
activeItemSet = true;
|
|
}
|
|
else
|
|
{
|
|
currentItem.Status = FiscalCalendarModel.FiscalCalendarSettingStatus.Inactive;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public FiscalCalendarModel GetCalendarSettingsItem(Guid? id)
|
|
{
|
|
if (!id.HasValue || id.Value == Guid.Empty)
|
|
return null;
|
|
|
|
var record = _dbContext.FiscalCalendarSettings.Find(id.Value);
|
|
var result = (FiscalCalendarModel)record;
|
|
|
|
return result;
|
|
}
|
|
|
|
public static IEnumerable<SelectListItem> GetCalendarTypes()
|
|
{
|
|
return new List<SelectListItem>
|
|
{
|
|
new SelectListItem
|
|
{
|
|
Text = FiscalCalendarModel.FiscalCalendarType.CalendarYear.ToDisplayValue(),
|
|
Value = FiscalCalendarModel.FiscalCalendarType.CalendarYear.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = FiscalCalendarModel.FiscalCalendarType.Calendar445.ToDisplayValue(),
|
|
Value = FiscalCalendarModel.FiscalCalendarType.Calendar445.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = FiscalCalendarModel.FiscalCalendarType.Calendar454.ToDisplayValue(),
|
|
Value = FiscalCalendarModel.FiscalCalendarType.Calendar454.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = FiscalCalendarModel.FiscalCalendarType.Calendar544.ToDisplayValue(),
|
|
Value = FiscalCalendarModel.FiscalCalendarType.Calendar544.ToString()
|
|
},
|
|
};
|
|
}
|
|
|
|
public static IEnumerable<SelectListItem> GetWeekendings()
|
|
{
|
|
return new List<SelectListItem>
|
|
{
|
|
new SelectListItem
|
|
{
|
|
Text = DayOfWeek.Sunday.ToDisplayValue(),
|
|
Value = DayOfWeek.Sunday.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = DayOfWeek.Monday.ToDisplayValue(),
|
|
Value = DayOfWeek.Monday.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = DayOfWeek.Tuesday.ToDisplayValue(),
|
|
Value = DayOfWeek.Tuesday.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = DayOfWeek.Wednesday.ToDisplayValue(),
|
|
Value = DayOfWeek.Wednesday.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = DayOfWeek.Thursday.ToDisplayValue(),
|
|
Value = DayOfWeek.Thursday.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = DayOfWeek.Friday.ToDisplayValue(),
|
|
Value = DayOfWeek.Friday.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = DayOfWeek.Saturday.ToDisplayValue(),
|
|
Value = DayOfWeek.Saturday.ToString()
|
|
},
|
|
};
|
|
}
|
|
|
|
public static IEnumerable<SelectListItem> GetYearTypes()
|
|
{
|
|
return new List<SelectListItem>
|
|
{
|
|
new SelectListItem
|
|
{
|
|
Text = FiscalCalendarModel.CalendarYearType.StandardYear.ToDisplayValue(),
|
|
Value = FiscalCalendarModel.CalendarYearType.StandardYear.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = FiscalCalendarModel.CalendarYearType.Only52Weeks.ToDisplayValue(),
|
|
Value = FiscalCalendarModel.CalendarYearType.Only52Weeks.ToString()
|
|
},
|
|
new SelectListItem
|
|
{
|
|
Text = FiscalCalendarModel.CalendarYearType.LastWeekDay.ToDisplayValue(),
|
|
Value = FiscalCalendarModel.CalendarYearType.LastWeekDay.ToString()
|
|
},
|
|
};
|
|
}
|
|
|
|
public void SaveFiscalCalendarSettings(FiscalCalendarModel model, DateTime timePoint)
|
|
{
|
|
if (model == null)
|
|
throw new ArgumentNullException("model");
|
|
|
|
DateTime validTimePoint = timePoint.Date;
|
|
FiscalCalendarSetting itemToSave = new FiscalCalendarSetting();
|
|
FiscalCalendarModel activeItem = this.GetActiveCalendarSettingsItem(validTimePoint);
|
|
|
|
if (activeItem != null)
|
|
{
|
|
// If pending to activation calendar setting exist, we should remove them
|
|
this.RemoveFutureCalendarSettingsItems(validTimePoint);
|
|
|
|
if (activeItem.EffectiveChangeDate.HasValue && model.EffectiveChangeDate.HasValue &&
|
|
(activeItem.EffectiveChangeDate.Value == model.EffectiveChangeDate.Value))
|
|
{
|
|
// Remove active item, because new item has the same EffStartDate as Active one
|
|
this.RemoveCalendarSettingsItem(activeItem.Id);
|
|
}
|
|
}
|
|
|
|
// Create new calendar settings
|
|
model.CopyTo(itemToSave);
|
|
itemToSave.Id = Guid.NewGuid();
|
|
_dbContext.FiscalCalendarSettings.Add(itemToSave);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns active Fiscal Calendar record for given time point
|
|
/// </summary>
|
|
/// <param name="timePoint"></param>
|
|
/// <returns></returns>
|
|
public FiscalCalendarModel GetActiveCalendarSettingsItem(DateTime timePoint)
|
|
{
|
|
DateTime validTimePoint = timePoint.Date;
|
|
|
|
FiscalCalendarSetting rec =
|
|
(from FiscalCalendarSetting item in _dbContext.FiscalCalendarSettings
|
|
orderby item.EffectiveChangeDate descending
|
|
where item.EffectiveChangeDate <= validTimePoint
|
|
select item)
|
|
.FirstOrDefault();
|
|
|
|
FiscalCalendarModel result = (FiscalCalendarModel)rec;
|
|
|
|
if (result != null)
|
|
{
|
|
// Set status for record. We get active record for the timePoint, so status should be Active
|
|
result.Status = FiscalCalendarModel.FiscalCalendarSettingStatus.Active;
|
|
|
|
FiscalCalendarSetting nextRec =
|
|
(from FiscalCalendarSetting item in _dbContext.FiscalCalendarSettings
|
|
orderby item.EffectiveChangeDate ascending
|
|
where item.EffectiveChangeDate > validTimePoint
|
|
select item)
|
|
.FirstOrDefault();
|
|
|
|
if (nextRec != null)
|
|
result.ValidTo = nextRec.EffectiveChangeDate.AddDays(-1);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all future Fiscal Calendar records relative to given time point
|
|
/// </summary>
|
|
/// <param name="timePoint"></param>
|
|
protected void RemoveFutureCalendarSettingsItems(DateTime timePoint)
|
|
{
|
|
var itemsToRemove = _dbContext.FiscalCalendarSettings.Where(t => t.EffectiveChangeDate > timePoint);
|
|
|
|
if (itemsToRemove.Count() > 0)
|
|
_dbContext.FiscalCalendarSettings.RemoveRange(itemsToRemove);
|
|
}
|
|
|
|
protected void RemoveCalendarSettingsItem(Guid id)
|
|
{
|
|
var foundItems = _dbContext.FiscalCalendarSettings.Where(t => t.Id.Equals(id));
|
|
|
|
if (foundItems.Count() > 0)
|
|
_dbContext.FiscalCalendarSettings.RemoveRange(foundItems);
|
|
}
|
|
|
|
#endregion
|
|
#region Pended to remove (after implementation of in-memory calendar)
|
|
|
|
//[Obsolete]
|
|
//public void UpdateFiscalCalendars(FiscalCalendarModel model)
|
|
//{
|
|
// switch (model.Type)
|
|
// {
|
|
// case FiscalCalendarModel.FiscalCalendarType.Calendar445:
|
|
// case FiscalCalendarModel.FiscalCalendarType.Calendar454:
|
|
// case FiscalCalendarModel.FiscalCalendarType.Calendar544:
|
|
// Apply445Year(model);
|
|
// break;
|
|
// default:
|
|
// ApplyCalendarYear(model);
|
|
// break;
|
|
// }
|
|
//}
|
|
|
|
///// <summary>
|
|
///// Generate fiscal calendar periods by the Calendar Year algo. 52 weeks in the year. Last 1-2 days will be be adjusted.
|
|
///// </summary>
|
|
///// <param name="model"></param>
|
|
//private void ApplyCalendarYear(FiscalCalendarModel model)
|
|
//{
|
|
// var startDate = model.CurrentYearStartDate ?? DateTime.Today;
|
|
// var periodEndDate = startDate.AddYears(Settings.Default.GenerateCalendarYears);
|
|
// var weekEndDate = startDate.AddDays(6);
|
|
// var weeksList = new List<FiscalCalendar>(periodEndDate.Subtract(startDate).Days / 7); // approx number of weeks
|
|
// var monthList = new List<FiscalCalendar>(periodEndDate.Subtract(startDate).Days / 30); // approx number of months
|
|
// var quarterList = new List<FiscalCalendar>(periodEndDate.Subtract(startDate).Days / 91); // approx number of quarters
|
|
// var yearList = new List<FiscalCalendar>(Settings.Default.GenerateCalendarYears);
|
|
// FiscalCalendar prevWeek = null;
|
|
// //FiscalCalendar prevMonth = null; // SA. Commented because are unused. Compliller show warnings
|
|
// //FiscalCalendar prevQuarter = null;
|
|
// //FiscalCalendar prevYear = null;
|
|
|
|
// #region Load one latest record of each period type before startDate
|
|
|
|
// #endregion
|
|
|
|
// #region Create adjustment between last enddate from loaded record and startDate
|
|
|
|
// #endregion
|
|
|
|
// #region Generate records from startDate to periodEndDate
|
|
// int weekPeriodInt = 1, monthWeekNum = 1, monthNum = 1, quarterNum = 1;
|
|
// while (weekEndDate < periodEndDate)
|
|
// {
|
|
// #region Create a new year if new week is in the new calendar year
|
|
// var year = yearList.LastOrDefault();
|
|
// if (year == null || year.EndDate < weekEndDate)
|
|
// {
|
|
// year = new FiscalCalendar
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = Constants.FISCAL_YEAR_NAME_TEMPLATE,
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Year,
|
|
// YearInt = weekEndDate.Year,
|
|
// QuarterInt = 4,
|
|
// PeriodInt = 1,
|
|
// StartDate = new DateTime(weekEndDate.Year, 1, 1),
|
|
// EndDate = new DateTime(weekEndDate.Year, 12, 31),
|
|
// SystemName = string.Format(Constants.FISCAL_YEAR_SYSTEMNAME_TEMPLATE, (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 0
|
|
// };
|
|
// yearList.Add(year);
|
|
// quarterNum = 1; // reset quarter of the year number
|
|
// monthNum = 1; // reset month of the year number;
|
|
// weekPeriodInt = 1; // reset week of the year number;
|
|
// }
|
|
// #endregion
|
|
|
|
// #region Create a new quarter if new week is in the new quarter
|
|
// var quarter = quarterList.LastOrDefault();
|
|
// if (quarter == null || quarter.EndDate < weekEndDate)
|
|
// {
|
|
// quarter = new FiscalCalendar
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = string.Format(Constants.FISCAL_QUARTER_NAME_TEMPLATE, quarterNum),
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Quarter,
|
|
// YearInt = year.YearInt,
|
|
// QuarterInt = quarterNum,
|
|
// PeriodInt = quarterNum,
|
|
// StartDate = (prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1),
|
|
// EndDate = ((prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1)).AddDays(90),// add 7 days * 13 weeks in quarter = 91 days
|
|
// SystemName = string.Format(Constants.FISCAL_QUARTER_SYSTEMNAME_TEMPLATE, quarterNum, (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 0
|
|
// };
|
|
// if (quarterNum == 4)
|
|
// quarter.EndDate = new DateTime(quarter.EndDate.Year, 12, 31);
|
|
// quarterList.Add(quarter);
|
|
// quarterNum++;
|
|
// }
|
|
// #endregion
|
|
|
|
// #region Create a new month if new week is in the new month
|
|
// var month = monthList.LastOrDefault();
|
|
// if (month == null || month.EndDate < weekEndDate)
|
|
// {
|
|
// month = new FiscalCalendar
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = string.Format(Constants.FISCAL_MONTH_NAME_TEMPLATE, weekEndDate.ToString("MMM").ToUpper()),
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Month,
|
|
// YearInt = year.YearInt,
|
|
// QuarterInt = quarterNum - 1,
|
|
// PeriodInt = monthNum,
|
|
// StartDate = (prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1),
|
|
// EndDate = ((prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1)).AddDays(27),// add 7 days * 4 weeks in month = 28 days
|
|
// SystemName = string.Format(Constants.FISCAL_MONTH_SYSTEMNAME_TEMPLATE, weekEndDate.ToString("MMM").ToUpper(), (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 0
|
|
// };
|
|
|
|
// // add 5th week to the 1st month of the quarter
|
|
// if (monthNum % 3 == 0)
|
|
// {
|
|
// month.EndDate = month.EndDate.AddDays(7);
|
|
// }
|
|
// // if we can place a 14th quarter week before 1st of January of next year then place it into the last quarter
|
|
// if (quarter.QuarterInt == 4 && month.PeriodInt == 12)
|
|
// month.EndDate = new DateTime(month.EndDate.Year, 12, 31);
|
|
// monthList.Add(month);
|
|
// monthNum++;
|
|
// monthWeekNum = 1; // reset week of the month number
|
|
// }
|
|
// #endregion
|
|
|
|
// // create a new week record
|
|
|
|
// var week = new FiscalCalendar
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = string.Format(Constants.FISCAL_WEEK_NAME_TEMPLATE, month.Name.ToUpper(), monthWeekNum),
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Week,
|
|
// YearInt = year.YearInt,
|
|
// QuarterInt = quarterNum - 1,
|
|
// PeriodInt = weekPeriodInt,
|
|
// StartDate = (prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1),
|
|
// EndDate = weekEndDate,
|
|
// SystemName = string.Format(Constants.FISCAL_WEEK_SYSTEMNAME_TEMPLATE, month.Name.ToUpper(), monthWeekNum, (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 0
|
|
// };
|
|
// weeksList.Add(week);
|
|
// // adjust remaining 1-2 days at the end of the year
|
|
// if (week.PeriodInt == 52)
|
|
// {
|
|
// monthWeekNum++;
|
|
// weekPeriodInt++;
|
|
// week = new FiscalCalendar()
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = string.Format(Constants.FISCAL_WEEK_NAME_TEMPLATE, month.Name.ToUpper(), monthWeekNum),
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Week,
|
|
// YearInt = year.YearInt,
|
|
// QuarterInt = quarterNum - 1,
|
|
// PeriodInt = weekPeriodInt,
|
|
// StartDate = week.EndDate.AddDays(1),
|
|
// EndDate = new DateTime(week.EndDate.Year, 12, 31),
|
|
// SystemName = string.Format(Constants.FISCAL_WEEK_SYSTEMNAME_TEMPLATE, month.Name.ToUpper(), monthWeekNum, (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 1
|
|
// };
|
|
// weeksList.Add(week);
|
|
// }
|
|
// monthWeekNum++;
|
|
// weekPeriodInt++;
|
|
// prevWeek = week;
|
|
// weekEndDate = week.EndDate.AddDays(7);
|
|
// }
|
|
|
|
// #endregion
|
|
|
|
// #region Save generated fiscal periods to the DB
|
|
|
|
// foreach (var FiscalCalendar in yearList)
|
|
// {
|
|
// _dbContext.FiscalCalendars.Add(FiscalCalendar);
|
|
// }
|
|
// foreach (var obj in quarterList)
|
|
// {
|
|
// _dbContext.FiscalCalendars.Add(obj);
|
|
// }
|
|
// foreach (var obj in monthList)
|
|
// {
|
|
// _dbContext.FiscalCalendars.Add(obj);
|
|
// }
|
|
// foreach (var obj in weeksList)
|
|
// {
|
|
// _dbContext.FiscalCalendars.Add(obj);
|
|
// }
|
|
// #endregion
|
|
//}
|
|
|
|
///// <summary>
|
|
///// Generate fiscal calendar periods by the 5-4-4 algo. 52/53 weeks in the year. 53rd weeks added only when it become a 7 day gap at the end of the year.
|
|
///// </summary>
|
|
///// <param name="model"></param>
|
|
//private void Apply445Year(FiscalCalendarModel model)
|
|
//{
|
|
// var startDate = model.CurrentYearStartDate ?? DateTime.Today;
|
|
// var periodEndDate = startDate.AddYears(Settings.Default.GenerateCalendarYears);
|
|
// var weekEndDate = startDate.AddDays(6);
|
|
// var weeksList = new List<FiscalCalendar>(periodEndDate.Subtract(startDate).Days / 7); // approx number of weeks
|
|
// var monthList = new List<FiscalCalendar>(periodEndDate.Subtract(startDate).Days / 30); // approx number of months
|
|
// var quarterList = new List<FiscalCalendar>(periodEndDate.Subtract(startDate).Days / 91); // approx number of quarters
|
|
// var yearList = new List<FiscalCalendar>(Settings.Default.GenerateCalendarYears);
|
|
// FiscalCalendar prevWeek = null;
|
|
// //FiscalCalendar prevMonth = null; // SA. Commented because are unused. Compiller shows warnings
|
|
// //FiscalCalendar prevQuarter = null;
|
|
// //FiscalCalendar prevYear = null;
|
|
|
|
// #region Load one latest record of each period type before startDate
|
|
|
|
// #endregion
|
|
|
|
// #region Create adjustment between last enddate from loaded record and startDate
|
|
|
|
// #endregion
|
|
|
|
// #region Generate records from startDate to periodEndDate
|
|
// //TODO: initial version, maybe required some refactoring
|
|
// int weekPeriodInt = 1, monthWeekNum = 1, monthNum = 1, quarterNum = 1;
|
|
// var isAddExtraWeek = false;
|
|
// while (weekEndDate < periodEndDate)
|
|
// {
|
|
// #region Create a new year if new week is in the new calendar year
|
|
// var year = yearList.LastOrDefault();
|
|
// if (year == null || year.EndDate < weekEndDate)
|
|
// {
|
|
// year = new FiscalCalendar
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = Constants.FISCAL_YEAR_NAME_TEMPLATE,
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Year,
|
|
// YearInt = weekEndDate.Year,
|
|
// QuarterInt = 4,
|
|
// PeriodInt = 1,
|
|
// StartDate = (prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1),
|
|
// EndDate = ((prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1)).AddDays(363),// add 7 days * 52 weeks in year = 364 days
|
|
// SystemName = string.Format(Constants.FISCAL_YEAR_SYSTEMNAME_TEMPLATE, (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 0
|
|
// };
|
|
// // if we can place a 53rd week before 1st of January of next year then do it
|
|
// isAddExtraWeek = year.EndDate.AddDays(7) < new DateTime(weekEndDate.Year + 1, startDate.Month, startDate.Day);
|
|
// if (isAddExtraWeek)
|
|
// year.EndDate = year.EndDate.AddDays(7);
|
|
// yearList.Add(year);
|
|
// quarterNum = 1; // reset quarter of the year number
|
|
// monthNum = 1; // reset month of the year number;
|
|
// weekPeriodInt = 1; // reset week of the year number;
|
|
// }
|
|
// #endregion
|
|
|
|
// #region Create a new quarter if new week is in the new quarter
|
|
// var quarter = quarterList.LastOrDefault();
|
|
// if (quarter == null || quarter.EndDate < weekEndDate)
|
|
// {
|
|
// quarter = new FiscalCalendar
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = string.Format(Constants.FISCAL_QUARTER_NAME_TEMPLATE, quarterNum),
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Quarter,
|
|
// YearInt = year.YearInt,
|
|
// QuarterInt = quarterNum,
|
|
// PeriodInt = quarterNum,
|
|
// StartDate = (prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1),
|
|
// EndDate = ((prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1)).AddDays(90),// add 7 days * 13 weeks in quarter = 91 days
|
|
// SystemName = string.Format(Constants.FISCAL_QUARTER_SYSTEMNAME_TEMPLATE, quarterNum, (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 0
|
|
// };
|
|
// // if we can place a 14th week before 1st of January of next year then place it into the last quarter
|
|
// if (isAddExtraWeek && quarterNum == 4)
|
|
// quarter.EndDate = quarter.EndDate.AddDays(7);
|
|
// quarterList.Add(quarter);
|
|
// quarterNum++;
|
|
// }
|
|
// #endregion
|
|
|
|
// #region Create a new month if new week is in the new month
|
|
// var month = monthList.LastOrDefault();
|
|
// if (month == null || month.EndDate < weekEndDate)
|
|
// {
|
|
// month = new FiscalCalendar
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = string.Format(Constants.FISCAL_MONTH_NAME_TEMPLATE, weekEndDate.ToString("MMM").ToUpper()),
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Month,
|
|
// YearInt = year.YearInt,
|
|
// QuarterInt = quarterNum - 1,
|
|
// PeriodInt = monthNum,
|
|
// StartDate = (prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1),
|
|
// EndDate = ((prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1)).AddDays(27),// add 7 days * 4 weeks in month = 28 days
|
|
// SystemName = string.Format(Constants.FISCAL_MONTH_SYSTEMNAME_TEMPLATE, weekEndDate.ToString("MMM").ToUpper(), (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 0
|
|
// };
|
|
|
|
// // add 5th week to the 1st month of the quarter
|
|
// if (monthNum % 3 == 1)
|
|
// {
|
|
// month.EndDate = month.EndDate.AddDays(7);
|
|
// }
|
|
// // if we can place a 14th quarter week before 1st of January of next year then place it into the last quarter
|
|
// if (isAddExtraWeek && quarter.QuarterInt == 4 && month.PeriodInt == 12)
|
|
// month.EndDate = month.EndDate.AddDays(7);
|
|
// monthList.Add(month);
|
|
// monthNum++;
|
|
// monthWeekNum = 1; // reset week of the month number
|
|
// }
|
|
// #endregion
|
|
|
|
// // create a new week record
|
|
// var week = new FiscalCalendar
|
|
// {
|
|
// Id = Guid.NewGuid(),
|
|
// Name = string.Format(Constants.FISCAL_WEEK_NAME_TEMPLATE, weekEndDate.ToString("MMM").ToUpper(), monthWeekNum),
|
|
// Type = (int)FiscalCalendarModel.FiscalYearType.Week,
|
|
// YearInt = year.YearInt,
|
|
// QuarterInt = quarterNum - 1,
|
|
// PeriodInt = weekPeriodInt,
|
|
// StartDate = (prevWeek == null) ? startDate : prevWeek.EndDate.AddDays(1),
|
|
// EndDate = weekEndDate,
|
|
// SystemName = string.Format(Constants.FISCAL_WEEK_SYSTEMNAME_TEMPLATE, weekEndDate.ToString("MMM").ToUpper(), monthWeekNum, (weekEndDate.Year % 100).ToString("00")),
|
|
// AdjustingPeriod = false,
|
|
// NonWorking = 0
|
|
// };
|
|
// weeksList.Add(week);
|
|
// monthWeekNum++;
|
|
// weekPeriodInt++;
|
|
// prevWeek = week;
|
|
// weekEndDate = weekEndDate.AddDays(7);
|
|
// }
|
|
// #endregion
|
|
|
|
// #region Save generated fiscal periods to the DB
|
|
|
|
// foreach (var FiscalCalendar in yearList)
|
|
// {
|
|
// _dbContext.FiscalCalendars.Add(FiscalCalendar);
|
|
// }
|
|
// foreach (var obj in quarterList)
|
|
// {
|
|
// _dbContext.FiscalCalendars.Add(obj);
|
|
// }
|
|
// foreach (var obj in monthList)
|
|
// {
|
|
// _dbContext.FiscalCalendars.Add(obj);
|
|
// }
|
|
// foreach (var obj in weeksList)
|
|
// {
|
|
// _dbContext.FiscalCalendars.Add(obj);
|
|
// }
|
|
// #endregion
|
|
//}
|
|
|
|
#endregion
|
|
#region Calendar methods for RMO (pended for refactoring)
|
|
|
|
public FiscalCalendar GetFirstWeek(DateTime? date = null)
|
|
{
|
|
var query = _dbContext.FiscalCalendars.AsNoTracking()
|
|
.Where(x => x.Type == (int)FiscalCalendarModel.FiscalYearType.Week && x.NonWorking == 0);
|
|
if (date.HasValue)
|
|
query = query.Where(x => x.EndDate >= date.Value);
|
|
|
|
return query.OrderBy(x => x.StartDate).FirstOrDefault();
|
|
}
|
|
|
|
public FiscalCalendar GetLastWeek()
|
|
{
|
|
var lastWeek = _dbContext.FiscalCalendars.AsNoTracking()
|
|
.Where(x => x.Type == (int)FiscalCalendarModel.FiscalYearType.Week && x.NonWorking == 0)
|
|
.OrderByDescending(x => x.EndDate)
|
|
.FirstOrDefault();
|
|
|
|
return lastWeek;
|
|
}
|
|
|
|
public List<FiscalCalendar> GetFiscalCalendar(FiscalCalendarModel.FiscalYearType type, DateTime? startDate, DateTime? endDate, bool onlyWorkingWeeks, bool? adjustingPeriod, bool includePartialWeeks)
|
|
{
|
|
return FilterWeeks(type, startDate, endDate, onlyWorkingWeeks, adjustingPeriod, includePartialWeeks).OrderBy(x => x.StartDate).ToList();
|
|
}
|
|
|
|
public List<FiscalCalendar> GetFiscalCalendar(FiscalCalendarModel.FiscalYearType type, List<DateTime> weeks, bool onlyWorkingWeeks, bool? adjustingPeriod, bool includePartialWeeks)
|
|
{
|
|
if (weeks == null || weeks.Count <= 0)
|
|
return new List<FiscalCalendar>();
|
|
|
|
var fc = FilterWeeks(type, null, null, onlyWorkingWeeks, adjustingPeriod, includePartialWeeks)
|
|
.Where(x => weeks.Contains(x.EndDate))
|
|
.OrderBy(x => x.StartDate)
|
|
.ToList();
|
|
|
|
return fc;
|
|
}
|
|
|
|
public Dictionary<string, Dictionary<string, List<int>>> CastWeekEndingsToTree(List<DateTime> weekEndings)
|
|
{
|
|
var weekEndingsHierarchy = weekEndings.Select(x => new
|
|
{
|
|
x.Year,
|
|
x.Month,
|
|
x.Day
|
|
})
|
|
.GroupBy(x => x.Year)
|
|
.OrderBy(x => x.Key)
|
|
.ToDictionary(year => year.Key.ToString(),
|
|
months => months.GroupBy(month => month.Month)
|
|
.OrderBy(month => month.Key)
|
|
.ToDictionary(month => month.Key.ToString(),
|
|
days => days.Select(day => day.Day).OrderBy(day => day).ToList()));
|
|
return weekEndingsHierarchy;
|
|
}
|
|
|
|
private IQueryable<FiscalCalendar> FilterWeeks(FiscalCalendarModel.FiscalYearType type, DateTime? startDate, DateTime? endDate, bool onlyWorkingWeeks, bool? adjustingPeriod, bool includePartialWeeks)
|
|
{
|
|
var query = _dbContext.FiscalCalendars.AsNoTracking().Where(x => x.Type == (int)type && (!onlyWorkingWeeks || x.NonWorking == 0));
|
|
if (startDate.HasValue)
|
|
query = query.Where(x => x.EndDate >= startDate.Value);
|
|
if (endDate.HasValue)
|
|
{
|
|
// lets suppose endDate = 2017-01-31
|
|
if (includePartialWeeks) // in this case 2017-01-28 - 2017-02-03 will be the last week in the result
|
|
query = query.Where(x => x.StartDate <= endDate.Value);
|
|
else // in this case 2017-01-21 - 2017-01-27 will be the last week in the result
|
|
query = query.Where(x => x.EndDate <= endDate.Value);
|
|
}
|
|
if (onlyWorkingWeeks)
|
|
query = query.Where(x => x.NonWorking == 0);
|
|
if (adjustingPeriod.HasValue)
|
|
query = query.Where(x => x.AdjustingPeriod == adjustingPeriod);
|
|
|
|
return query;
|
|
}
|
|
|
|
#endregion
|
|
#region Holidays
|
|
|
|
/// <summary>
|
|
/// Return total count for holidays (not versions, but groups count)
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public int GetHolidaysCount()
|
|
{
|
|
int itemCount =
|
|
(from Holiday item in _dbContext.Holidays
|
|
select item.HolidayGroupId)
|
|
.Distinct()
|
|
.Count();
|
|
return itemCount;
|
|
}
|
|
|
|
public IEnumerable<HolidayDisplayModel> GetHolidays(DateTime timePoint)
|
|
{
|
|
DateTime validTimePoint = timePoint.Date;
|
|
|
|
var activeItemsEffectiveDates =
|
|
from item in
|
|
(from Holiday h in _dbContext.Holidays
|
|
where h.EffectiveChangeDate <= validTimePoint
|
|
select new
|
|
{
|
|
h.HolidayGroupId,
|
|
h.EffectiveChangeDate
|
|
})
|
|
group item by item.HolidayGroupId into g
|
|
select new
|
|
{
|
|
HolidayGroupId = g.Key,
|
|
EffectiveChangeDate = (from d in g select d.EffectiveChangeDate).Max()
|
|
};
|
|
|
|
// Get EffectiveChangeDate for the nearest future record in every Holiday
|
|
Dictionary<Guid, DateTime> activeItemsValidityDates =
|
|
(from item in
|
|
(from Holiday h in _dbContext.Holidays
|
|
where h.EffectiveChangeDate > validTimePoint
|
|
select new
|
|
{
|
|
HolidayGroupId = h.HolidayGroupId,
|
|
EffectiveChangeDate = h.EffectiveChangeDate
|
|
})
|
|
group item by item.HolidayGroupId into g
|
|
select new
|
|
{
|
|
HolidayGroupId = g.Key,
|
|
EffectiveChangeDate = (from d in g select d.EffectiveChangeDate).Min()
|
|
})
|
|
.ToDictionary(k => k.HolidayGroupId, v => v.EffectiveChangeDate);
|
|
|
|
// Build query for data to display
|
|
List<Holiday> srcData =
|
|
(from item in _dbContext.Holidays
|
|
join dt in activeItemsEffectiveDates on
|
|
new { item.HolidayGroupId, item.EffectiveChangeDate }
|
|
equals dt
|
|
select item).ToList();
|
|
|
|
List<HolidayDisplayModel> qry =
|
|
srcData.Select(t => (HolidayDisplayModel)(HolidayModel)t).ToList();
|
|
|
|
qry.ForEach(t => t.ValidTo = activeItemsValidityDates.Keys.Contains(t.HolidayGroupId) ?
|
|
activeItemsValidityDates[t.HolidayGroupId].AddDays(-1) : (DateTime?)null);
|
|
qry.ForEach(t => t.ValidToAsText = t.ValidTo.HasValue ?
|
|
t.ValidTo.Value.ToShortDateString() : String.Empty);
|
|
|
|
return qry;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns active Holiday record for given time point
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public HolidayModel GetActiveHolidayItem(Guid holidayGroupId, DateTime timePoint)
|
|
{
|
|
DateTime validTimePoint = timePoint.Date;
|
|
|
|
Holiday rec =
|
|
(from Holiday item in _dbContext.Holidays
|
|
orderby item.EffectiveChangeDate descending
|
|
where item.HolidayGroupId.Equals(holidayGroupId) && (item.EffectiveChangeDate <= validTimePoint)
|
|
select item)
|
|
.FirstOrDefault();
|
|
|
|
var result = (HolidayModel)rec;
|
|
|
|
if (!result.MultipleDaysHoliday)
|
|
result.EndDate = null;
|
|
|
|
if (result.Id != Guid.Empty)
|
|
{
|
|
// Set status for record. We get active record for the timePoint, so status should be Active
|
|
result.Status = HolidayModel.HolidayStatus.Active;
|
|
|
|
Holiday nextRec =
|
|
(from Holiday item in _dbContext.Holidays
|
|
orderby item.EffectiveChangeDate ascending
|
|
where item.HolidayGroupId.Equals(holidayGroupId) && (item.EffectiveChangeDate > validTimePoint)
|
|
select item)
|
|
.FirstOrDefault();
|
|
|
|
if (nextRec != null)
|
|
result.ValidTo = nextRec.EffectiveChangeDate.AddDays(-1);
|
|
|
|
result.IncludexpenditureCategories = result.ExpenditureCategories != null && result.ExpenditureCategories.Count > 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes all future Holiday records relative to given time point
|
|
/// </summary>
|
|
protected void RemoveFutureHolidayItems(Guid holidayGroupId, DateTime timePoint, Guid? exceptId = null)
|
|
{
|
|
var itemsToRemove = _dbContext.Holidays.Where(t =>
|
|
t.HolidayGroupId.Equals(holidayGroupId) && (t.EffectiveChangeDate > timePoint) &&
|
|
(!exceptId.HasValue || !t.Id.Equals(exceptId.Value)));
|
|
|
|
if (itemsToRemove.Count() > 0)
|
|
{
|
|
_dbContext.Holiday2Team.RemoveRange(itemsToRemove.SelectMany(x => x.Holiday2Team));
|
|
_dbContext.Holiday2PeopleResource.RemoveRange(itemsToRemove.SelectMany(x => x.Holiday2PeopleResource));
|
|
_dbContext.Holiday2ExpenditureCategory.RemoveRange(itemsToRemove.SelectMany(x => x.Holiday2ExpenditureCategory));
|
|
_dbContext.Holidays.RemoveRange(itemsToRemove);
|
|
}
|
|
}
|
|
|
|
protected void RemoveHolidayItem(Guid id)
|
|
{
|
|
var foundItems = _dbContext.Holidays.Where(t => t.Id.Equals(id));
|
|
|
|
if (foundItems.Count() > 0)
|
|
{
|
|
_dbContext.Holiday2Team.RemoveRange(foundItems.SelectMany(x => x.Holiday2Team));
|
|
_dbContext.Holiday2PeopleResource.RemoveRange(foundItems.SelectMany(x => x.Holiday2PeopleResource));
|
|
_dbContext.Holiday2ExpenditureCategory.RemoveRange(foundItems.SelectMany(x => x.Holiday2ExpenditureCategory));
|
|
_dbContext.Holidays.RemoveRange(foundItems);
|
|
}
|
|
}
|
|
|
|
public void SaveHoliday(HolidayModel model, DateTime timePoint)
|
|
{
|
|
if (model == null)
|
|
throw new ArgumentNullException("model");
|
|
|
|
// Create new holiday item (group of item versions)
|
|
var itemToSave = new Holiday();
|
|
|
|
model.CopyTo(itemToSave);
|
|
itemToSave.Id = Guid.NewGuid();
|
|
|
|
if (model.HolidayGroupId.Equals(Guid.Empty))
|
|
itemToSave.HolidayGroupId = Guid.NewGuid();
|
|
|
|
if (!model.CompanyImpactAllResources)
|
|
{
|
|
if (!model.IncludexpenditureCategories)
|
|
{
|
|
var holiday2PeopleResourceToAddCollection = new List<Holiday2PeopleResource>();
|
|
foreach (var x in model.Resources)
|
|
{
|
|
var item = new Holiday2PeopleResource
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
HolidayId = itemToSave.Id,
|
|
ResourceId = x
|
|
};
|
|
holiday2PeopleResourceToAddCollection.Add(item);
|
|
}
|
|
_dbContext.Holiday2PeopleResource.AddRange(holiday2PeopleResourceToAddCollection);
|
|
|
|
var holiday2TeamToAddCollection = new List<Holiday2Team>();
|
|
foreach (var x in model.Teams)
|
|
{
|
|
var item = new Holiday2Team
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
HolidayId = itemToSave.Id,
|
|
TeamId = x
|
|
};
|
|
holiday2TeamToAddCollection.Add(item);
|
|
}
|
|
_dbContext.Holiday2Team.AddRange(holiday2TeamToAddCollection);
|
|
|
|
_dbContext.Holiday2ExpenditureCategory.RemoveRange(itemToSave.Holiday2ExpenditureCategory);
|
|
}
|
|
else
|
|
{
|
|
var holiday2ExpenditureCategoryToAddCollection = new List<Holiday2ExpenditureCategory>();
|
|
foreach (var x in model.ExpenditureCategories)
|
|
{
|
|
var item = new Holiday2ExpenditureCategory
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
HolidayId = itemToSave.Id,
|
|
ExpenditureCategoryId = x
|
|
};
|
|
holiday2ExpenditureCategoryToAddCollection.Add(item);
|
|
}
|
|
_dbContext.Holiday2ExpenditureCategory.AddRange(holiday2ExpenditureCategoryToAddCollection);
|
|
_dbContext.Holiday2Team.RemoveRange(itemToSave.Holiday2Team);
|
|
_dbContext.Holiday2PeopleResource.RemoveRange(itemToSave.Holiday2PeopleResource);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_dbContext.Holiday2Team.RemoveRange(itemToSave.Holiday2Team);
|
|
_dbContext.Holiday2PeopleResource.RemoveRange(itemToSave.Holiday2PeopleResource);
|
|
_dbContext.Holiday2ExpenditureCategory.RemoveRange(itemToSave.Holiday2ExpenditureCategory);
|
|
}
|
|
|
|
|
|
var validTimePoint = timePoint.Date;
|
|
HolidayModel activeItem = null;
|
|
|
|
if (!model.HolidayGroupId.Equals(Guid.Empty))
|
|
{
|
|
activeItem = this.GetActiveHolidayItem(model.HolidayGroupId, validTimePoint);
|
|
|
|
if ((activeItem != null) && !activeItem.Id.Equals(itemToSave.Id))
|
|
{
|
|
if (model.EffectiveChangeDate.HasValue)
|
|
// Remove holiday allocations
|
|
this.RemoveHolidayAllocations(model.HolidayGroupId, model.EffectiveChangeDate.Value);
|
|
}
|
|
else
|
|
activeItem = null;
|
|
}
|
|
|
|
_dbContext.BulkSaveChanges();
|
|
|
|
// Holiday Allocations generation
|
|
HolidayModel modelCopy = model.Clone();
|
|
modelCopy.Id = itemToSave.Id;
|
|
modelCopy.HolidayGroupId = itemToSave.HolidayGroupId;
|
|
|
|
this.CreateHolidayAllocations(modelCopy);
|
|
_dbContext.Holidays.Add(itemToSave);
|
|
_dbContext.SaveChanges();
|
|
|
|
if (!model.HolidayGroupId.Equals(Guid.Empty))
|
|
{
|
|
if (activeItem != null)
|
|
{
|
|
// If pended to activation calendar setting exist, we should remove them
|
|
this.RemoveFutureHolidayItems(model.HolidayGroupId, validTimePoint, itemToSave.Id);
|
|
|
|
if (activeItem.EffectiveChangeDate.HasValue && model.EffectiveChangeDate.HasValue &&
|
|
(activeItem.EffectiveChangeDate.Value == model.EffectiveChangeDate.Value))
|
|
{
|
|
// Remove active item, because new item has the same EffStartDate as Active one
|
|
this.RemoveHolidayItem(activeItem.Id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns history records for Holiday
|
|
/// </summary>
|
|
/// <param name="timePoint">Current time point to mark Active, Inactive and Future records</param>
|
|
/// <returns></returns>
|
|
public HolidayListModel GetHolidayHistoryItems(Guid holidayGroupId, DateTime timePoint)
|
|
{
|
|
bool activeItemSet = false;
|
|
DateTime validTimePoint = timePoint.Date;
|
|
HolidayListModel result = new HolidayListModel();
|
|
|
|
List<Holiday> items =
|
|
(from Holiday rec in _dbContext.Holidays
|
|
orderby rec.EffectiveChangeDate descending
|
|
where rec.HolidayGroupId.Equals(holidayGroupId)
|
|
select rec).Take(10).ToList();
|
|
|
|
for (int index = 0; index < items.Count; index++)
|
|
{
|
|
HolidayModel currentItem = (HolidayModel)items[index];
|
|
|
|
if (currentItem.EffectiveChangeDate.HasValue && (currentItem.EffectiveChangeDate.Value > validTimePoint))
|
|
{
|
|
currentItem.Status = HolidayModel.HolidayStatus.Future;
|
|
}
|
|
else
|
|
{
|
|
if (!activeItemSet)
|
|
{
|
|
currentItem.Status = HolidayModel.HolidayStatus.Active;
|
|
activeItemSet = true;
|
|
}
|
|
else
|
|
{
|
|
currentItem.Status = HolidayModel.HolidayStatus.Inactive;
|
|
}
|
|
}
|
|
|
|
HolidayDisplayModel currentDisplayItem = (HolidayDisplayModel)currentItem;
|
|
result.Items.Add(currentDisplayItem);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public void DeleteHoliday(Guid holidayGroupId)
|
|
{
|
|
var foundItems = _dbContext.Holidays.Where(t => t.HolidayGroupId.Equals(holidayGroupId));
|
|
|
|
if (foundItems.Count() < 1)
|
|
throw new Exception(String.Format("Holiday (holidayGroupId = '{0}') not found", holidayGroupId.ToString()));
|
|
|
|
_dbContext.Holiday2Team.RemoveRange(foundItems.SelectMany(x => x.Holiday2Team));
|
|
_dbContext.Holiday2PeopleResource.RemoveRange(foundItems.SelectMany(x => x.Holiday2PeopleResource));
|
|
_dbContext.Holiday2ExpenditureCategory.RemoveRange(foundItems.SelectMany(x => x.Holiday2ExpenditureCategory));
|
|
_dbContext.Holidays.RemoveRange(foundItems);
|
|
|
|
// Remove all holiday allocations for all its group of records
|
|
this.RemoveHolidayAllocations(holidayGroupId);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Holiday Allocations
|
|
|
|
/// <summary>
|
|
/// Removes all holiday allocation records for specified Holiday Group
|
|
/// </summary>
|
|
protected void RemoveHolidayAllocations(Guid holidayGroupId)
|
|
{
|
|
var itemsToRemove = _dbContext.HolidayAllocations.Where(x => x.HolidayGroupId.Equals(holidayGroupId));
|
|
_dbContext.HolidayAllocations.RemoveRange(itemsToRemove);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return date for start team membership (according to fiscal calendar) by specified date point
|
|
/// </summary>
|
|
/// <param name="date">Source date point</param>
|
|
/// <param name="dbContext"></param>
|
|
/// <returns></returns>
|
|
public static DateTime GetDateForTeamMembershipStart(DateTime date, EnVisageEntities dbContext)
|
|
{
|
|
var fiscalWeeks = GetFiscalCalendarCurrentAndNextWeeksForDate(date, dbContext);
|
|
|
|
if (fiscalWeeks.Count > 0)
|
|
{
|
|
if (fiscalWeeks.First().StartDate == date)
|
|
return fiscalWeeks.First().StartDate;
|
|
|
|
if (fiscalWeeks.Count > 1)
|
|
return fiscalWeeks.Last().StartDate;
|
|
|
|
return Constants.FISCAL_CALENDAR_MAX_DATE;
|
|
}
|
|
|
|
string errMessage = "There are no full fiscal weeks for the specified date point: {0}";
|
|
throw new Exception(String.Format(errMessage, date.ToShortDateString()));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return date for end team membership (according to fiscal calendar) by specified date point
|
|
/// </summary>
|
|
/// <param name="date">Source date point</param>
|
|
/// <param name="dbContext"></param>
|
|
/// <returns></returns>
|
|
public static DateTime? GetDateForTeamMembershipEnd(DateTime date, EnVisageEntities dbContext)
|
|
{
|
|
var fiscalWeeks = GetFiscalCalendarCurrentAndPrevWeeksForDate(date, dbContext);
|
|
|
|
if (fiscalWeeks.Count > 0)
|
|
{
|
|
if (fiscalWeeks.First().EndDate == date)
|
|
return fiscalWeeks.First().EndDate;
|
|
|
|
if (fiscalWeeks.Count > 1)
|
|
return fiscalWeeks.Last().EndDate;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes holiday allocations for specified Holiday Group from specified time point and to the future
|
|
/// </summary>
|
|
protected void RemoveHolidayAllocations(Guid holidayGroupId, DateTime startingPoint)
|
|
{
|
|
// Note:
|
|
// 1. We must find the week, startingPoint belongs to. Let's call it Updatable week.
|
|
// If Holiday allocations for this week exist, we should update this allocations record,
|
|
// because this record can share allocations for current holiday item and its previous version.
|
|
// 2. We must remove all the allocations, next to the Updatable week
|
|
// (they will be calculated and created againt, when the holiday item saved)
|
|
|
|
DateTime startDateCorrected = startingPoint.Date;
|
|
DateRange we = GetFiscalCalendarWeekForDate(startingPoint, _dbContext);
|
|
DateTime updatableWeekWe = we.EndDate;
|
|
|
|
// Get updatable allocations record
|
|
var updatableAllocRec =
|
|
_dbContext.HolidayAllocations.FirstOrDefault(x => x.HolidayGroupId.Equals(holidayGroupId) &&
|
|
(x.WeekEndingDate == updatableWeekWe));
|
|
|
|
if (updatableAllocRec != null)
|
|
{
|
|
// Allocation record for update found. Perform update
|
|
int daysAffected = Convert.ToInt32((updatableWeekWe - startDateCorrected).TotalDays) + 1;
|
|
for (int index = 0; index < daysAffected; index++)
|
|
{
|
|
DateTime currentDate = startDateCorrected.AddDays(index);
|
|
switch (currentDate.DayOfWeek)
|
|
{
|
|
case DayOfWeek.Sunday:
|
|
updatableAllocRec.Sunday = true;
|
|
break;
|
|
case DayOfWeek.Monday:
|
|
updatableAllocRec.Monday = true;
|
|
break;
|
|
case DayOfWeek.Tuesday:
|
|
updatableAllocRec.Tuesday = true;
|
|
break;
|
|
case DayOfWeek.Wednesday:
|
|
updatableAllocRec.Wednesday = true;
|
|
break;
|
|
case DayOfWeek.Thursday:
|
|
updatableAllocRec.Thursday = true;
|
|
break;
|
|
case DayOfWeek.Friday:
|
|
updatableAllocRec.Friday = true;
|
|
break;
|
|
case DayOfWeek.Saturday:
|
|
updatableAllocRec.Saturday = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Perform deleting of future allocation records
|
|
var recsToRemove = _dbContext.HolidayAllocations
|
|
.Where(x => x.HolidayGroupId.Equals(holidayGroupId) && (x.WeekEndingDate > updatableWeekWe));
|
|
_dbContext.HolidayAllocations.RemoveRange(recsToRemove);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates holiday allocations records for holiday
|
|
/// </summary>
|
|
protected void CreateHolidayAllocations(HolidayModel model)
|
|
{
|
|
if (model.WorkingDays)
|
|
return;
|
|
|
|
// Get holiday days and corresponding weekendings in the Fiscal Calendar
|
|
List<DateTime> holidayDates = model.GetHolidayDates();
|
|
|
|
if (holidayDates.Count < 1)
|
|
return;
|
|
|
|
var weekendingsForDates = GetFiscalCalendarWeekendingsForDates(holidayDates);
|
|
|
|
var newAllocations = new List<HolidayAllocation>();
|
|
|
|
Dictionary<DateTime, HolidayAllocation> allocationsForDates =
|
|
_dbContext.HolidayAllocations.Where(a => a.HolidayGroupId.Equals(model.HolidayGroupId) &&
|
|
weekendingsForDates.Values.Contains(a.WeekEndingDate)).
|
|
ToDictionary(k => k.WeekEndingDate, v => v);
|
|
|
|
foreach (DateTime holidayDate in holidayDates)
|
|
{
|
|
DateTime? we = weekendingsForDates[holidayDate];
|
|
|
|
if (we.HasValue)
|
|
{
|
|
HolidayAllocation ha = null;
|
|
|
|
if (allocationsForDates.ContainsKey(we.Value))
|
|
{
|
|
ha = allocationsForDates[we.Value];
|
|
ha.HolidayId = model.Id;
|
|
}
|
|
else
|
|
{
|
|
ha = new HolidayAllocation
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
HolidayId = model.Id,
|
|
HolidayGroupId = model.HolidayGroupId,
|
|
WeekEndingDate = we.Value,
|
|
Sunday = true,
|
|
Monday = true,
|
|
Tuesday = true,
|
|
Wednesday = true,
|
|
Thursday = true,
|
|
Friday = true,
|
|
Saturday = true
|
|
};
|
|
newAllocations.Add(ha);
|
|
allocationsForDates[we.Value] = ha;
|
|
}
|
|
|
|
switch (holidayDate.DayOfWeek)
|
|
{
|
|
case DayOfWeek.Sunday:
|
|
ha.Sunday = false;
|
|
break;
|
|
case DayOfWeek.Monday:
|
|
ha.Monday = false;
|
|
break;
|
|
case DayOfWeek.Tuesday:
|
|
ha.Tuesday = false;
|
|
break;
|
|
case DayOfWeek.Wednesday:
|
|
ha.Wednesday = false;
|
|
break;
|
|
case DayOfWeek.Thursday:
|
|
ha.Thursday = false;
|
|
break;
|
|
case DayOfWeek.Friday:
|
|
ha.Friday = false;
|
|
break;
|
|
case DayOfWeek.Saturday:
|
|
ha.Saturday = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_dbContext.HolidayAllocations.AddRange(newAllocations);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets weekly holiday allocations grouped by PeopleResourceId and then by weekending date.
|
|
/// </summary>
|
|
/// <param name="resourceIds">A collection of people resource identifiers.</param>
|
|
/// <param name="startDate">Start date of period to search.</param>
|
|
/// <param name="endDate">End date of period to search.</param>
|
|
/// <returns>A dictionary of dictionaries [PeopleResourceId, [Weekending, AdjustmentKoeff]]</returns>
|
|
public Dictionary<Guid, Dictionary<DateTime, decimal>> GetHolidayAllocationsByResource(DateTime? startDate, DateTime? endDate, IEnumerable<Guid> resourceIds = null, IEnumerable<Guid> teamIds = null)
|
|
{
|
|
if (endDate <= startDate)
|
|
return new Dictionary<Guid, Dictionary<DateTime, decimal>>();
|
|
|
|
var result = new Dictionary<Guid, Dictionary<DateTime, decimal>>();
|
|
var list = GetHolidayAllocations(startDate, endDate, resourceIds, teamIds);
|
|
foreach (var item in list.OrderBy(t => t.WeekEndingDate))
|
|
{
|
|
if (!result.ContainsKey(item.PeopleResourceId.Value))
|
|
result.Add(item.PeopleResourceId.Value, new Dictionary<DateTime, decimal>());
|
|
if (!result[item.PeopleResourceId.Value].ContainsKey(item.WeekEndingDate))
|
|
result[item.PeopleResourceId.Value].Add(item.WeekEndingDate, item.AdjustmentKoeff);
|
|
}
|
|
return result;
|
|
}
|
|
public IEnumerable<VW_HolidayAllocation> GetHolidayAllocations(DateTime? startDate, DateTime? endDate, IEnumerable<Guid> resourceIds = null, IEnumerable<Guid> teamIds = null)
|
|
{
|
|
if (endDate <= startDate)
|
|
return new List<VW_HolidayAllocation>();
|
|
|
|
var holidaysQuery = _dbContext.VW_HolidayAllocation.AsNoTracking().AsQueryable();
|
|
if (resourceIds != null && resourceIds.Any())
|
|
holidaysQuery = holidaysQuery.Where(t => t.PeopleResourceId.HasValue && resourceIds.Contains(t.PeopleResourceId.Value));
|
|
if (teamIds != null && teamIds.Any())
|
|
holidaysQuery = holidaysQuery.Where(t => t.TeamId.HasValue && teamIds.Contains(t.TeamId.Value));
|
|
if (startDate.HasValue)
|
|
holidaysQuery = holidaysQuery.Where(x => x.WeekEndingDate >= startDate);
|
|
if (endDate.HasValue)
|
|
holidaysQuery = holidaysQuery.Where(x => x.WeekEndingDate <= endDate);
|
|
|
|
return holidaysQuery.ToList();
|
|
}
|
|
#endregion
|
|
#region Get Weekendings Data methods
|
|
|
|
/// <summary>
|
|
/// Return StartDate and EndDate for fiscal week containing specified date point
|
|
/// </summary>
|
|
public static DateRange GetFiscalCalendarWeekForDate(DateTime date, EnVisageEntities dbContext)
|
|
{
|
|
if (dbContext == null)
|
|
throw new ArgumentNullException("dbContext");
|
|
|
|
string errMessage;
|
|
DateTime dateCorrected = date.Date;
|
|
|
|
var weekending =
|
|
dbContext.FiscalCalendars
|
|
.Where(c => (c.Type == (int)FiscalCalendarModel.FiscalYearType.Week) &&
|
|
(c.StartDate <= dateCorrected) && (c.EndDate >= dateCorrected)).FirstOrDefault();
|
|
|
|
if (weekending == null)
|
|
{
|
|
errMessage = String.Format("No fiscal week, containing specified date found (date point: {0})",
|
|
date.ToShortDateString());
|
|
throw new Exception(errMessage);
|
|
}
|
|
|
|
return (DateRange)weekending;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return StartDate and EndDate for previous fiscal week for the one, containing specified date point
|
|
/// </summary>
|
|
public static DateRange GetFiscalCalendarPrevWeekForDate(DateTime date, EnVisageEntities dbContext)
|
|
{
|
|
if (dbContext == null)
|
|
throw new ArgumentNullException("dbContext");
|
|
|
|
string errMessage;
|
|
DateTime dateCorrected = date.Date;
|
|
|
|
var weekendingsOrdered =
|
|
dbContext.FiscalCalendars.AsNoTracking()
|
|
.Where(c => (c.Type == (int)FiscalCalendarModel.FiscalYearType.Week) &&
|
|
(c.StartDate <= dateCorrected)).OrderByDescending(x => x.StartDate)
|
|
.Take(2).ToList();
|
|
|
|
if (weekendingsOrdered.Count < 2)
|
|
{
|
|
errMessage = String.Format("No previous fiscal week for the one, containing specified date found (date point: {0})",
|
|
date.ToShortDateString());
|
|
throw new Exception(errMessage);
|
|
}
|
|
|
|
return (DateRange)weekendingsOrdered.Last();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns current fiscal week (containing date point) and the previous one (1st = current, 2nd = prev)
|
|
/// </summary>
|
|
public static List<DateRange> GetFiscalCalendarCurrentAndPrevWeeksForDate(DateTime date, EnVisageEntities dbContext)
|
|
{
|
|
if (dbContext == null)
|
|
throw new ArgumentNullException("dbContext");
|
|
|
|
DateTime dateCorrected = date.Date;
|
|
|
|
var weekendingsOrdered =
|
|
dbContext.FiscalCalendars.AsNoTracking()
|
|
.Where(c => (c.Type == (int)FiscalCalendarModel.FiscalYearType.Week) &&
|
|
(c.StartDate <= dateCorrected)).OrderByDescending(x => x.StartDate)
|
|
.Take(2).ToList();
|
|
|
|
List<DateRange> result = weekendingsOrdered.Select(x => (DateRange)x).ToList();
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns current fiscal week (containing date point) and the next one (1st = current, 2nd = next)
|
|
/// </summary>
|
|
public static List<DateRange> GetFiscalCalendarCurrentAndNextWeeksForDate(DateTime date, EnVisageEntities dbContext)
|
|
{
|
|
if (dbContext == null)
|
|
throw new ArgumentNullException("dbContext");
|
|
|
|
DateTime dateCorrected = date.Date;
|
|
|
|
var weekendingsOrdered =
|
|
dbContext.FiscalCalendars.AsNoTracking()
|
|
.Where(c => (c.Type == (int)FiscalCalendarModel.FiscalYearType.Week) &&
|
|
(c.EndDate >= dateCorrected)).OrderBy(x => x.StartDate)
|
|
.Take(2).ToList();
|
|
|
|
List<DateRange> result = weekendingsOrdered.Select(x => (DateRange)x).ToList();
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns weekendings for the fiscal weeks containing specified dates. Result is the dictionary,
|
|
/// where keys are specified dates, and values are their corresponding weekendings
|
|
/// </summary>
|
|
protected Dictionary<DateTime, DateTime?> GetFiscalCalendarWeekendingsForDates(List<DateTime> dates)
|
|
{
|
|
List<DateTime> datesCorrected = dates.Select(d => d.Date).OrderBy(d => d).ToList();
|
|
DateTime minDate = datesCorrected.First();
|
|
DateTime maxDate = datesCorrected.Last();
|
|
|
|
DateTime fcBrowseStartDate = minDate.AddMonths(-1);
|
|
DateTime fcBrowseEndDate = maxDate.AddMonths(1);
|
|
|
|
var weekendings =
|
|
_dbContext.FiscalCalendars
|
|
.Where(c => (c.Type == (int)FiscalCalendarModel.FiscalYearType.Week) &&
|
|
(c.StartDate >= fcBrowseStartDate) && (c.EndDate <= fcBrowseEndDate))
|
|
.Select(c => new { c.StartDate, c.EndDate }).ToList();
|
|
|
|
Dictionary<DateTime, DateTime?> couples = datesCorrected.Select(d =>
|
|
new KeyValuePair<DateTime, DateTime?>(d, weekendings
|
|
.Where(c => (c.StartDate <= d) && (c.EndDate >= d))
|
|
.Select(c => c.EndDate).FirstOrDefault())
|
|
).ToDictionary(k => k.Key, v =>
|
|
(v.Value.HasValue && v.Value != DateTime.MinValue) ? v.Value : (DateTime?)null);
|
|
|
|
|
|
|
|
return couples;
|
|
}
|
|
|
|
public static List<DateTime> GetWeekendingsByRange(DateTime startDate, DateTime? endDate, EnVisageEntities dbContext)
|
|
{
|
|
var weekendings =
|
|
dbContext.FiscalCalendars.AsNoTracking().Where(x => (x.Type == (int)FiscalCalendarModel.FiscalYearType.Week) &&
|
|
(x.EndDate >= startDate) && (!endDate.HasValue || (x.StartDate <= endDate.Value)) &&
|
|
(x.AdjustingPeriod == false))
|
|
.OrderBy(x => x.StartDate)
|
|
.Select(x => x.EndDate).ToList();
|
|
return weekendings;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns Fiscal Calendar Weeks (start & end dates) for specified date range
|
|
/// </summary>
|
|
public static List<DateRange> GetFiscalCalendarWeeksByRange(DateTime startDate, DateTime? endDate, EnVisageEntities dbContext)
|
|
{
|
|
List<DateRange> result =
|
|
dbContext.FiscalCalendars.AsNoTracking().Where(x => (x.Type == (int)FiscalCalendarModel.FiscalYearType.Week) &&
|
|
(x.EndDate >= startDate) && (!endDate.HasValue || (x.StartDate <= endDate.Value)) &&
|
|
(x.AdjustingPeriod == false))
|
|
.OrderBy(x => x.StartDate).ToList()
|
|
.Select(x => (DateRange)x).ToList();
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns StartDate for the earliest period of _type_ in fiscal calendar
|
|
/// </summary>
|
|
/// <param name="type">Fiscal Calendar Type</param>
|
|
/// <returns></returns>
|
|
public static DateTime GetCalendarMinDate(FiscalCalendarModel.FiscalYearType type = FiscalCalendarModel.FiscalYearType.Week)
|
|
{
|
|
using (var dbContext = new EnVisageEntities())
|
|
{
|
|
var result = dbContext.FiscalCalendars.Where(x => x.Type == (int)type).Select(x => x.StartDate).Min();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns EndDate for the latest period of _type_ in fiscal calendar
|
|
/// </summary>
|
|
/// <param name="type">Fiscal Calendar Type</param>
|
|
/// <returns></returns>
|
|
public static DateTime GetCalendarMaxDate(FiscalCalendarModel.FiscalYearType type = FiscalCalendarModel.FiscalYearType.Week)
|
|
{
|
|
using (var dbContext = new EnVisageEntities())
|
|
{
|
|
var result = dbContext.FiscalCalendars.Where(x => x.Type == (int)type).Select(x => x.EndDate).Max();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class for representing Date Ranges
|
|
/// </summary>
|
|
public class DateRange
|
|
{
|
|
public DateTime StartDate { get; set; }
|
|
public DateTime EndDate { get; set; }
|
|
|
|
public static explicit operator DateRange(DateRangeNullable obj)
|
|
{
|
|
if (obj == null)
|
|
return null;
|
|
|
|
if (!obj.StartDate.HasValue || !obj.EndDate.HasValue)
|
|
throw new InvalidCastException("DateRangeNullable can't be casted to DateRange because of null values");
|
|
|
|
var result = new DateRange()
|
|
{
|
|
StartDate = obj.StartDate.Value,
|
|
EndDate = obj.EndDate.Value
|
|
};
|
|
return result;
|
|
}
|
|
|
|
public static explicit operator DateRange(FiscalCalendar obj)
|
|
{
|
|
if (obj == null)
|
|
return null;
|
|
|
|
var result = new DateRange()
|
|
{
|
|
StartDate = obj.StartDate,
|
|
EndDate = obj.EndDate
|
|
};
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class for representing Date Ranges with nullable bounds
|
|
/// </summary>
|
|
public class DateRangeNullable
|
|
{
|
|
public DateTime? StartDate { get; set; }
|
|
public DateTime? EndDate { get; set; }
|
|
|
|
public static explicit operator DateRangeNullable(DateRange obj)
|
|
{
|
|
if (obj == null)
|
|
return null;
|
|
|
|
var result = new DateRangeNullable()
|
|
{
|
|
StartDate = obj.StartDate,
|
|
EndDate = obj.EndDate
|
|
};
|
|
return result;
|
|
}
|
|
|
|
// Returns True, if date fits the range
|
|
public bool IsInRange(DateTime date)
|
|
{
|
|
return (!StartDate.HasValue || (StartDate.HasValue && StartDate.Value <= date)) &&
|
|
(!EndDate.HasValue || (EndDate.HasValue && EndDate.Value >= date));
|
|
}
|
|
}
|
|
} |