Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/VirtoCommerce.OrdersModule.Core/Model/PurchasedProduct.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace VirtoCommerce.OrdersModule.Core.Model
{
public class PurchasedProduct
{
public string ProductId { get; set; }

public string StoreId { get; set; }

public string UserId { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace VirtoCommerce.OrdersModule.Core.Model
{
public class PurchasedProductsGroupedRequest
{
public IList<string> ProductIds { get; set; } = [];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Collections.Generic;

namespace VirtoCommerce.OrdersModule.Core.Model
{
public class PurchasedProductsRequest
{
public string StoreId { get; set; }

public string UserId { get; set; }

public IList<string> ProductIds { get; set; } = [];

public int? ProductsLimit { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace VirtoCommerce.OrdersModule.Core.Model
{
public class PurchasedProductsResult
{
public IList<string> ProductIds { get; set; } = [];
}
}
31 changes: 31 additions & 0 deletions src/VirtoCommerce.OrdersModule.Core/ModuleConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class ModuleConstants

public static string OrderIndexDocumentType { get; } = OrderIndexDocumentTypeConstant;

public const string PurchasedProductDocumentPrefix = "__purchased_by_user";

public static class Security
{
public static class Permissions
Expand Down Expand Up @@ -249,6 +251,31 @@ public static class General
DefaultValue = false,
};

public static SettingDescriptor PurchasedProductIndexation { get; } = new SettingDescriptor
{
Name = "Order.PurchasedProductIndexation.Enable",
GroupName = "Orders|Products",
ValueType = SettingValueType.Boolean,
DefaultValue = false,
};

public static SettingDescriptor EventBasedPurchasedProductIndexation { get; } = new SettingDescriptor
{
Name = "Order.EventBasedPurchasedProductIndexation.Enable",
GroupName = "Orders|Products",
ValueType = SettingValueType.Boolean,
DefaultValue = false
};

public static SettingDescriptor PurchasedProductStoreFilter { get; } = new SettingDescriptor
{
Name = "Order.PurchasedProductStoreFilter.Enable",
GroupName = "Orders|Products",
ValueType = SettingValueType.Boolean,
DefaultValue = false,
IsPublic = true,
};

public static IEnumerable<SettingDescriptor> AllSettings
{
get
Expand All @@ -271,6 +298,9 @@ public static IEnumerable<SettingDescriptor> AllSettings
yield return CustomerOrderValidation;
yield return OrderPaidAndOrderSentNotifications;
yield return PaymentShipmentStatusChangedNotifications;
yield return PurchasedProductIndexation;
yield return EventBasedPurchasedProductIndexation;
yield return PurchasedProductStoreFilter;
}
}
}
Expand All @@ -283,6 +313,7 @@ public static IEnumerable<SettingDescriptor> StoreLevelSettings
yield return General.OrderPaymentInNewNumberTemplate;
yield return General.OrderShipmentNewNumberTemplate;
yield return General.RefundNewNumberTemplate;
yield return General.PurchasedProductStoreFilter;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using VirtoCommerce.OrdersModule.Core.Model;

namespace VirtoCommerce.OrdersModule.Core.Services;

public interface IPurchasedProductsService
{
Task<PurchasedProductsResult> GetPurchasedProductsAsync(PurchasedProductsRequest request);

Task<IDictionary<string, IEnumerable<PurchasedProduct>>> GetGroupedPurchasedProductsAsync(PurchasedProductsGroupedRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VirtoCommerce.OrdersModule.Core.Events;
using VirtoCommerce.OrdersModule.Data.Search.Indexed;
using VirtoCommerce.Platform.Core.Common;
using VirtoCommerce.Platform.Core.Events;
using VirtoCommerce.Platform.Core.Jobs;
using VirtoCommerce.Platform.Core.Settings;
using VirtoCommerce.SearchModule.Core.BackgroundJobs;
using VirtoCommerce.SearchModule.Core.Extensions;
using VirtoCommerce.SearchModule.Core.Model;
using static VirtoCommerce.OrdersModule.Core.ModuleConstants.Settings.General;

namespace VirtoCommerce.OrdersModule.Data.Handlers
{
public class IndexPurchasedProductsCustomerOrderChangedEventHandler : IEventHandler<OrderChangedEvent>
{
private readonly ISettingsManager _settingsManager;
private readonly IIndexingJobService _indexingJobService;
private readonly IEnumerable<IndexDocumentConfiguration> _indexingConfigurations;

public IndexPurchasedProductsCustomerOrderChangedEventHandler(
ISettingsManager settingsManager,
IIndexingJobService indexingJobService,
IEnumerable<IndexDocumentConfiguration> indexingConfigurations)
{
_settingsManager = settingsManager;
_indexingJobService = indexingJobService;
_indexingConfigurations = indexingConfigurations;
}

public async Task Handle(OrderChangedEvent message)
{
if (!await _settingsManager.GetValueAsync<bool>(EventBasedPurchasedProductIndexation) &&
!await _settingsManager.GetValueAsync<bool>(PurchasedProductIndexation))
{
return;
}

HashSet<string> productIds = [];
foreach (var changedEntry in message.ChangedEntries.Where(x => x.NewEntry != null))
{
foreach (var productId in changedEntry.NewEntry.Items.Select(x => x.ProductId))
{
productIds.Add(productId);
}
}

var indexEntries = productIds
.Select(x => new IndexEntry { Id = x, EntryState = EntryState.Modified, Type = KnownDocumentTypes.Product })
.ToArray();

_indexingJobService.EnqueueIndexAndDeleteDocuments(indexEntries, JobPriority.Normal,
_indexingConfigurations.GetDocumentBuilders(KnownDocumentTypes.Product, typeof(PurchasedProductsChangesProvider)).ToList());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Linq;
using System.Threading.Tasks;
using VirtoCommerce.OrdersModule.Data.Search.Indexed;
using VirtoCommerce.Platform.Core.Common;
using VirtoCommerce.Platform.Core.Events;
using VirtoCommerce.Platform.Core.Settings.Events;
using static VirtoCommerce.OrdersModule.Core.ModuleConstants.Settings.General;

namespace VirtoCommerce.OrdersModule.Data.Handlers
{
public class PurchasedProductIndexationSettingChangedEventHandler : IEventHandler<ObjectSettingChangedEvent>
{
private readonly PurchasedProductsIndexConfigurator _configurator;

public PurchasedProductIndexationSettingChangedEventHandler(PurchasedProductsIndexConfigurator configurator)
{
_configurator = configurator;
}

public virtual async Task Handle(ObjectSettingChangedEvent message)
{
if (message.ChangedEntries.Any(x => (x.EntryState == EntryState.Modified || x.EntryState == EntryState.Added) &&
x.NewEntry.Name == PurchasedProductIndexation.Name))
{
await _configurator.Configure();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VirtoCommerce.OrdersModule.Core.Model;
using VirtoCommerce.OrdersModule.Core.Services;
using VirtoCommerce.Platform.Core.ChangeLog;
using VirtoCommerce.SearchModule.Core.Model;
using VirtoCommerce.SearchModule.Core.Services;

namespace VirtoCommerce.OrdersModule.Data.Search.Indexed;
public class PurchasedProductsChangesProvider : IIndexDocumentChangesProvider
{
public const string ChangeLogObjectType = nameof(CustomerOrder);

private readonly ICustomerOrderService _customerOrderService;
private readonly IChangeLogSearchService _changeLogSearchService;

public PurchasedProductsChangesProvider(
ICustomerOrderService customerOrderService,
IChangeLogSearchService changeLogSearchService)
{
_customerOrderService = customerOrderService;
_changeLogSearchService = changeLogSearchService;
}

public async Task<IList<IndexDocumentChange>> GetChangesAsync(DateTime? startDate, DateTime? endDate, long skip, long take)
{
var criteria = new ChangeLogSearchCriteria
{
ObjectType = ChangeLogObjectType,
StartDate = startDate,
EndDate = endDate,
Skip = (int)skip,
Take = (int)take
};

// Get changes from operation log
var operations = (await _changeLogSearchService.SearchAsync(criteria)).Results;
var orders = await _customerOrderService.GetAsync(operations.Select(x => x.ObjectId).Distinct().ToArray(), CustomerOrderResponseGroup.WithItems.ToString());
var productIds = orders.SelectMany(x => x.Items).Select(x => x.ProductId).Distinct().ToArray();

var results = productIds.Select(x => new IndexDocumentChange
{
DocumentId = x,
ChangeType = IndexDocumentChangeType.Modified, // dunno how to correctly get Deleted
}).ToList();

return results;
}

public async Task<long> GetTotalChangesCountAsync(DateTime? startDate, DateTime? endDate)
{
var criteria = new ChangeLogSearchCriteria
{
ObjectType = ChangeLogObjectType,
StartDate = startDate,
EndDate = endDate,
Take = 0
};

// Get changes count from operation log
return (await _changeLogSearchService.SearchAsync(criteria)).TotalCount;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VirtoCommerce.OrdersModule.Core.Model;
using VirtoCommerce.OrdersModule.Core.Services;
using VirtoCommerce.Platform.Core.Settings;
using VirtoCommerce.SearchModule.Core.Extensions;
using VirtoCommerce.SearchModule.Core.Model;
using VirtoCommerce.SearchModule.Core.Services;
using static VirtoCommerce.OrdersModule.Core.ModuleConstants;

namespace VirtoCommerce.OrdersModule.Data.Search.Indexed;
public class PurchasedProductsDocumentBuilder : IIndexDocumentBuilder
{
private readonly IPurchasedProductsService _purchasedProductsService;

public PurchasedProductsDocumentBuilder(
IPurchasedProductsService purchasedBeforeService,
ISettingsManager settingsManager)
{
_purchasedProductsService = purchasedBeforeService;
}

public async Task<IList<IndexDocument>> GetDocumentsAsync(IList<string> documentIds)
{
var request = new PurchasedProductsGroupedRequest
{
ProductIds = documentIds,
};

var products = await _purchasedProductsService.GetGroupedPurchasedProductsAsync(request);

var result = products
.Select(g => CreateDocument(g.Key, g.Value))
.ToArray();

return result;
}

private static IndexDocument CreateDocument(string productId, IEnumerable<PurchasedProduct> purchasedProducts)
{
var document = new IndexDocument(productId);

foreach (var storeGroup in purchasedProducts.GroupBy(x => x.StoreId))
{
var users = storeGroup.Select(x => x.UserId).ToArray();

document.AddFilterableCollection($"{PurchasedProductDocumentPrefix}_{storeGroup.Key}", users);
}

return document;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VirtoCommerce.Platform.Core.Settings;
using VirtoCommerce.SearchModule.Core.Model;

namespace VirtoCommerce.OrdersModule.Data.Search.Indexed;

public class PurchasedProductsIndexConfigurator
{
private readonly ISettingsManager _settingsManager;
private readonly IEnumerable<IndexDocumentConfiguration> _indexDocumentConfigurations;
private readonly PurchasedProductsChangesProvider _purchasedProductsChangesProvider;
private readonly PurchasedProductsDocumentBuilder _purchasedProductsDocumentBuilder;

public PurchasedProductsIndexConfigurator(
ISettingsManager settingsManager,
IEnumerable<IndexDocumentConfiguration> indexDocumentConfigurations,
PurchasedProductsChangesProvider purchasedProductsChangesProvider,
PurchasedProductsDocumentBuilder purchasedProductsDocumentBuilder)
{
_settingsManager = settingsManager;
_indexDocumentConfigurations = indexDocumentConfigurations;
_purchasedProductsChangesProvider = purchasedProductsChangesProvider;
_purchasedProductsDocumentBuilder = purchasedProductsDocumentBuilder;
}

public async Task Configure()
{
var productIndexingConfigurations = _indexDocumentConfigurations
.Where(x => x.DocumentType == KnownDocumentTypes.Product)
.ToList();

if (productIndexingConfigurations.Count != 0)
{
var source = new IndexDocumentSource
{
ChangesProvider = _purchasedProductsChangesProvider,
DocumentBuilder = _purchasedProductsDocumentBuilder,
};

foreach (var configuration in productIndexingConfigurations)
{
var puchasedProductsIndexationEnabled = await _settingsManager.GetValueAsync<bool>(Core.ModuleConstants.Settings.General.PurchasedProductIndexation);

var existingSource = configuration.RelatedSources.FirstOrDefault(x => x.ChangesProvider is PurchasedProductsChangesProvider
&& x.DocumentBuilder is PurchasedProductsDocumentBuilder);

if (existingSource != null)
{
configuration.RelatedSources?.Remove(existingSource);
}

if (puchasedProductsIndexationEnabled)
{
configuration.RelatedSources ??= new List<IndexDocumentSource>();
configuration.RelatedSources.Add(source);
}
}
}
}
}
Loading
Loading