diff --git a/FakeXrmEasy.Shared/Extensions/XmlExtensionsForFetchXml.cs b/FakeXrmEasy.Shared/Extensions/XmlExtensionsForFetchXml.cs index 93b77a03..1ed12797 100644 --- a/FakeXrmEasy.Shared/Extensions/XmlExtensionsForFetchXml.cs +++ b/FakeXrmEasy.Shared/Extensions/XmlExtensionsForFetchXml.cs @@ -26,7 +26,8 @@ public static class XmlExtensionsForFetchXml ConditionOperator.LastXMonths, ConditionOperator.LastXWeeks, ConditionOperator.LastXYears, - ConditionOperator.NextXWeeks + ConditionOperator.NextXWeeks, + ConditionOperator.InFiscalYear }; public static bool IsAttributeTrue(this XElement elem, string attributeName) @@ -520,6 +521,9 @@ public static ConditionExpression ToConditionExpression(this XElement elem, XrmF case "next-week": op = ConditionOperator.NextWeek; break; + case "in-fiscal-year": + op = ConditionOperator.InFiscalYear; + break; #if FAKE_XRM_EASY_9 case "contain-values": op = ConditionOperator.ContainValues; diff --git a/FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems b/FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems index 464baeb3..4b29a693 100644 --- a/FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems +++ b/FakeXrmEasy.Shared/FakeXrmEasy.Shared.projitems @@ -68,6 +68,7 @@ + diff --git a/FakeXrmEasy.Shared/FiscalYearSettings.cs b/FakeXrmEasy.Shared/FiscalYearSettings.cs new file mode 100644 index 00000000..3a35c7e1 --- /dev/null +++ b/FakeXrmEasy.Shared/FiscalYearSettings.cs @@ -0,0 +1,25 @@ +using Microsoft.Xrm.Sdk; +using Microsoft.Xrm.Sdk.Client; +using System; + +namespace FakeXrmEasy +{ + [EntityLogicalName("organization")] + public class FiscalYearSettings + { + [AttributeLogicalName("fiscalcalendarstart")] + public DateTime StartDate { get; set; } + + [AttributeLogicalName("fiscalperiodtype")] + public Template FiscalPeriodTemplate { get; set; } + + public enum Template + { + Annually = 2000, + SemiAnnually = 2001, + Quarterly = 2002, + Monthly = 2003, + FourWeek = 2004 + } + } +} diff --git a/FakeXrmEasy.Shared/XrmFakedContext.DateTime.cs b/FakeXrmEasy.Shared/XrmFakedContext.DateTime.cs index fc053568..553afd79 100644 --- a/FakeXrmEasy.Shared/XrmFakedContext.DateTime.cs +++ b/FakeXrmEasy.Shared/XrmFakedContext.DateTime.cs @@ -8,6 +8,8 @@ public partial class XrmFakedContext : IXrmContext { public TimeZoneInfo SystemTimeZone { get; set; } + public FiscalYearSettings FiscalYearSettings { get; set; } + public Dictionary> DateBehaviour { get; set; } private static Dictionary> DefaultDateBehaviour() diff --git a/FakeXrmEasy.Shared/XrmFakedContext.Queries.cs b/FakeXrmEasy.Shared/XrmFakedContext.Queries.cs index 50e50e28..c1c5eaf0 100644 --- a/FakeXrmEasy.Shared/XrmFakedContext.Queries.cs +++ b/FakeXrmEasy.Shared/XrmFakedContext.Queries.cs @@ -853,7 +853,8 @@ protected static Expression TranslateConditionExpression(QueryExpression qe, Xrm case ConditionOperator.LastWeek: case ConditionOperator.ThisWeek: case ConditionOperator.NextWeek: - operatorExpression = TranslateConditionExpressionBetweenDates(c, getNonBasicValueExpr, containsAttributeExpression); + case ConditionOperator.InFiscalYear: + operatorExpression = TranslateConditionExpressionBetweenDates(c, getNonBasicValueExpr, containsAttributeExpression, context); break; case ConditionOperator.Next7Days: @@ -1679,7 +1680,7 @@ protected static Expression TranslateConditionExpressionLast(TypedConditionExpre /// /// Takes a condition expression which needs translating into a 'between two dates' expression and works out the relevant dates /// - protected static Expression TranslateConditionExpressionBetweenDates(TypedConditionExpression tc, Expression getAttributeValueExpr, Expression containsAttributeExpr) + protected static Expression TranslateConditionExpressionBetweenDates(TypedConditionExpression tc, Expression getAttributeValueExpr, Expression containsAttributeExpr, XrmFakedContext context) { var c = tc.CondExpression; @@ -1690,6 +1691,7 @@ protected static Expression TranslateConditionExpressionBetweenDates(TypedCondit var thisYear = today.Year; var thisMonth = today.Month; + switch (c.Operator) { case ConditionOperator.ThisYear: // From first day of this year to last day of this year @@ -1731,6 +1733,13 @@ protected static Expression TranslateConditionExpressionBetweenDates(TypedCondit fromDate = today.ToFirstDayOfDeltaWeek(1); toDate = today.ToLastDayOfDeltaWeek(1).AddDays(1); break; + case ConditionOperator.InFiscalYear: + var fiscalYear = (int)c.Values[0]; + c.Values.Clear(); + var fiscalYearDate = context.FiscalYearSettings?.StartDate ?? new DateTime(fiscalYear, 4, 1); + fromDate = fiscalYearDate; + toDate = fiscalYearDate.AddYears(1).AddDays(-1); + break; } c.Values.Add(fromDate); diff --git a/FakeXrmEasy.Tests.Shared/FakeContextTests/FetchXml/ConditionOperatorTests.cs b/FakeXrmEasy.Tests.Shared/FakeContextTests/FetchXml/ConditionOperatorTests.cs index 1ac8a298..5380ee11 100644 --- a/FakeXrmEasy.Tests.Shared/FakeContextTests/FetchXml/ConditionOperatorTests.cs +++ b/FakeXrmEasy.Tests.Shared/FakeContextTests/FetchXml/ConditionOperatorTests.cs @@ -718,7 +718,7 @@ public void FetchXml_Operator_Last_Seven_Days_Translation() "; - + var query = XrmFakedContext.TranslateFetchXmlToQueryExpression(ctx, fetchXml); Assert.True(query.Criteria != null); @@ -1300,6 +1300,37 @@ public void FetchXml_Operator_ThisYear_Execution() Assert.Equal(((DateTime)collection.Entities[2]["anniversary"]).Year, thisYear); } + [Fact] + public void FetchXml_Operator_InFiscalYear_Execution() + { + var today = DateTime.Today; + var thisYear = today.Year; + + var ctx = new XrmFakedContext(); + ctx.FiscalYearSettings = new FiscalYearSettings() { StartDate = new DateTime(thisYear, 1, 2), FiscalPeriodTemplate = FiscalYearSettings.Template.Annually }; + var fetchXml = $@" + + + + + + + "; + + var ct1 = new Contact() { Id = Guid.NewGuid(), Anniversary = new DateTime(thisYear, 1, 2) }; // Second day of this year - should be returned + var ct2 = new Contact() { Id = Guid.NewGuid(), Anniversary = new DateTime(thisYear, 12, 31) }; // Last day of this year - should be returned + var ct3 = new Contact() { Id = Guid.NewGuid(), Anniversary = new DateTime(thisYear + 1, 1, 2) }; // Second day of next year - should not be returned + ctx.Initialize(new[] { ct1, ct2, ct3 }); + var service = ctx.GetOrganizationService(); + + var collection = service.RetrieveMultiple(new FetchExpression(fetchXml)); + + Assert.Equal(2, collection.Entities.Count); + + Assert.Equal(((DateTime)collection.Entities[0]["anniversary"]).Year, thisYear); + Assert.Equal(((DateTime)collection.Entities[1]["anniversary"]).Year, thisYear); + } + [Fact] public void FetchXml_Operator_ThisMonth_Execution() { @@ -1366,7 +1397,7 @@ public void FetchXml_Operator_LastMonth_Execution() Assert.Equal(2, collection.Entities.Count); Assert.Equal(((DateTime)collection.Entities[0]["anniversary"]).Month, lastMonth); - Assert.Equal(((DateTime)collection.Entities[1]["anniversary"]).Month, lastMonth); + Assert.Equal(((DateTime)collection.Entities[1]["anniversary"]).Month, lastMonth); } [Fact] @@ -1384,7 +1415,7 @@ public void FetchXml_Operator_NextMonth_Execution() var today = DateTime.Today; var thisYear = today.Year; - var thisMonth = today.Month; + var thisMonth = today.Month; var nextMonth = new DateTime(thisYear, thisMonth, 1).AddMonths(1).Month; var ct1 = new Contact() { Id = Guid.NewGuid(), Anniversary = today }; // Today - Should not be returned var ct2 = new Contact() { Id = Guid.NewGuid(), Anniversary = new DateTime(thisYear, thisMonth, 1) }; // First day of this month - should not be returned @@ -1393,7 +1424,7 @@ public void FetchXml_Operator_NextMonth_Execution() var ct5 = new Contact() { Id = Guid.NewGuid(), Anniversary = new DateTime(thisYear, thisMonth, 1).AddMonths(2).AddDays(-1) }; // Last day of next month - should be returned var ct6 = new Contact() { Id = Guid.NewGuid(), Anniversary = new DateTime(thisYear, thisMonth, 1).AddDays(-1) }; // Last day of last month - should not be returned var ct7 = new Contact() { Id = Guid.NewGuid(), Anniversary = new DateTime(thisYear, thisMonth, 1).AddMonths(-1) }; // First day of last month - should not be returned - + ctx.Initialize(new[] { ct1, ct2, ct3, ct4, ct5, ct6, ct7 }); var service = ctx.GetFakedOrganizationService(); @@ -1580,9 +1611,9 @@ public void FetchXml_Operator_Next_X_Weeks_Execution() "; var date = DateTime.Now; - var ct1 = new Contact() { Id = Guid.NewGuid(), Anniversary = date.AddDays(7*2) }; //Should be returned - var ct2 = new Contact() { Id = Guid.NewGuid(), Anniversary = date.AddDays(7*4) }; //Shouldnt - ctx.Initialize(new[] { ct1, ct2}); + var ct1 = new Contact() { Id = Guid.NewGuid(), Anniversary = date.AddDays(7 * 2) }; //Should be returned + var ct2 = new Contact() { Id = Guid.NewGuid(), Anniversary = date.AddDays(7 * 4) }; //Shouldnt + ctx.Initialize(new[] { ct1, ct2 }); var service = ctx.GetOrganizationService(); var collection = service.RetrieveMultiple(new FetchExpression(fetchXml)); @@ -1789,7 +1820,7 @@ public void FetchXml_Operator_Next_Week_Execution() Assert.Equal(retrievedUser, ct1.Id); } - + #if FAKE_XRM_EASY_9 [Fact] public void FetchXml_Operator_ContainValues_Translation()