diff --git a/ayanova/devdocs/todo.txt b/ayanova/devdocs/todo.txt index 5f61b26d..22f02cc0 100644 --- a/ayanova/devdocs/todo.txt +++ b/ayanova/devdocs/todo.txt @@ -50,16 +50,12 @@ SHELL / NAV / MENUS / LAYOUT TODO: LOCALIZATION - TODO ACTIONS - - Need to determine actual hours of time zone adjustment for grid filtering with relative times so can send to server - - Now no longer have user's own timezone offset stored - - Or should server calculate it based on timezone + - Relative time filters need to be removed from server and replaced with a single BETWEEN filter + - Then they need to be re-implemented at the client where the client will send the between date/times to the server based on the user's chosen relative token + - This fixes a bad design decision to involve the server in time zone shit when in fact the server should never operate in anything but UTC + - Time zones are a client issue and should never be a server issue - - Get rid of timezone numeric override and any other deprecated stuff (currency symbol, decimal symbol etc) and associated code at client and server - - Add the new overrides for language and timezone and currency code and 12hour at client and server - - CurrencyName (only one can't be inferred) - - Time zone name - - language name - - 12hr time + - Make functional user settings form with all overrides so can test shit out - Need a browser check on opening the login page that will check to ensure the browser can do the date conversions properly etc and tell user browser is unsuitable if it isn't diff --git a/ayanova/src/api/relative-date-filter-calculator.js b/ayanova/src/api/relative-date-filter-calculator.js new file mode 100644 index 00000000..320cd14d --- /dev/null +++ b/ayanova/src/api/relative-date-filter-calculator.js @@ -0,0 +1,452 @@ + +//TODO: Replace all this server code with equivalent client code + + + +namespace AyaNova.DataList +{ + public static class DataListFilterSpecialToken + { + public const string Null = "{[null]}"; + public const string Yesterday = "{[yesterday]}"; + public const string Today = "{[today]}"; + public const string Tomorrow = "{[tomorrow]}"; + public const string LastWeek = "{[lastweek]}"; + public const string ThisWeek = "{[thisweek]}"; + public const string NextWeek = "{[nextweek]}"; + public const string LastMonth = "{[lastmonth]}"; + public const string ThisMonth = "{[thismonth]}"; + public const string NextMonth = "{[nextmonth]}"; + public const string FourteenDayWindow = "{[14daywindow]}"; + public const string Past = "{[past]}"; + public const string Future = "{[future]}"; + public const string LastYear = "{[lastyear]}"; + public const string ThisYear = "{[thisyear]}"; + public const string InTheLast3Months = "{[last3months]}"; + public const string InTheLast6Months = "{[last6months]}"; + public const string InTheLastYear = "{[lastcalendaryear]}"; + + //Months THIS year + public const string January = "{[january]}"; + public const string February = "{[february]}"; + public const string March = "{[march]}"; + public const string April = "{[april]}"; + public const string May = "{[may]}"; + public const string June = "{[june]}"; + public const string July = "{[july]}"; + public const string August = "{[august]}"; + public const string September = "{[september]}"; + public const string October = "{[october]}"; + public const string November = "{[november]}"; + public const string December = "{[december]}"; + + //These TEXT filter tokens were more for paging purposes than anything else + //however paging is done by numeric range now so will not implement for now + // public const string AH = "{[ah]}"; + // public const string IP = "{[ip]}"; + // public const string QZ = "{[qz]}"; + // public const string ZeroToThree = "{[03]}"; + // public const string FourToSix = "{[46]}"; + // public const string SevenToNine = "{[79]}"; + + + //Don't think I need these + //public const string LessThanZero = "{[<0]}"; + // public const string Zero = "{[0]}"; + //public const string GreaterThanZero = "{[>0]}"; + + //https://www.klipfolio.com/resources/articles/kpi-timeframe-comparison-metrics + + //More business time frames + + public const string YearToDate = "{[yeartodate]}"; + + public const string Past90Days = "{[past90days]}"; + public const string Past30Days = "{[past30days]}"; + public const string Past24Hours = "{[past24hours]}"; + + + + + + + } +} + + +//############################################################### OLD SERVER FILTERING CODE ########################## + + + + //HOWEVER, if it's a relative date filter TOKEN like "nextMonth" then the users time zone offset will be taken into consideration + + //So this is the core date time to work off of + DateTime RelativeToday = DateTime.Today; + DateTime RelativeNow = DateTime.Now; + // ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("FilterSqlCriteriaBuilder::DataFilterToColumnCriteria"); + // log.LogInformation("RelativeToday (before adjustment):"); + // log.LogInformation(RelativeToday.ToString()); + // log.LogInformation("RelativeNow (before adjustment):"); + // log.LogInformation(RelativeNow.ToString()); + + + if (sValue.StartsWith("{[") && sValue.EndsWith("]}")) + { + + + //Need to adjust RelativeToday to users time frame + //Fetch useroptions object and relative time offset + //See servers spec doc core-locale-currency-numbers-time-and-dates.txt for details about why this is necessary to be done this way + AyaNova.Models.AyContext ct = AyaNova.Util.ServiceProviderProvider.DBContext; + var u = ct.User.AsNoTracking().Where(a => a.Id == userId).Select(m => new { tz = m.UserOptions.TimeZoneOffset }).First(); + + //Add this value to any time's hours to convert to user local time + Double TimeZoneAdjustment = ((double)u.tz) * -1; + + //Stock times used for many of the tokens: + RelativeToday = RelativeToday.AddHours(TimeZoneAdjustment);//flip the sign to adjust towards UTC + RelativeNow = RelativeNow.AddHours(TimeZoneAdjustment);//flip the sign to adjust towards UTC + + //TESTING: + //LOG THE CRIT AND QUERY + // ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("FilterSqlCriteriaBuilder::DataFilterToColumnCriteria"); + // log.LogInformation("RelativeToday (adjusted):"); + // log.LogInformation(RelativeToday.ToString()); + // log.LogInformation("RelativeNow (adjusted):"); + // log.LogInformation(RelativeNow.ToString()); + // log.LogInformation("Offset used:"); + // log.LogInformation(u.tz.ToString()); + + #region Build criteria for date RANGE TOKEN specified + //Used as the basis point + System.DateTime dtAfter; + System.DateTime dtBefore; + switch (sValue) + { + //Case 402 + case DataListFilterSpecialToken.Yesterday: + //Between Day before yesterday at midnight and yesterday at midnight + dtAfter = RelativeToday.AddDays(-1); + dtAfter = dtAfter.AddSeconds(-1); + dtBefore = RelativeToday;//.AddDays(-1); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.Today: + //Between yesterday at midnight and tommorow at midnight + dtAfter = RelativeToday.AddSeconds(-1); + dtBefore = RelativeToday.AddDays(1); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + case DataListFilterSpecialToken.Tomorrow: + //Between Tonight at midnight and day after tommorow at midnight + dtAfter = RelativeToday.AddDays(1); + dtAfter = dtAfter.AddSeconds(-1); + dtBefore = RelativeToday.AddDays(2); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + //Case 402 + case DataListFilterSpecialToken.LastWeek: + //Between two Sundays ago at midnight and last sunday at midnight + dtAfter = RelativeToday; + + //go back a week + dtAfter = dtAfter.AddDays(-7); + + //go backwards to Sunday + while (dtAfter.DayOfWeek != DayOfWeek.Sunday) + dtAfter = dtAfter.AddDays(-1); + + //go to very start of eighth dayahead + dtBefore = dtAfter.AddDays(8); + + dtAfter = dtAfter.AddSeconds(-1); + + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + + case DataListFilterSpecialToken.ThisWeek: + //Between Sunday at midnight and Next sunday at midnight + dtAfter = RelativeToday; + //go backwards to monday + while (dtAfter.DayOfWeek != DayOfWeek.Monday) + dtAfter = dtAfter.AddDays(-1); + + //Now go back to sunday last second + dtAfter = dtAfter.AddSeconds(-1); + + + + dtBefore = RelativeToday; + //go forwards to monday + if (RelativeToday.DayOfWeek == DayOfWeek.Monday) + { + //Monday today? then go to next monday + dtBefore = dtBefore.AddDays(7); + } + else + { + while (dtBefore.DayOfWeek != DayOfWeek.Monday) + dtBefore = dtBefore.AddDays(1); + } + + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + case DataListFilterSpecialToken.NextWeek: + //Between Next Sunday at midnight and Next Next sunday at midnight + dtAfter = RelativeToday; + + //If today is monday skip over it first + if (dtAfter.DayOfWeek == DayOfWeek.Monday) + dtAfter = dtAfter.AddDays(1); + + //go forwards to next monday + while (dtAfter.DayOfWeek != DayOfWeek.Monday) + dtAfter = dtAfter.AddDays(1); + + //Now go back to sunday last second + dtAfter = dtAfter.AddDays(-1); + + //go seven days ahead + dtBefore = dtAfter.AddDays(7); + + //case 1155 + dtAfter = dtAfter.AddSeconds(-1); + + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + case DataListFilterSpecialToken.LastMonth: + //start with the first day of this month + dtAfter = new DateTime(RelativeToday.Year, RelativeToday.Month, 1, RelativeToday.Hour, RelativeToday.Minute, 00); + //subtract a Month + dtAfter = dtAfter.AddMonths(-1); + + //Add one month to dtAfter to get end date + dtBefore = dtAfter.AddMonths(1); + + //case 1155 + dtAfter = dtAfter.AddSeconds(-1); + + // 'yyyy-mm-ddTHH:MM:SS' + + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + case DataListFilterSpecialToken.ThisMonth: + //start with the first day of this month + dtAfter = new DateTime(RelativeToday.Year, RelativeToday.Month, 1, RelativeToday.Hour, RelativeToday.Minute, 00); + + //Add one month to dtAfter to get end date + dtBefore = dtAfter.AddMonths(1); + + //case 1155 + dtAfter = dtAfter.AddSeconds(-1); + + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.NextMonth: + //start with the first day of this month + dtAfter = new DateTime(RelativeToday.Year, RelativeToday.Month, 1, RelativeToday.Hour, RelativeToday.Minute, 00); + //Add a Month + dtAfter = dtAfter.AddMonths(1); + + //Add one month to dtAfter to get end date + dtBefore = dtAfter.AddMonths(1); + + //case 1155 + dtAfter = dtAfter.AddSeconds(-1); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + case DataListFilterSpecialToken.FourteenDayWindow: + //start with today zero hour + dtAfter = new DateTime(RelativeToday.Year, RelativeToday.Month, RelativeToday.Day, RelativeToday.Hour, RelativeToday.Minute, 00); + dtAfter = dtAfter.AddDays(-7); + + //Add 15 days to get end date (zero hour so not really 15 full days) + dtBefore = dtAfter.AddDays(15); + + //case 1155 + dtAfter = dtAfter.AddSeconds(-1); + + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + + //case 2067 ADDITIONAL DATE RANGES ************ + + case DataListFilterSpecialToken.Past: + //Forever up to Now + dtAfter = new DateTime(1753, 1, 2, 00, 00, 00); + dtBefore = DateTime.UtcNow; + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.Future: + //From Now to forever (999 years from now) + dtAfter = DateTime.UtcNow; + dtBefore = DateTime.UtcNow.AddYears(999); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.LastYear: + //From zero hour january 1 a year ago + dtAfter = new DateTime(RelativeNow.AddYears(-1).Year, 1, 1, 0, 0, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + //To zero hour January 1 this year + dtBefore = new DateTime(RelativeNow.Year, 1, 1, 0, 0, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.ThisYear: + //From zero hour january 1 this year + dtAfter = new DateTime(RelativeNow.Year, 1, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + //To zero hour Jan 1 next year + dtBefore = new DateTime(RelativeNow.AddYears(1).Year, 1, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.InTheLast3Months: + //From Now minus 3 months + dtAfter = DateTime.UtcNow.AddMonths(-3); + //To Now + dtBefore = DateTime.UtcNow; + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.InTheLast6Months: + //From Now minus 6 months + dtAfter = DateTime.UtcNow.AddMonths(-6); + //To Now + dtBefore = DateTime.UtcNow; + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.InTheLastYear: + //From Now minus 365 days + dtAfter = DateTime.UtcNow.AddDays(-365); + //To Now + dtBefore = DateTime.UtcNow; + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + //======================= + //NEW ONES FOR RAVEN + + + case DataListFilterSpecialToken.YearToDate: + //From zero hour january 1 this year + dtAfter = new DateTime(RelativeNow.Year, 1, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); ; + //To now + dtBefore = RelativeNow; + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.Past90Days: + //From Now minus 90 days + dtAfter = DateTime.UtcNow.AddDays(-90); + //To Now + dtBefore = DateTime.UtcNow; + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + case DataListFilterSpecialToken.Past30Days: + //From Now minus 30 days + dtAfter = DateTime.UtcNow.AddDays(-30); + //To Now + dtBefore = DateTime.UtcNow; + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + case DataListFilterSpecialToken.Past24Hours: + //From Now minus 24 hours + dtAfter = DateTime.UtcNow.AddHours(-24); + //To Now + dtBefore = DateTime.UtcNow; + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.January: + //From zero hour january 1 this year + dtAfter = new DateTime(RelativeNow.Year, 1, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + //To zero hour feb 1 this year + dtBefore = new DateTime(RelativeNow.Year, 2, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.February: + dtAfter = new DateTime(RelativeNow.Year, 2, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 3, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.March: + dtAfter = new DateTime(RelativeNow.Year, 3, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 4, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.April: + dtAfter = new DateTime(RelativeNow.Year, 4, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 5, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.May: + dtAfter = new DateTime(RelativeNow.Year, 5, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 6, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.June: + dtAfter = new DateTime(RelativeNow.Year, 6, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 7, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.July: + dtAfter = new DateTime(RelativeNow.Year, 7, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 8, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.August: + dtAfter = new DateTime(RelativeNow.Year, 8, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 9, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.September: + dtAfter = new DateTime(RelativeNow.Year, 9, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 10, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.October: + dtAfter = new DateTime(RelativeNow.Year, 10, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 11, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.November: + dtAfter = new DateTime(RelativeNow.Year, 11, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + dtBefore = new DateTime(RelativeNow.Year, 12, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + case DataListFilterSpecialToken.December: + //From zero hour dec 1 this year + dtAfter = new DateTime(RelativeNow.Year, 12, 1, 00, 00, 00).AddSeconds(-1).AddHours(TimeZoneAdjustment); + //To zero hour Jan 1 next year + dtBefore = new DateTime(RelativeNow.AddYears(1).Year, 1, 1, 00, 00, 00).AddHours(TimeZoneAdjustment); + BuildBetweenTwoDatesFragment(SqlColumnNameToFilter, sb, dtAfter, dtBefore); + break; + + default: + throw new System.ArgumentOutOfRangeException("TOKEN", sOperator, "DataListSqlFilterCriteriaBuilder invalid filter TOKEN type [" + sValue + "] IN DATE_TIME"); + + //----- + } + + #endregion + } + else + { \ No newline at end of file