Get Settings by Vendor in Multi-Vendor nopCommerce Store

Setup for Multi-Vendor nopCommerce Store

First of all, In this article, I will show you how to get and set settings like a tax, shipping settings for each vendor. which means you should be able to store all settings for multiple vendors in nopCommerce admin. as well you should be able to retrieve each setting on nopCommerce Front-end as per your need.

nopCommerce is an open source eCommerce solution for the shopping cart that built in the ASP.NET MVC based with MS SQL Server 2008 as a backend database. In nopCommerce by default, it doesn’t give the functionality of vendor settings to be managed by multi-vendor himself. so on, and only admin has all the control over all the nopCommerce settings and configurations. For the multi-vendor, We required adding custom nopCommerce setting of the tax, shipping, country & another field for the multi vendors to give the ability to set up setting by merchant himself.

Contact Us

Do You Need Multi-Vendor Store Demo?

Ask for the multi-vendor store in NopCommerce. Fill the form and we will be back to you as soon as possible.

Your Content Goes Here

Contact Us

Problem with nopCommerce Multi-Vendor setting

If you or your client doing business over the multiple country or state with multiple vendors, then there may be changes that the shipping and tax or some other things will change as geographically. In this case, it’s very hard for the admin to understand and handle all those settings and configuration properly.
Nopcommerce doesn’t provide default multi-vendor setting up kind of functionality where you can give additional settings to be managed by a vendor. Now, what if you or your client want such functionality in your current asp.net MVC project?

I am working on one multi-vendor project in nopCommerce multi-store scenario. Our client wants to give an ability to a merchant to set up tax field by merchant themselves. But it is not provided by nopCommerce built in functionality.
So we have to find out the solution to add a custom field for tax setting for the vendor in the nopCommerce. Another setting like country, shipping for the vendor, you can do by adding a custom field for this setting as well on your nopCommerce theme.

Solution for Multi-Vendor nopCommerce setup

Here I have some solutions for this, I am going to give an example of Tax Settings to be a by a vendor.

Please refer below links for tax settings

http://docs.nopcommerce.com/display/nc/Tax+Settings
http://admin-demo.nopcommerce.com/Admin/Setting/Tax

Step 1:  you need to do to give permission to a vendor from Access control list using the following link.

http://admin-demo.nopcommerce.com/Admin/Security/Permissions

Step 2: add column “VendorId” in Setting Table using following SQL query.

ALTER TABLE [dbo].[Setting] ADD VendorId INT

Step 3: Open Nop.Service and find SettingService class.
Give the ability to merchant /vendor to set up tax by himself using following method.
In the NopService.SettingService Class, Replace the method using following code.

To give access of Tax Settings to your vendor.

Add column “VendorId” in settings Table.
Update or add following the method in NopService.SettingService Class.

C# code for setup Multi-Vendor nopCommerce Store

#region GetSetting
public virtual Setting GetSetting(string key, int storeId = 0, bool loadSharedValueIfNotFound = false)
{
return this.GetSettingByVendor(key, storeId, loadSharedValueIfNotFound, 0);
}
public virtual Setting GetSettingByVendor(string key, int storeId = 0, bool loadSharedValueIfNotFound = false, int vendorId = 0)
{
if (String.IsNullOrEmpty(key))
return null;

var settings = GetAllSettingsCached(vendorId); key = key.Trim().ToLowerInvariant(); if (settings.ContainsKey(key)) { var settingsByKey = settings[key]; var setting = settingsByKey.FirstOrDefault(x => x.StoreId == storeId && x.VendorId == vendorId);

//load shared value? if (setting == null && storeId > 0 && loadSharedValueIfNotFound) setting = settingsByKey.FirstOrDefault(x => x.StoreId == 0);

if (setting != null) return GetSettingById(setting.Id); }

return null; } #endregion

#region GetSettingByKey public virtual T GetSettingByKey<T>(string key, T defaultValue = default(T), int storeId = 0, bool loadSharedValueIfNotFound = false) { return this.GetSettingByKeyByVendor<T>(key, defaultValue, storeId, loadSharedValueIfNotFound, 0); } public virtual T GetSettingByKeyByVendor<T>(string key, T defaultValue = default(T), int storeId = 0, bool loadSharedValueIfNotFound = false, int vendorId = 0) { if (String.IsNullOrEmpty(key)) return defaultValue;

var settings = GetAllSettingsCached(vendorId); key = key.Trim().ToLowerInvariant(); if (settings.ContainsKey(key)) { var settingsByKey = settings[key]; var setting = settingsByKey.FirstOrDefault(x => x.StoreId == storeId && x.VendorId == vendorId);

//load shared value? if (setting == null && storeId > 0 && loadSharedValueIfNotFound) setting = settingsByKey.FirstOrDefault(x => x.StoreId == 0);

if (setting != null) return CommonHelper.To<T>(setting.Value); }

return defaultValue; } #endregion

#region SetSetting public virtual void SetSetting<T>(string key, T value, int storeId = 0, bool clearCache = true) { this.SetSettingByVendor<T>(key, value, storeId, clearCache, 0); } public virtual void SetSettingByVendor<T>(string key, T value, int storeId = 0, bool clearCache = true, int vendorId = 0) { if (key == null) throw new ArgumentNullException("key"); key = key.Trim().ToLowerInvariant(); string valueStr = CommonHelper.GetNopCustomTypeConverter(typeof(T)).ConvertToInvariantString(value);

var allSettings = GetAllSettingsCached(vendorId); var settingForCaching = allSettings.ContainsKey(key) ? allSettings[key].FirstOrDefault(x => x.StoreId == storeId && x.VendorId == vendorId) : null; if (settingForCaching != null) { //update var setting = GetSettingById(settingForCaching.Id); setting.Value = valueStr; UpdateSetting(setting, clearCache); } else { //insert var setting = new Setting { Name = key, Value = valueStr, StoreId = storeId, VendorId = vendorId }; InsertSetting(setting, clearCache); } } #endregion

#region SettingExists public virtual bool SettingExists<T, TPropType>(T settings, Expression<Func<T, TPropType>> keySelector, int storeId = 0) where T : ISettings, new() { return this.SettingExistsByVendor<T, TPropType>(settings, keySelector, storeId, 0); } public virtual bool SettingExistsByVendor<T, TPropType>(T settings, Expression<Func<T, TPropType>> keySelector, int storeId = 0, int vendorId = 0) where T : ISettings, new() { string key = settings.GetSettingKey(keySelector);

var setting = GetSettingByKeyByVendor<string>(key, storeId: storeId, loadSharedValueIfNotFound: false, vendorId: vendorId); return setting != null; } #endregion #region LoadSetting public virtual T LoadSetting<T>(int storeId = 0) where T : ISettings, new() { return this.LoadSettingByVendor<T>(storeId, 0); ; } public virtual T LoadSettingByVendor<T>(int storeId = 0, int vendorId = 0) where T : ISettings, new() { var settings = Activator.CreateInstance<T>();

foreach (var prop in typeof(T).GetProperties()) { // get properties we can read and write to if (!prop.CanRead

!prop.CanWrite) continue;

var key = typeof(T).Name + "." + prop.Name; //load by store var setting = GetSettingByKeyByVendor<string>(key, storeId: storeId, loadSharedValueIfNotFound: true, vendorId: vendorId); if (setting == null) continue;

if (!CommonHelper.GetNopCustomTypeConverter(prop.PropertyType).CanConvertFrom(typeof(string))) continue;

if (!CommonHelper.GetNopCustomTypeConverter(prop.PropertyType).IsValid(setting)) continue;

object value = CommonHelper.GetNopCustomTypeConverter(prop.PropertyType).ConvertFromInvariantString(setting);

//set property prop.SetValue(settings, value, null); }

return settings; } #endregion

#region SaveSetting public virtual void SaveSetting<T>(T settings, int storeId = 0) where T : ISettings, new() { this.SaveSettingByVendor<T>(settings, storeId, 0); } public virtual void SaveSettingByVendor<T>(T settings, int storeId = 0, int vendorId = 0) where T : ISettings, new() { /* We do not clear cache after each setting update. * This behavior can increase performance because cached settings will not be cleared * and loaded from database after each update */ foreach (var prop in typeof(T).GetProperties()) { // get properties we can read and write to if (!prop.CanRead

!prop.CanWrite) continue;

if (!CommonHelper.GetNopCustomTypeConverter(prop.PropertyType).CanConvertFrom(typeof(string))) continue;

string key = typeof(T).Name + "." + prop.Name; //Duck typing is not supported in C#. That’s why we’re using dynamic type dynamic value = prop.GetValue(settings, null); if (value != null) SetSettingByVendor(key, value, storeId, false, vendorId); else SetSettingByVendor(key, "", storeId, false, vendorId); }

//and now clear cache ClearCache(); } #endregion #region SaveSetting public virtual void SaveSetting<T, TPropType>(T settings, Expression<Func<T, TPropType>> keySelector, int storeId = 0, bool clearCache = true) where T : ISettings, new() { this.SaveSettingByVendor<T, TPropType>(settings, keySelector, storeId, clearCache, 0); } public virtual void SaveSettingByVendor<T, TPropType>(T settings, Expression<Func<T, TPropType>> keySelector, int storeId = 0, bool clearCache = true, int vendorId = 0) where T : ISettings, new() { var member = keySelector.Body as MemberExpression; if (member == null) { throw new ArgumentException(string.Format( "Expression ‘{0}’ refers to a method, not a property.", keySelector)); }

var propInfo = member.Member as PropertyInfo; if (propInfo == null) { throw new ArgumentException(string.Format( "Expression ‘{0}’ refers to a field, not a property.", keySelector)); }

string key = settings.GetSettingKey(keySelector); //Duck typing is not supported in C#. That’s why we’re using dynamic type dynamic value = propInfo.GetValue(settings, null); if (value != null) SetSettingByVendor(key, value, storeId, clearCache, vendorId); else SetSettingByVendor(key, "", storeId, clearCache, vendorId); } #endregion #region DeleteSetting public virtual void DeleteSetting<T, TPropType>(T settings, Expression<Func<T, TPropType>> keySelector, int storeId = 0) where T : ISettings, new() { this.DeleteSettingByVendor<T, TPropType>(settings, keySelector, storeId, 0); } public virtual void DeleteSettingByVendor<T, TPropType>(T settings, Expression<Func<T, TPropType>> keySelector, int storeId = 0, int vendorId = 0) where T : ISettings, new() { string key = settings.GetSettingKey(keySelector); key = key.Trim().ToLowerInvariant();

var allSettings = GetAllSettingsCached(vendorId); var settingForCaching = allSettings.ContainsKey(key) ? allSettings[key].FirstOrDefault(x => x.StoreId == storeId && x.VendorId == vendorId) : null; if (settingForCaching != null) { //update var setting = GetSettingById(settingForCaching.Id); DeleteSetting(setting); } } #endregion

What above c# code does :
It add one additional method with postfix “ByVendor” and one additional parameter int vendorId = 0.
Ex. the original method is SaveSetting and new method is SaveSettingByVendor.

Now all the code of the original method is copied to new method and one addition filter in where a query is added like x.VendorId == vendorId.

Now next and lastly you just need to update your controller with the additional parameter of vendorId as below.


var taxSettings = _settingService.LoadSettingByVendor<TaxSettings>(storeScope, VendorId);

Conclusion:

This is the easiest way to give settings to the vendor and other settings will not affect the default functionality of nopCommerce.
In that way, We can customize nopCommerce method for the vendor and we can add tax setting,shipping setting, country setting etc. field for the vendor to give the ability to set up by a vendor.

Note
You have to add vendorId field in your model, mapping and validation class as per your requirement.
This example is based on nopcommerce version 3.6. There may be change in some syntax if using different version.

See More

Are Your Want to Develop Multi-Vendor nopCommerce Store?

We are at Satva Solution, providing total solution for multi-vendor nopCommerce store development services.
See More
By | 2017-09-14T13:02:58+00:00 October 3rd, 2016|E-Commerce, nopCommerce, nopCommerce Plugins Development|