Skip to content

Commit

Permalink
Resolves #896 Add a cart rule for affiliates
Browse files Browse the repository at this point in the history
Added a button to remove the assignment of a customer to an affiliate on customer edit page.
  • Loading branch information
mgesing committed Nov 22, 2023
1 parent 6b89f66 commit 1ac1f03
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 39 deletions.
@@ -0,0 +1,51 @@
using Smartstore.Core.Data;
using Smartstore.Core.Rules;
using Smartstore.Core.Rules.Rendering;

namespace Smartstore.Core.Checkout.Affiliates.Rules
{
public partial class AffiliateRuleOptionsProvider : IRuleOptionsProvider
{
private readonly SmartDbContext _db;

public AffiliateRuleOptionsProvider(SmartDbContext db)
{
_db = db;
}

public int Order => 0;

public bool Matches(string dataSource)
{
return dataSource == KnownRuleOptionDataSourceNames.Affiliate;
}

public async Task<RuleOptionsResult> GetOptionsAsync(RuleOptionsContext context)
{
if (context.DataSource != KnownRuleOptionDataSourceNames.Affiliate)
{
return null;
}

var result = new RuleOptionsResult();

var pager = _db.Affiliates
.AsNoTracking()
.Include(x => x.Address)
.Where(x => x.Active)
.ToFastPager();

while ((await pager.ReadNextPageAsync<Affiliate>()).Out(out var affiliates))
{
result.AddOptions(context, affiliates.Select(x => new RuleValueSelectListOption
{
Value = x.Id.ToString(),
Text = x.Address?.GetFullName()?.NullEmpty() ?? StringExtensions.NotAvailable,
Hint = x.Address?.Email
}));
}

return result;
}
}
}
2 changes: 2 additions & 0 deletions src/Smartstore.Core/Checkout/Bootstrapping/CheckoutStarter.cs
@@ -1,4 +1,5 @@
using Autofac;
using Smartstore.Core.Checkout.Affiliates.Rules;
using Smartstore.Core.Checkout.Attributes;
using Smartstore.Core.Checkout.Cart;
using Smartstore.Core.Checkout.GiftCards;
Expand Down Expand Up @@ -69,6 +70,7 @@ public override void ConfigureContainer(ContainerBuilder builder, IApplicationCo
builder.RegisterType<PaymentMethodRuleOptionsProvider>().As<IRuleOptionsProvider>().InstancePerLifetimeScope();
builder.RegisterType<ShippingRateComputationMethodRuleOptionsProvider>().As<IRuleOptionsProvider>().InstancePerLifetimeScope();
builder.RegisterType<ShippingMethodRuleOptionsProvider>().As<IRuleOptionsProvider>().InstancePerLifetimeScope();
builder.RegisterType<AffiliateRuleOptionsProvider>().As<IRuleOptionsProvider>().InstancePerLifetimeScope();
}
}
}
72 changes: 40 additions & 32 deletions src/Smartstore.Core/Checkout/Rules/CartRuleProvider.cs
Expand Up @@ -236,39 +236,39 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()

var descriptors = new List<CartRuleDescriptor>
{
new CartRuleDescriptor
new()
{
Name = "Currency",
DisplayName = T("Admin.Rules.FilterDescriptor.Currency"),
RuleType = RuleType.IntArray,
ProcessorType = typeof(CurrencyRule),
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Currency) { Multiple = true }
},
new CartRuleDescriptor
new()
{
Name = "Language",
DisplayName = T("Admin.Rules.FilterDescriptor.Language"),
RuleType = RuleType.IntArray,
ProcessorType = typeof(LanguageRule),
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Language) { Multiple = true }
},
new CartRuleDescriptor
new()
{
Name = "Store",
DisplayName = T("Admin.Rules.FilterDescriptor.Store"),
RuleType = RuleType.IntArray,
ProcessorType = typeof(StoreRule),
SelectList = new LocalRuleValueSelectList(stores) { Multiple = true }
},
new CartRuleDescriptor
new()
{
Name = "IPCountry",
DisplayName = T("Admin.Rules.FilterDescriptor.IPCountry"),
RuleType = RuleType.StringArray,
ProcessorType = typeof(IPCountryRule),
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Country) { Multiple = true }
},
new CartRuleDescriptor
new()
{
Name = "Weekday",
DisplayName = T("Admin.Rules.FilterDescriptor.Weekday"),
Expand All @@ -277,7 +277,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new LocalRuleValueSelectList(WeekdayRule.GetDefaultValues(language)) { Multiple = true }
},

new CartRuleDescriptor
new()
{
Name = "CustomerRole",
DisplayName = T("Admin.Rules.FilterDescriptor.IsInCustomerRole"),
Expand All @@ -286,31 +286,39 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.CustomerRole) { Multiple = true },
IsComparingSequences = true
},
new CartRuleDescriptor
new()
{
Name = "Affiliate",
DisplayName = T("Admin.Rules.FilterDescriptor.Affiliate"),
RuleType = RuleType.IntArray,
ProcessorType = typeof(CustomerAffiliateRule),
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Affiliate) { Multiple = true }
},
new()
{
Name = "CartBillingCountry",
DisplayName = T("Admin.Rules.FilterDescriptor.BillingCountry"),
RuleType = RuleType.IntArray,
ProcessorType = typeof(BillingCountryRule),
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Country) { Multiple = true }
},
new CartRuleDescriptor
new()
{
Name = "CartShippingCountry",
DisplayName = T("Admin.Rules.FilterDescriptor.ShippingCountry"),
RuleType = RuleType.IntArray,
ProcessorType = typeof(ShippingCountryRule),
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Country) { Multiple = true }
},
new CartRuleDescriptor
new()
{
Name = "CartShippingMethod",
DisplayName = T("Admin.Rules.FilterDescriptor.ShippingMethod"),
RuleType = RuleType.IntArray,
ProcessorType = typeof(ShippingMethodRule),
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.ShippingMethod) { Multiple = true }
},
new CartRuleDescriptor
new()
{
Name = "CartPaymentMethod",
DisplayName = T("Admin.Rules.FilterDescriptor.PaymentMethod"),
Expand All @@ -319,21 +327,21 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.PaymentMethod) { Multiple = true }
},

new CartRuleDescriptor
new()
{
Name = "CartTotal",
DisplayName = T("Admin.Rules.FilterDescriptor.CartTotal"),
RuleType = RuleType.Money,
ProcessorType = typeof(CartTotalRule)
},
new CartRuleDescriptor
new()
{
Name = "CartSubtotal",
DisplayName = T("Admin.Rules.FilterDescriptor.CartSubtotal"),
RuleType = RuleType.Money,
ProcessorType = typeof(CartSubtotalRule)
},
new CartRuleDescriptor
new()
{
Name = "CartProductCount",
DisplayName = T("Admin.Rules.FilterDescriptor.CartProductCount"),
Expand All @@ -342,7 +350,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
},
cartItemQuantity,
cartItemFromCategoryQuantity,
new CartRuleDescriptor
new()
{
Name = "ProductInCart",
DisplayName = T("Admin.Rules.FilterDescriptor.ProductInCart"),
Expand All @@ -351,7 +359,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Product) { Multiple = true },
IsComparingSequences = true
},
new CartRuleDescriptor
new()
{
Name = "ProductFromCategoryInCart",
DisplayName = T("Admin.Rules.FilterDescriptor.ProductFromCategoryInCart"),
Expand All @@ -360,7 +368,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Category) { Multiple = true },
IsComparingSequences = true
},
new CartRuleDescriptor
new()
{
Name = "ProductFromManufacturerInCart",
DisplayName = T("Admin.Rules.FilterDescriptor.ProductFromManufacturerInCart"),
Expand All @@ -369,7 +377,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Manufacturer) { Multiple = true },
IsComparingSequences = true
},
new CartRuleDescriptor
new()
{
Name = "ProductWithDeliveryTimeInCart",
DisplayName = T("Admin.Rules.FilterDescriptor.ProductWithDeliveryTimeInCart"),
Expand All @@ -378,7 +386,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.DeliveryTime) { Multiple = true },
IsComparingSequences = true
},
new CartRuleDescriptor
new()
{
Name = "ProductInWishlist",
DisplayName = T("Admin.Rules.FilterDescriptor.ProductOnWishlist"),
Expand All @@ -387,21 +395,21 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Product) { Multiple = true },
IsComparingSequences = true
},
new CartRuleDescriptor
new()
{
Name = "ProductReviewCount",
DisplayName = T("Admin.Rules.FilterDescriptor.ProductReviewCount"),
RuleType = RuleType.Int,
ProcessorType = typeof(ProductReviewCountRule)
},
new CartRuleDescriptor
new()
{
Name = "RewardPointsBalance",
DisplayName = T("Admin.Rules.FilterDescriptor.RewardPointsBalance"),
RuleType = RuleType.Int,
ProcessorType = typeof(RewardPointsBalanceRule)
},
new CartRuleDescriptor
new()
{
Name = "RuleSet",
DisplayName = T("Admin.Rules.FilterDescriptor.RuleSet"),
Expand All @@ -411,23 +419,23 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.CartRule),
},

new CartRuleDescriptor
new()
{
Name = "CartOrderCount",
DisplayName = T("Admin.Rules.FilterDescriptor.OrderCount"),
GroupKey = "Admin.Orders",
RuleType = RuleType.Int,
ProcessorType = typeof(OrderCountRule)
},
new CartRuleDescriptor
new()
{
Name = "CartSpentAmount",
DisplayName = T("Admin.Rules.FilterDescriptor.SpentAmount"),
GroupKey = "Admin.Orders",
RuleType = RuleType.Money,
ProcessorType = typeof(SpentAmountRule)
},
new CartRuleDescriptor
new()
{
Name = "CartPaidBy",
DisplayName = T("Admin.Rules.FilterDescriptor.PaidBy"),
Expand All @@ -437,7 +445,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.PaymentMethod) { Multiple = true },
IsComparingSequences = true
},
new CartRuleDescriptor
new()
{
Name = "CartPurchasedProduct",
DisplayName = T("Admin.Rules.FilterDescriptor.PurchasedProduct"),
Expand All @@ -447,7 +455,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
SelectList = new RemoteRuleValueSelectList(KnownRuleOptionDataSourceNames.Product) { Multiple = true },
IsComparingSequences = true
},
new CartRuleDescriptor
new()
{
Name = "CartPurchasedFromManufacturer",
DisplayName = T("Admin.Rules.FilterDescriptor.PurchasedFromManufacturer"),
Expand All @@ -458,15 +466,15 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
IsComparingSequences = true
},

new CartRuleDescriptor
new()
{
Name = "UserAgent.IsMobile",
DisplayName = T("Admin.Rules.FilterDescriptor.MobileDevice"),
GroupKey = "Admin.Rules.FilterDescriptor.Group.BrowserUserAgent",
RuleType = RuleType.Boolean,
ProcessorType = typeof(IsMobileRule)
},
new CartRuleDescriptor
new()
{
Name = "UserAgent.Device",
DisplayName = T("Admin.Rules.FilterDescriptor.DeviceFamily"),
Expand All @@ -475,7 +483,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
ProcessorType = typeof(DeviceRule),
SelectList = new LocalRuleValueSelectList(DeviceRule.GetDefaultOptions()) { Multiple = true, Tags = true }
},
new CartRuleDescriptor
new()
{
Name = "UserAgent.OS",
DisplayName = T("Admin.Rules.FilterDescriptor.OperatingSystem"),
Expand All @@ -484,7 +492,7 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
ProcessorType = typeof(OSRule),
SelectList = new LocalRuleValueSelectList(OSRule.GetDefaultOptions()) { Multiple = true, Tags = true }
},
new CartRuleDescriptor
new()
{
Name = "UserAgent.Browser",
DisplayName = T("Admin.Rules.FilterDescriptor.BrowserName"),
Expand All @@ -493,15 +501,15 @@ protected override Task<IEnumerable<RuleDescriptor>> LoadDescriptorsAsync()
ProcessorType = typeof(BrowserRule),
SelectList = new LocalRuleValueSelectList(BrowserRule.GetDefaultOptions()) { Multiple = true, Tags = true }
},
new CartRuleDescriptor
new()
{
Name = "UserAgent.BrowserMajorVersion",
DisplayName = T("Admin.Rules.FilterDescriptor.BrowserMajorVersion"),
GroupKey = "Admin.Rules.FilterDescriptor.Group.BrowserUserAgent",
RuleType = RuleType.Int,
ProcessorType = typeof(BrowserMajorVersionRule)
},
new CartRuleDescriptor
new()
{
Name = "UserAgent.BrowserMinorVersion",
DisplayName = T("Admin.Rules.FilterDescriptor.BrowserMinorVersion"),
Expand Down
27 changes: 27 additions & 0 deletions src/Smartstore.Core/Checkout/Rules/Impl/CustomerAffiliateRule.cs
@@ -0,0 +1,27 @@
using Smartstore.Core.Data;
using Smartstore.Core.Rules;

namespace Smartstore.Core.Checkout.Rules.Impl
{
internal class CustomerAffiliateRule : IRule
{
private readonly SmartDbContext _db;

public CustomerAffiliateRule(SmartDbContext db)
{
_db = db;
}

public async Task<bool> MatchAsync(CartRuleContext context, RuleExpression expression)
{
var customer = context.Customer;
if (customer != null && !customer.IsSystemAccount && customer.AffiliateId != 0 && expression.HasListMatch(customer.AffiliateId))
{
var isValidAffiliate = await _db.Affiliates.AnyAsync(x => x.Id == customer.AffiliateId && !x.Deleted && x.Active);
return isValidAffiliate;
}

return false;
}
}
}
5 changes: 5 additions & 0 deletions src/Smartstore.Core/Migrations/SmartDbContextDataSeeder.cs
Expand Up @@ -22,6 +22,11 @@ public void MigrateLocaleResources(LocaleResourcesBuilder builder)
builder.Delete("Account.ChangePassword.Errors.PasswordIsNotProvided");

builder.AddOrUpdate("Admin.Report.MediaFilesSize", "Media size", "Mediengröße");
builder.AddOrUpdate("Admin.Rules.FilterDescriptor.Affiliate", "Affiliate", "Partner");

builder.AddOrUpdate("Admin.Customers.RemoveAffiliateAssignment",
"Remove assignment to affiliate",
"Zuordnung zum Partner entfernen");
}
}
}

0 comments on commit 1ac1f03

Please sign in to comment.