private Cart GetCart(string cartId, CommerceContext commerceContext, string baseUrl) { var shopName = commerceContext.CurrentShopName(); var shopperId = commerceContext.CurrentShopperId(); var customerId = commerceContext.CurrentCustomerId(); var environment = commerceContext.Environment.Name; var url = string.Format(Constants.Settings.EndpointUrl, baseUrl, cartId); var client = new HttpClient(); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Constants.Settings.AppJson)); client.DefaultRequestHeaders.Add(Constants.Settings.ShopName, shopName); client.DefaultRequestHeaders.Add(Constants.Settings.ShopperId, shopperId); client.DefaultRequestHeaders.Add(Constants.Settings.Language, "en-US"); client.DefaultRequestHeaders.Add(Constants.Settings.Environment, environment); client.DefaultRequestHeaders.Add(Constants.Settings.CustomerId, customerId); client.DefaultRequestHeaders.Add(Constants.Settings.Currency, commerceContext.CurrentCurrency()); client.DefaultRequestHeaders.Add(Constants.Settings.Roles, Constants.Settings.CartRoles); try { var cart = new Cart(); var response = client.GetAsync(url).Result; if (response != null) { var task = response.Content.ReadAsStreamAsync().ContinueWith(t => { var stream = t.Result; using (var reader = new StreamReader(stream)) { var responseValue = reader.ReadToEnd(); cart = JsonConvert.DeserializeObject <Cart>(responseValue); } }); task.Wait(); } client.Dispose(); return(cart); } catch (Exception ex) { Console.WriteLine(ex.Message); client.Dispose(); return(null); } }
public static CartLevelAwardedAdjustment CreateCartLevelAwardedAdjustment(decimal amountOff, string awardingBlock, CommerceContext commerceContext) { var propertiesModel = commerceContext.GetObject <PropertiesModel>(); string discount = commerceContext.GetPolicy <KnownCartAdjustmentTypesPolicy>().Discount; var adjustment = new CartLevelAwardedAdjustment { Name = propertiesModel?.GetPropertyValue("PromotionText") as string ?? discount, DisplayName = propertiesModel?.GetPropertyValue("PromotionCartText") as string ?? discount, Adjustment = new Money(commerceContext.CurrentCurrency(), amountOff), AdjustmentType = discount, IsTaxable = false, AwardingBlock = awardingBlock }; return(adjustment); }
/// <summary> /// The process of the command /// </summary> /// <param name="commerceContext"> /// The commerce context /// </param> /// <param name="cartLineComponent"></param> /// <param name="awardingAction"></param> /// <returns> /// The <see cref="Task"/>. /// </returns> public virtual void Process(CommerceContext commerceContext, [NotNull] CartLineComponent cartLineComponent, [NotNull] string awardingAction) { using (CommandActivity.Start(commerceContext, this)) { var discountAdjustmentType = commerceContext.GetPolicy <KnownCartAdjustmentTypesPolicy>().Discount; var propertiesModel = commerceContext.GetObject <PropertiesModel>(); var totals = commerceContext?.GetObject <CartTotals>(); var discountAmount = cartLineComponent.UnitListPrice.Amount * decimal.MinusOne; cartLineComponent.Adjustments.Add(new CartLineLevelAwardedAdjustment { Name = (propertiesModel?.GetPropertyValue("PromotionText") as string ?? discountAdjustmentType), DisplayName = (propertiesModel?.GetPropertyValue("PromotionCartText") as string ?? discountAdjustmentType), Adjustment = new Money(commerceContext.CurrentCurrency(), discountAmount), AdjustmentType = discountAdjustmentType, IsTaxable = false, AwardingBlock = propertiesModel?.GetPropertyValue("PromotionId") as string }); totals.Lines[cartLineComponent.Id].SubTotal.Amount = totals.Lines[cartLineComponent.Id].SubTotal.Amount + discountAmount; cartLineComponent.GetComponent <MessagesComponent>().AddMessage(commerceContext.GetPolicy <KnownMessageCodePolicy>().Promotions, string.Format("PromotionApplied: {0}", propertiesModel?.GetPropertyValue("PromotionId") ?? awardingAction)); } }
public void Execute_WithProperties( BaseCartItemSubtotalAmountOffAction action, IRuleValue <decimal> subtotal, IRuleValue <decimal> amountOff, Cart cart, CommerceContext commerceContext, IRuleExecutionContext context) { /********************************************** * Arrange **********************************************/ cart.Adjustments.Clear(); cart.Lines.ForEach(l => l.Adjustments.Clear()); var globalPricingPolicy = commerceContext.GetPolicy <GlobalPricingPolicy>(); globalPricingPolicy.ShouldRoundPriceCalc = false; cart.Lines.ForEach(l => l.Totals.SubTotal.Amount = 100); var cartline = cart.Lines[1]; cartline.Totals.SubTotal.Amount = 150; var cartTotals = new CartTotals(cart); subtotal.Yield(context).ReturnsForAnyArgs(150); amountOff.Yield(context).ReturnsForAnyArgs(25); var propertiesModel = new PropertiesModel(); propertiesModel.Properties.Add("PromotionId", "id"); propertiesModel.Properties.Add("PromotionCartText", "carttext"); propertiesModel.Properties.Add("PromotionText", "text"); commerceContext.AddObject(propertiesModel); context.Fact <CommerceContext>().ReturnsForAnyArgs(commerceContext); commerceContext.AddObject(cartTotals); commerceContext.AddObject(cart); action.MatchingLines(context).ReturnsForAnyArgs(cart.Lines); action.SubtotalOperator = new DecimalGreaterThanEqualToOperator(); action.Subtotal = subtotal; action.AmountOff = amountOff; /********************************************** * Act **********************************************/ Action executeAction = () => action.Execute(context); /********************************************** * Assert **********************************************/ executeAction.Should().NotThrow <Exception>(); cart.Lines.SelectMany(l => l.Adjustments).Should().HaveCount(1); cart.Adjustments.Should().BeEmpty(); cartTotals.Lines[cartline.Id].SubTotal.Amount.Should().Be(125); cartline.Adjustments.Should().NotBeEmpty(); cartline.Adjustments.FirstOrDefault().Should().NotBeNull(); cartline.Adjustments.FirstOrDefault().Should().BeOfType <CartLineLevelAwardedAdjustment>(); cartline.Adjustments.FirstOrDefault()?.Name.Should().Be("text"); cartline.Adjustments.FirstOrDefault()?.DisplayName.Should().Be("carttext"); cartline.Adjustments.FirstOrDefault()?.AdjustmentType.Should().Be(commerceContext.GetPolicy <KnownCartAdjustmentTypesPolicy>().Discount); cartline.Adjustments.FirstOrDefault()?.AwardingBlock.Should().Contain(nameof(BaseCartItemSubtotalAmountOffAction)); cartline.Adjustments.FirstOrDefault()?.IsTaxable.Should().BeFalse(); cartline.Adjustments.FirstOrDefault()?.Adjustment.CurrencyCode.Should().Be(commerceContext.CurrentCurrency()); cartline.Adjustments.FirstOrDefault()?.Adjustment.Amount.Should().Be(-25); cartline.HasComponent <MessagesComponent>().Should().BeTrue(); }
public void Execute_WithProperties( IRuleValue <string> fulfillmentOptionName, IRuleValue <decimal> amountOff, Cart cart, CommerceContext commerceContext, IRuleExecutionContext context, string fulfillmentOptionNameValue, FulfillmentComponent fulfillmentComponent) { /********************************************** * Arrange **********************************************/ const decimal FULFILLMENT_FEE = MINIMUM_AMOUNT_OFF + 10m; cart.Adjustments.Clear(); var awardedAdjustment = new AwardedAdjustment() { Name = "FulfillmentFee" }; awardedAdjustment.Adjustment = new Money(FULFILLMENT_FEE); cart.Adjustments.Add(awardedAdjustment); cart.Lines.ForEach(l => l.Adjustments.Clear()); cart.SetComponent(fulfillmentComponent); context.Fact <CommerceContext>().ReturnsForAnyArgs(commerceContext); commerceContext.AddObject(cart); var globalPricingPolicy = commerceContext.GetPolicy <GlobalPricingPolicy>(); globalPricingPolicy.ShouldRoundPriceCalc = false; fulfillmentOptionName.Yield(context).ReturnsForAnyArgs(fulfillmentOptionNameValue); amountOff.Yield(context).ReturnsForAnyArgs(MINIMUM_AMOUNT_OFF); var propertiesModel = new PropertiesModel(); propertiesModel.Properties.Add("PromotionId", "id"); propertiesModel.Properties.Add("PromotionCartText", "carttext"); propertiesModel.Properties.Add("PromotionText", "text"); commerceContext.AddObject(propertiesModel); var commander = Substitute.For <CommerceCommander>(Substitute.For <IServiceProvider>()); var command = Substitute.For <GetFulfillmentMethodsCommand>( Substitute.For <IFindEntityPipeline>(), Substitute.For <IGetCartFulfillmentMethodsPipeline>(), Substitute.For <IGetCartLineFulfillmentMethodsPipeline>(), Substitute.For <IGetFulfillmentMethodsPipeline>(), Substitute.For <IServiceProvider>()); var fulfillmentMethod = new FulfillmentMethod() { FulfillmentType = fulfillmentOptionNameValue }; command.Process(commerceContext).ReturnsForAnyArgs(new List <FulfillmentMethod>() { fulfillmentMethod }.AsEnumerable()); commander.When(x => x.Command <GetFulfillmentMethodsCommand>()).DoNotCallBase(); commander.Command <GetFulfillmentMethodsCommand>().Returns(command); var action = new CartShippingOptionAmountOffAction(commander) { FulfillmentOptionName = fulfillmentOptionName, AmountOff = amountOff }; /********************************************** * Act **********************************************/ Action executeAction = () => action.Execute(context); /********************************************** * Assert **********************************************/ executeAction.Should().NotThrow <Exception>(); cart.Lines.SelectMany(l => l.Adjustments).Should().HaveCount(0); cart.Adjustments.Should().NotBeEmpty(); cart.Adjustments.LastOrDefault().Should().NotBeNull(); cart.Adjustments.LastOrDefault().Should().BeOfType <CartLevelAwardedAdjustment>(); cart.Adjustments.LastOrDefault().Name.Should().Be("text"); cart.Adjustments.LastOrDefault().DisplayName.Should().Be("carttext"); cart.Adjustments.LastOrDefault().AdjustmentType.Should().Be(commerceContext.GetPolicy <KnownCartAdjustmentTypesPolicy>().Discount); cart.Adjustments.LastOrDefault().AwardingBlock.Should().Contain(nameof(CartShippingOptionAmountOffAction)); cart.Adjustments.LastOrDefault().IsTaxable.Should().BeFalse(); cart.Adjustments.LastOrDefault().Adjustment.CurrencyCode.Should().Be(commerceContext.CurrentCurrency()); cart.Adjustments.LastOrDefault().Adjustment.Amount.Should().Be(-MINIMUM_AMOUNT_OFF); cart.HasComponent <MessagesComponent>().Should().BeTrue(); }
public void Execute(IRuleExecutionContext context) { CommerceContext commerceContext = context.Fact <CommerceContext>((string)null); CommerceContext commerceContext1 = commerceContext; Cart cart = commerceContext1 != null?commerceContext1.GetObjects <Cart>().FirstOrDefault <Cart>() : (Cart)null; CommerceContext commerceContext2 = commerceContext; CartTotals totals = commerceContext2 != null?commerceContext2.GetObjects <CartTotals>().FirstOrDefault <CartTotals>() : (CartTotals)null; if (cart == null || !cart.Lines.Any <CartLineComponent>() || (totals == null || !totals.Lines.Any <KeyValuePair <string, Totals> >())) { return; } List <CartLineComponent> list = new List <CartLineComponent>(); //Get the valid cartline items that matches specific tag provided foreach (var cartLine in cart.Lines.Where(x => x.HasComponent <CartProductComponent>())) { var firstOrDefault = cartLine.GetComponent <CartProductComponent>().Tags.FirstOrDefault(t => t.Name == this.Tag.Yield(context)); if (!string.IsNullOrEmpty(firstOrDefault?.Name)) { list.Add(cartLine); } } if (!list.Any <CartLineComponent>()) { return; } list.ForEach((Action <CartLineComponent>)(line => { if (!totals.Lines.ContainsKey(line.Id)) { return; } PropertiesModel propertiesModel = commerceContext.GetObject <PropertiesModel>(); string discountPolicy = commerceContext.GetPolicy <KnownCartAdjustmentTypesPolicy>().Discount; //Extract the coupon code in-order to associate coupon code with adjustment (1 to 1 mapping) string couponCode = string.Empty; if (cart.HasComponent <CartCouponsComponent>()) { if (cart.GetComponent <CartCouponsComponent>().List != null && cart.GetComponent <CartCouponsComponent>().List.Any()) { couponCode = cart.GetComponent <CartCouponsComponent>().List.FirstOrDefault(c => c.Promotion.EntityTarget == (string)propertiesModel?.GetPropertyValue("PromotionId"))?.CouponId; } } //calculate discounts on specified custom pricing if (line.HasComponent <CustomPriceInfoComponent>()) { var customPriceInfo = line.GetComponent <CustomPriceInfoComponent>(); Decimal discount = 0; if (this.BasePrice.Yield(context)) { discount += (Decimal)((double)this.PercentOff.Yield(context) * 0.01) * (decimal.Parse(customPriceInfo.BasePrice.ToString())); } if (this.ActivationPrice.Yield(context)) { discount += (Decimal)((double)this.PercentOff.Yield(context) * 0.01) * (decimal.Parse(customPriceInfo.ActivationPrice.ToString())); } if (this.DeliveryPrice.Yield(context)) { discount += (Decimal)((double)this.PercentOff.Yield(context) * 0.01) * (decimal.Parse(customPriceInfo.DeliveryPrice.ToString())); } if (commerceContext.GetPolicy <GlobalPricingPolicy>().ShouldRoundPriceCalc) { discount = Decimal.Round(discount, commerceContext.GetPolicy <GlobalPricingPolicy>().RoundDigits, commerceContext.GetPolicy <GlobalPricingPolicy>().MidPointRoundUp ? MidpointRounding.AwayFromZero : MidpointRounding.ToEven); } Decimal amount = discount * Decimal.MinusOne; //Create an adjustment and associate coupon code with coupon description delimited by '|' [Workaround for known issue with Promotion Plugin] IList <AwardedAdjustment> adjustments = line.Adjustments; adjustments.Add((AwardedAdjustment) new CartLineLevelAwardedAdjustment() { Name = (propertiesModel?.GetPropertyValue("PromotionText") as string ?? discountPolicy), DisplayName = couponCode + "|" + (propertiesModel?.GetPropertyValue("PromotionCartText") as string ?? discountPolicy), Adjustment = new Money(commerceContext.CurrentCurrency(), amount), AdjustmentType = discountPolicy, IsTaxable = false, AwardingBlock = nameof(CustomPercentOffAction) }); totals.Lines[line.Id].SubTotal.Amount = totals.Lines[line.Id].SubTotal.Amount + amount; line.GetComponent <MessagesComponent>().AddMessage(commerceContext.GetPolicy <KnownMessageCodePolicy>().Promotions, string.Format("PromotionApplied: {0}", propertiesModel?.GetPropertyValue("PromotionId") ?? (object)nameof(CustomPercentOffAction))); } })); }
private async Task PrettifyChild(EntityView entity, CommerceContext commerceContext) { ViewProperty originalEntity = entity.Properties.First(x => x.Name.EqualsOrdinalIgnoreCase("Condition") || x.Name.EqualsOrdinalIgnoreCase("Action")); originalEntity.IsHidden = true; var fullEntity = new ViewProperty { DisplayName = originalEntity.DisplayName, IsHidden = false, IsReadOnly = originalEntity.IsReadOnly, IsRequired = originalEntity.IsRequired, Name = $"Full{originalEntity.Name}", OriginalType = "Html", Policies = originalEntity.Policies, RawValue = originalEntity.RawValue, Value = originalEntity.Value }; entity.Properties.Insert(entity.Properties.IndexOf(originalEntity), fullEntity); //Add the condition operator if exists at the begin of the condition ViewProperty conditionOperator = entity.Properties.FirstOrDefault(x => x.Name.EqualsOrdinalIgnoreCase("ConditionOperator")); if (conditionOperator != null) { conditionOperator.IsHidden = true; fullEntity.Value = $"{conditionOperator.Value} {fullEntity.Value}"; } //Replace all the variables within [] in the condition with the values var regex = new Regex("\\[(.*?)\\]"); MatchCollection matches = regex.Matches(fullEntity.Value); foreach (Match match in matches) { string variableName = match.Groups[1].ToString(); ViewProperty variable = entity.Properties.FirstOrDefault(x => x.DisplayName.EqualsOrdinalIgnoreCase(variableName)); if (variable == null && variableName.EqualsOrdinalIgnoreCase("Gift")) { variable = entity.Properties.FirstOrDefault(x => x.Name.EqualsOrdinalIgnoreCase("TargetItemId")); } if (variable != null) { variable.IsHidden = true; string variableValue = await PrettifyVariableValue(variable, entity.Properties, commerceContext); fullEntity.Value = fullEntity.Value.Replace(match.Value, $"<strong>{variableValue}</strong>"); } } fullEntity.Value = fullEntity.Value.Replace("$", commerceContext.CurrentCurrency()); // A quick and dirty resolution to let the content go over multiple lines. // Add extra div's with specific default classes because adding custom style is stripped by Angular. // The .dropdown-header class is for overwriting the white-space: nowrap, the .col-form-legend is for setting the font-size back to normal and .p-0 for removing the padding added by these classes fullEntity.Value = $"<div class='dropdown-header p-0 border-0'><div class='col-form-legend p-0'>{fullEntity.Value}</div></div>"; }
public void Execute_ShouldRoundPriceCalc_True( BaseCartItemSubtotalPercentOffAction action, IRuleValue <decimal> subtotal, IRuleValue <decimal> percentOff, Cart cart, CommerceContext commerceContext, IRuleExecutionContext context) { /********************************************** * Arrange **********************************************/ cart.Adjustments.Clear(); cart.Lines.ForEach(l => l.Adjustments.Clear()); var globalPricingPolicy = commerceContext.GetPolicy <GlobalPricingPolicy>(); globalPricingPolicy.ShouldRoundPriceCalc = true; globalPricingPolicy.RoundDigits = 3; globalPricingPolicy.MidPointRoundUp = true; cart.Lines.ForEach(l => l.Totals.SubTotal.Amount = 100); var cartline = cart.Lines[1]; cartline.Totals.SubTotal.Amount = 175; var cartTotals = new CartTotals(cart); subtotal.Yield(context).ReturnsForAnyArgs(150); percentOff.Yield(context).ReturnsForAnyArgs(33.3333333M); context.Fact <CommerceContext>().ReturnsForAnyArgs(commerceContext); commerceContext.AddObject(cartTotals); commerceContext.AddObject(cart); action.MatchingLines(context).ReturnsForAnyArgs(cart.Lines); action.SubtotalOperator = new DecimalGreaterThanEqualToOperator(); action.Subtotal = subtotal; action.PercentOff = percentOff; /********************************************** * Act **********************************************/ Action executeAction = () => action.Execute(context); /********************************************** * Assert **********************************************/ executeAction.Should().NotThrow <Exception>(); cart.Lines.SelectMany(l => l.Adjustments).Should().HaveCount(1); cart.Adjustments.Should().BeEmpty(); cartTotals.Lines[cartline.Id].SubTotal.Amount.Should().Be(116.667M); cartline.Adjustments.Should().NotBeEmpty(); cartline.Adjustments.FirstOrDefault().Should().NotBeNull(); cartline.Adjustments.FirstOrDefault().Should().BeOfType <CartLineLevelAwardedAdjustment>(); cartline.Adjustments.FirstOrDefault()?.Name.Should().Be(commerceContext.GetPolicy <KnownCartAdjustmentTypesPolicy>().Discount); cartline.Adjustments.FirstOrDefault()?.DisplayName.Should().Be(commerceContext.GetPolicy <KnownCartAdjustmentTypesPolicy>().Discount); cartline.Adjustments.FirstOrDefault()?.AdjustmentType.Should().Be(commerceContext.GetPolicy <KnownCartAdjustmentTypesPolicy>().Discount); cartline.Adjustments.FirstOrDefault()?.AwardingBlock.Should().Contain(nameof(BaseCartItemSubtotalPercentOffAction)); cartline.Adjustments.FirstOrDefault()?.IsTaxable.Should().BeFalse(); cartline.Adjustments.FirstOrDefault()?.Adjustment.CurrencyCode.Should().Be(commerceContext.CurrentCurrency()); cartline.Adjustments.FirstOrDefault()?.Adjustment.Amount.Should().Be(-58.333M); cartline.HasComponent <MessagesComponent>().Should().BeTrue(); }