Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VCST-2303: add changeCartCurrency mutation #24

Merged
merged 12 commits into from
Dec 20, 2024
65 changes: 38 additions & 27 deletions src/VirtoCommerce.XCart.Core/CartAggregate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,47 +205,56 @@ public virtual async Task<CartAggregate> AddConfiguredItemAsync(NewCartItem newC

public virtual async Task<CartAggregate> AddItemAsync(NewCartItem newCartItem)
{
EnsureCartExists();

ArgumentNullException.ThrowIfNull(newCartItem);

EnsureCartExists();

var validationResult = await AbstractTypeFactory<NewCartItemValidator>.TryCreateInstance().ValidateAsync(newCartItem, options => options.IncludeRuleSets(ValidationRuleSet));
if (!validationResult.IsValid)
{
OperationValidationErrors.AddRange(validationResult.Errors);
}
else if (newCartItem.CartProduct != null)
{
if (newCartItem.IsWishlist && newCartItem.CartProduct.Price == null)

if (!newCartItem.IgnoreValidationErrors)
{
newCartItem.CartProduct.Price = new ProductPrice(Currency);
return this;
}
}

var lineItem = _mapper.Map<LineItem>(newCartItem.CartProduct);
if (newCartItem.CartProduct == null)
{
return this;
}

lineItem.SelectedForCheckout = IsSelectedForCheckout;
lineItem.Quantity = newCartItem.Quantity;
if (newCartItem.IsWishlist && newCartItem.CartProduct.Price == null)
{
newCartItem.CartProduct.Price = new ProductPrice(Currency);
}

if (newCartItem.Price != null)
{
lineItem.ListPrice = newCartItem.Price.Value;
lineItem.SalePrice = newCartItem.Price.Value;
}
else
{
SetLineItemTierPrice(newCartItem.CartProduct.Price, newCartItem.Quantity, lineItem);
}
var lineItem = _mapper.Map<LineItem>(newCartItem.CartProduct);

if (!string.IsNullOrEmpty(newCartItem.Comment))
{
lineItem.Note = newCartItem.Comment;
}
lineItem.Currency ??= Currency.Code;
lineItem.SelectedForCheckout = newCartItem.IsSelectedForCheckout ?? IsSelectedForCheckout;
lineItem.Quantity = newCartItem.Quantity;

CartProducts[newCartItem.CartProduct.Id] = newCartItem.CartProduct;
await SetItemFulfillmentCenterAsync(lineItem, newCartItem.CartProduct);
await UpdateVendor(lineItem, newCartItem.CartProduct);
await InnerAddLineItemAsync(lineItem, newCartItem.CartProduct, newCartItem.DynamicProperties);
if (newCartItem.Price != null)
{
lineItem.ListPrice = newCartItem.Price.Value;
lineItem.SalePrice = newCartItem.Price.Value;
}
else
{
SetLineItemTierPrice(newCartItem.CartProduct.Price, newCartItem.Quantity, lineItem);
}

if (!string.IsNullOrEmpty(newCartItem.Comment))
{
lineItem.Note = newCartItem.Comment;
}

CartProducts[newCartItem.CartProduct.Id] = newCartItem.CartProduct;
await SetItemFulfillmentCenterAsync(lineItem, newCartItem.CartProduct);
await UpdateVendor(lineItem, newCartItem.CartProduct);
await InnerAddLineItemAsync(lineItem, newCartItem.CartProduct, newCartItem.DynamicProperties);

return this;
}
Expand All @@ -270,7 +279,9 @@ await AddItemAsync(new NewCartItem(item.ProductId, item.Quantity)
DynamicProperties = item.DynamicProperties,
Price = item.Price,
IsWishlist = item.IsWishlist,
IsSelectedForCheckout = item.IsSelectedForCheckout,
CartProduct = product,
IgnoreValidationErrors = item.IgnoreValidationErrors,
});
}
else
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using VirtoCommerce.XCart.Core.Commands.BaseCommands;

namespace VirtoCommerce.XCart.Core.Commands
{
public class ChangeCartCurrencyCommand : CartCommand
{
public string NewCurrencyCode { get; set; }
}
}
4 changes: 4 additions & 0 deletions src/VirtoCommerce.XCart.Core/Models/NewCartItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,9 @@ public NewCartItem(string productId, int quantity)
public IList<DynamicPropertyValue> DynamicProperties { get; set; }

public bool IsWishlist { get; set; }

public bool? IsSelectedForCheckout { get; set; }

public bool IgnoreValidationErrors { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using GraphQL.Types;

namespace VirtoCommerce.XCart.Core.Schemas
{
public class InputChangeCartCurrencyType : InputCartBaseType
{
public InputChangeCartCurrencyType()
{
Field<NonNullGraphType<StringGraphType>>("newCurrencyCode", "Second cart currency");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using VirtoCommerce.Xapi.Core.Models;
using VirtoCommerce.XCart.Core;
using VirtoCommerce.XCart.Core.Commands;
using VirtoCommerce.XCart.Core.Commands.BaseCommands;
using VirtoCommerce.XCart.Core.Models;
using VirtoCommerce.XCart.Core.Services;

namespace VirtoCommerce.XCart.Data.Commands
{
public class ChangeCartCurrencyCommandHandler : CartCommandHandler<ChangeCartCurrencyCommand>
{
public ChangeCartCurrencyCommandHandler(ICartAggregateRepository cartAggregateRepository)
: base(cartAggregateRepository)
{
}

public override async Task<CartAggregate> Handle(ChangeCartCurrencyCommand request, CancellationToken cancellationToken)
{
// get (or create) both carts
var currentCurrencyCartAggregate = await GetOrCreateCartFromCommandAsync(request);

var newCurrencyCartRequest = new ChangeCartCurrencyCommand
{
StoreId = request.StoreId ?? currentCurrencyCartAggregate.Cart.StoreId,
CartName = request.CartName ?? currentCurrencyCartAggregate.Cart.Name,
CartType = request.CartType ?? currentCurrencyCartAggregate.Cart.Type,
UserId = request.UserId ?? currentCurrencyCartAggregate.Cart.CustomerId,
OrganizationId = request.OrganizationId ?? currentCurrencyCartAggregate.Cart.OrganizationId,
CultureName = request.CultureName ?? currentCurrencyCartAggregate.Cart.LanguageCode,
CurrencyCode = request.NewCurrencyCode,
};

var newCurrencyCartAggregate = await GetOrCreateCartFromCommandAsync(newCurrencyCartRequest);

// clear (old) cart items and add items from the currency cart
newCurrencyCartAggregate.Cart.Items.Clear();

var newCartItems = currentCurrencyCartAggregate.LineItems
.Select(x => new NewCartItem(x.ProductId, x.Quantity)
{
IgnoreValidationErrors = true,
Comment = x.Note,
IsSelectedForCheckout = x.SelectedForCheckout,
DynamicProperties = x.DynamicProperties.SelectMany(x => x.Values.Select(y => new DynamicPropertyValue()
{
Name = x.Name,
Value = y.Value,
Locale = y.Locale,
})).ToArray(),
})
.ToArray();

await newCurrencyCartAggregate.AddItemsAsync(newCartItems);

await CartRepository.SaveAsync(newCurrencyCartAggregate);
return newCurrencyCartAggregate;
}
}
}
19 changes: 19 additions & 0 deletions src/VirtoCommerce.XCart.Data/Schemas/PurchaseSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,25 @@ public void Build(ISchema schema)

schema.Mutation.AddField(margeCartField);

var changeCartCurrency = FieldBuilder.Create<CartAggregate, CartAggregate>(GraphTypeExtenstionHelper.GetActualType<CartType>())
.Name("changeCartCurrency")
.Argument(GraphTypeExtenstionHelper.GetActualComplexType<NonNullGraphType<InputChangeCartCurrencyType>>(), SchemaConstants.CommandName)
.ResolveSynchronizedAsync(CartPrefix, "userId", _distributedLockService, async context =>
{
var cartCommand = context.GetCartCommand<ChangeCartCurrencyCommand>();

await CheckAuthByCartCommandAsync(context, cartCommand);

//We need to add cartAggregate to the context to be able use it on nested cart types resolvers (e.g for currency)
var cartAggregate = await _mediator.Send(cartCommand);

//store cart aggregate in the user context for future usage in the graph types resolvers
context.SetExpandedObjectGraph(cartAggregate);
return cartAggregate;
}).FieldType;

schema.Mutation.AddField(changeCartCurrency);

/// <example>
/// This is an example JSON request for a mutation
/// {
Expand Down
Loading