Skip to content

Commit

Permalink
Merge branch 'dev' into feat/VCST-2241
Browse files Browse the repository at this point in the history
  • Loading branch information
ksavosteev authored Dec 6, 2024
2 parents 952871f + 5a7e51d commit 5e7e01a
Show file tree
Hide file tree
Showing 19 changed files with 397 additions and 61 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>
<!-- These properties will be shared for all projects -->
<PropertyGroup>
<VersionPrefix>3.818.0</VersionPrefix>
<VersionPrefix>3.819.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
<VersionSuffix Condition=" '$(VersionSuffix)' != '' AND '$(BuildNumber)' != '' ">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>
</PropertyGroup>
Expand Down
74 changes: 72 additions & 2 deletions src/VirtoCommerce.XCart.Core/CartAggregate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,16 @@ public virtual async Task<CartAggregate> ChangeItemQuantityAsync(ItemQtyAdjustme

if (lineItem != null)
{
SetLineItemTierPrice(qtyAdjustment.CartProduct.Price, qtyAdjustment.NewQuantity, lineItem);

lineItem.Quantity = qtyAdjustment.NewQuantity;

if (lineItem.IsConfigured)
{
await UpdateConfiguredLineItemPrice([lineItem]);
}
else
{
SetLineItemTierPrice(qtyAdjustment.CartProduct.Price, qtyAdjustment.NewQuantity, lineItem);
}
}

return this;
Expand Down Expand Up @@ -1101,6 +1108,69 @@ public virtual void SetLineItemTierPrice(ProductPrice productPrice, int quantity
}
}

public virtual Task<CartAggregate> UpdateConfiguredLineItemAsync(string lineItemId, LineItem configuredItem)
{
ArgumentNullException.ThrowIfNull(lineItemId);
ArgumentNullException.ThrowIfNull(configuredItem);

EnsureCartExists();

var lineItem = Cart.Items.FirstOrDefault(x => x.Id == lineItemId && x.IsConfigured);

if (lineItem != null)
{
lineItem.Quantity = configuredItem.Quantity;
lineItem.ListPrice = configuredItem.ListPrice;
lineItem.SalePrice = configuredItem.SalePrice;
lineItem.DiscountAmount = configuredItem.DiscountAmount;
lineItem.PlacedPrice = configuredItem.PlacedPrice;
lineItem.ExtendedPrice = configuredItem.ExtendedPrice;

lineItem.ConfigurationItems = new List<ConfigurationItem>(configuredItem.ConfigurationItems);
}

return Task.FromResult(this);
}

public virtual async Task<CartAggregate> UpdateConfiguredLineItemPrice(IList<LineItem> configuredItems)
{
var configProductsIds = configuredItems
.Where(x => !x.ConfigurationItems.IsNullOrEmpty())
.SelectMany(x => x.ConfigurationItems.Select(x => x.ProductId))
.Distinct()
.ToArray();

if (configProductsIds.Length == 0)
{
return this;
}

var configProducts = await _cartProductService.GetCartProductsByIdsAsync(this, configProductsIds);

foreach (var configurationLineItem in configuredItems)
{
var contaner = AbstractTypeFactory<ConfiguredLineItemContainer>.TryCreateInstance();

if (CartProducts.TryGetValue(configurationLineItem.ProductId, out var configurableProduct))
{
contaner.ConfigurableProduct = configurableProduct;
}

foreach (var configurationItem in configurationLineItem.ConfigurationItems ?? [])
{
var product = configProducts.FirstOrDefault(x => x.Product.Id == configurationItem.ProductId);
if (product != null)
{
contaner.AddItem(product, configurationItem.Quantity, configurationItem.SectionId);
}
}

contaner.UpdatePrice(configurationLineItem);
}

return this;
}

#region ICloneable

public virtual object Clone()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using VirtoCommerce.XCart.Core.Commands.BaseCommands;
using VirtoCommerce.XCart.Core.Models;

namespace VirtoCommerce.XCart.Core.Commands;

public class ChangeCartConfiguredLineItemCommand : CartCommand
{
public string LineItemId { get; set; }

public int? Quantity { get; set; }

public IList<ProductConfigurationSection> ConfigurationSections { get; set; } = new List<ProductConfigurationSection>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,7 @@ public class CreateConfiguredLineItemCommand : ICommand<ExpConfigurationLineItem

public string ConfigurableProductId { get; set; }

public int Quantity { get; set; } = 1;

public IList<ProductConfigurationSection> ConfigurationSections { get; set; } = [];
}
42 changes: 27 additions & 15 deletions src/VirtoCommerce.XCart.Core/ConfiguredLineItemContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ public class ConfiguredLineItemContainer : ICloneable
public IList<string> ProductsIncludeFields { get; set; }

public CartProduct ConfigurableProduct { get; set; }
public IList<LineItem> Items { get; set; } = new List<LineItem>();

public LineItem AddItem(CartProduct cartProduct, int quantity)
private readonly List<SectionLineItem> _items = [];

public LineItem AddItem(CartProduct cartProduct, int quantity, string sectionId)
{
var lineItem = AbstractTypeFactory<LineItem>.TryCreateInstance();
lineItem.ProductId = cartProduct.Id;
Expand Down Expand Up @@ -51,17 +52,21 @@ public LineItem AddItem(CartProduct cartProduct, int quantity)
lineItem.ExtendedPrice = lineItem.PlacedPrice * lineItem.Quantity;
}

Items.Add(lineItem);
_items.Add(new SectionLineItem
{
Item = lineItem,
SectionId = sectionId,
});

return lineItem;
}

public ExpConfigurationLineItem CreateConfiguredLineItem()
public ExpConfigurationLineItem CreateConfiguredLineItem(int quantity)
{
var lineItem = AbstractTypeFactory<LineItem>.TryCreateInstance();

lineItem.IsConfigured = true;
lineItem.Quantity = 1;
lineItem.Quantity = quantity;

lineItem.Discounts = [];
lineItem.TaxDetails = [];
Expand All @@ -83,18 +88,19 @@ public ExpConfigurationLineItem CreateConfiguredLineItem()
lineItem.VendorId = ConfigurableProduct.Product.Vendor;

// create sub items
lineItem.ConfigurationItems = Items
lineItem.ConfigurationItems = _items
.Select(x =>
{
var subItem = AbstractTypeFactory<ConfigurationItem>.TryCreateInstance();

subItem.ProductId = x.ProductId;
subItem.Name = x.Name;
subItem.Sku = x.Sku;
subItem.ImageUrl = x.ImageUrl;
subItem.Quantity = x.Quantity;
subItem.CatalogId = x.CatalogId;
subItem.CategoryId = x.CategoryId;
subItem.SectionId = x.SectionId;
subItem.ProductId = x.Item.ProductId;
subItem.Name = x.Item.Name;
subItem.Sku = x.Item.Sku;
subItem.ImageUrl = x.Item.ImageUrl;
subItem.Quantity = x.Item.Quantity;
subItem.CatalogId = x.Item.CatalogId;
subItem.CategoryId = x.Item.CategoryId;

return subItem;
})
Expand All @@ -119,8 +125,8 @@ public void UpdatePrice(LineItem lineItem)
{
var configurableProductPrice = ConfigurableProduct.Price ?? new Xapi.Core.Models.ProductPrice(Currency);

lineItem.ListPrice = Items.Sum(x => x.ListPrice * x.Quantity) + configurableProductPrice.ListPrice.Amount;
lineItem.SalePrice = Items.Sum(x => x.SalePrice * x.Quantity) + configurableProductPrice.SalePrice.Amount;
lineItem.ListPrice = _items.Select(x => x.Item).Sum(x => x.ListPrice * x.Quantity) + configurableProductPrice.ListPrice.Amount;
lineItem.SalePrice = _items.Select(x => x.Item).Sum(x => x.SalePrice * x.Quantity) + configurableProductPrice.SalePrice.Amount;

lineItem.DiscountAmount = Math.Max(0, lineItem.ListPrice - lineItem.SalePrice);
lineItem.PlacedPrice = lineItem.ListPrice - lineItem.DiscountAmount;
Expand All @@ -144,5 +150,11 @@ public object Clone()
{
return MemberwiseClone();
}

private sealed class SectionLineItem
{
public string SectionId { get; set; }
public LineItem Item { get; set; }
}
}
}
11 changes: 11 additions & 0 deletions src/VirtoCommerce.XCart.Core/Models/ConfigurationItemsResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Collections.Generic;
using VirtoCommerce.CartModule.Core.Model;

namespace VirtoCommerce.XCart.Core.Models;

public class ConfigurationItemsResponse
{
public CartAggregate CartAggregate { get; set; }

public IList<ConfigurationItem> ConfigurationItems { get; set; } = [];
}
51 changes: 51 additions & 0 deletions src/VirtoCommerce.XCart.Core/Queries/GetConfigurationItemsQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Linq;
using GraphQL;
using GraphQL.Types;
using VirtoCommerce.Xapi.Core.BaseQueries;
using VirtoCommerce.Xapi.Core.Extensions;
using VirtoCommerce.XCart.Core.Models;

namespace VirtoCommerce.XCart.Core.Queries;

public class GetConfigurationItemsQuery : Query<ConfigurationItemsResponse>, ICartQuery
{
public IList<string> IncludeFields { get; set; } = new List<string>();
public string StoreId { get; set; }
public string CartType { get; set; }
public string CartName { get; set; }
public string UserId { get; set; }
public string OrganizationId { get; set; }
public string CurrencyCode { get; set; }
public string CultureName { get; set; }

public string CartId { get; set; }
public string LineItemId { get; set; }

public override IEnumerable<QueryArgument> GetArguments()
{
yield return Argument<StringGraphType>(nameof(CartId));
yield return Argument<NonNullGraphType<StringGraphType>>(nameof(LineItemId));
yield return Argument<NonNullGraphType<StringGraphType>>(nameof(StoreId), description: "Store Id");
yield return Argument<NonNullGraphType<StringGraphType>>(nameof(CurrencyCode), description: "Currency code (\"USD\")");
yield return Argument<StringGraphType>(nameof(CartType), description: "Cart type");
yield return Argument<StringGraphType>(nameof(CartName), description: "Cart name");
yield return Argument<StringGraphType>(nameof(UserId), description: "User Id");
yield return Argument<StringGraphType>(nameof(CultureName), description: "Culture name (\"en-Us\")");
}

public override void Map(IResolveFieldContext context)
{
CartId = context.GetArgument<string>(nameof(CartId));
LineItemId = context.GetArgument<string>(nameof(LineItemId));
StoreId = context.GetArgument<string>(nameof(StoreId));
CartType = context.GetArgument<string>(nameof(CartType));
CartName = context.GetArgument<string>(nameof(CartName));
UserId = context.GetArgument<string>(nameof(UserId));
OrganizationId = context.GetCurrentOrganizationId();
CurrencyCode = context.GetArgument<string>(nameof(CurrencyCode));
CultureName = context.GetArgument<string>(nameof(CultureName));

IncludeFields = context.SubFields.Values.GetAllNodesPaths(context).ToArray();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using VirtoCommerce.CartModule.Core.Model;
using VirtoCommerce.CartModule.Core.Model;
using VirtoCommerce.Xapi.Core.Schemas;

namespace VirtoCommerce.XCart.Core.Schemas
Expand All @@ -9,6 +9,9 @@ public CartConfigurationItemType()
{
Field(x => x.Id, nullable: false).Description("Configuration item ID");
Field(x => x.Name, nullable: true).Description("Configuration item name");
Field(x => x.SectionId, nullable: true).Description("Configuration item section ID");
Field(x => x.ProductId, nullable: true).Description("Configuration item product ID");
Field(x => x.Quantity, nullable: true).Description("Configuration item quantity");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using GraphQL.Types;
using VirtoCommerce.Xapi.Core.Schemas;
using VirtoCommerce.XCart.Core.Models;

namespace VirtoCommerce.XCart.Core.Schemas;

public class ConfigurationItemsResponseType : ExtendableGraphType<ConfigurationItemsResponse>
{
public ConfigurationItemsResponseType()
{
ExtendableField<ListGraphType<CartConfigurationItemType>>(
"configurationItems",
"Configuration items for configurable product",
resolve: context => context.Source.ConfigurationItems ?? []);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using GraphQL.Types;

namespace VirtoCommerce.XCart.Core.Schemas
{
public class InputChangeCartConfiguredItemType : InputCartBaseType
{
public InputChangeCartConfiguredItemType()
{
Field<NonNullGraphType<StringGraphType>>("lineItemId", "Line item Id");
Field<IntGraphType>("quantity", "Quantity");
Field<ListGraphType<ConfigurationSectionInput>>("configurationSections", "Configuration sections");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
<PackageReference Include="VirtoCommerce.Xapi.Core" Version="3.814.0" />
<PackageReference Include="VirtoCommerce.XCatalog.Core" Version="3.818.0" />
<PackageReference Include="VirtoCommerce.CartModule.Core" Version="3.820.0" />
<PackageReference Include="VirtoCommerce.CartModule.Core" Version="3.822.0" />
<PackageReference Include="VirtoCommerce.PaymentModule.Core" Version="3.804.0" />
<PackageReference Include="VirtoCommerce.ShippingModule.Core" Version="3.802.0" />
<PackageReference Include="VirtoCommerce.InventoryModule.Core" Version="3.805.0" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using VirtoCommerce.CartModule.Core.Model;
using VirtoCommerce.XCart.Core;
using VirtoCommerce.XCart.Core.Commands;
using VirtoCommerce.XCart.Core.Commands.BaseCommands;
using VirtoCommerce.XCart.Core.Services;

namespace VirtoCommerce.XCart.Data.Commands;

public class ChangeCartConfiguredLineItemCommandHandler : CartCommandHandler<ChangeCartConfiguredLineItemCommand>
{
private readonly IMediator _mediator;

public ChangeCartConfiguredLineItemCommandHandler(ICartAggregateRepository cartAggregateRepository, IMediator mediator)
: base(cartAggregateRepository)
{
_mediator = mediator;
}

public override async Task<CartAggregate> Handle(ChangeCartConfiguredLineItemCommand request, CancellationToken cancellationToken)
{
var cartAggregate = await GetOrCreateCartFromCommandAsync(request);

var lineItem = GetConfiguredLineItem(request, cartAggregate);
if (lineItem != null)
{
var command = new CreateConfiguredLineItemCommand
{
StoreId = request.StoreId,
UserId = request.UserId,
OrganizationId = request.OrganizationId,
CultureName = request.CultureName,
CurrencyCode = request.CurrencyCode,
ConfigurableProductId = lineItem.ProductId,
ConfigurationSections = request.ConfigurationSections,
Quantity = request.Quantity ?? lineItem.Quantity,
};

var mediatorResult = await _mediator.Send(command, cancellationToken);
await cartAggregate.UpdateConfiguredLineItemAsync(lineItem.Id, mediatorResult.Item);

return await SaveCartAsync(cartAggregate);
}

return cartAggregate;
}

private static LineItem GetConfiguredLineItem(ChangeCartConfiguredLineItemCommand request, CartAggregate cartAggregate)
{
return cartAggregate.Cart.Items.FirstOrDefault(x => x.Id == request.LineItemId && x.IsConfigured);
}
}
Loading

0 comments on commit 5e7e01a

Please sign in to comment.