After two years using Nop, Im finally able to give something back to the community. This should definitely be on the next version. Also, I would like to point that I was able to this in the previous 2.5 version, but back then, I had no experience with MVC Razor or the application itself. I ended up making it work but I changed a TON of files and it was going to be a pain in the ass for others trying to implement it. Also, I could't upgrade because It will break my current customizations, so I finally decided to give it another try with 3.2 version. Well, this time, now with more experience I was able to do it with minor changes, only 4 files and much less code, and I accomplished the same result in a more elegant way. Without further a due, lets begin.
THE PROBLEM
Well, we all love the Attribute Values/Combinations in the system to keep track of Stock for each Product Variant Combination. This works great but the problem is that when the customer selects an item from the dropdown list that is out of stock, he gets the "out of stock" message after clicking on BUY NOW button. Not very elegant right? Imagine having 20 combinations and you only have 5 combinations in stock. The customer could get pissed off and think that you have NOTHING in your store at all.
Let's take the classic T-Shirt example for instance. We have in stock as follows (Color : Size : StockQuantity)
Black : S : 10
Black : M : 0
Black : L : 15
White : S : 3
White : M : 10
White : L : 12
In the product page, we are going to see TWO dropdownlist's. One for Color and other for Size. Correct?
Wouldn't be nice that if the current selection is 'Black', on the Size dropdown, the options will be as follows:
S
M (out of stock) <--- This option gets DISABLED
L
Then, if the customer selects 'White', the size dropdown will auto-populate with:
S (only 3 left) <--- Amazon style
M
L
Well, this is exactly what I did. Wanna know how? Don't worry, it's easy. Let me show you how.
STEP 1. Database changes
We have to Add a boolean column to ProductVariantAttributeValue table. Execute this code:
ALTER TABLE ProductVariantAttributeValue
ADD IsMasterAttribute bit
GO
UPDATE ProductVariantAttributeValue --Set all records to 0
SET IsMasterAttribute=0
GO
This is the flag to tell us that the current Attribute is a Master (I couldn't think of a better name, sorry).
In our example, T-Shirt COLOR will be our master attributes. So, you will have to manually set as 1 the values Attributes of Black and White like this:
UPDATE ProductVariantAttributeValue
SET IsMasterAttribute=1
where id in (829,835)
GO
Ok great, this is all thats needed for db changes.
STEP 2.
Add
public bool IsMasterAttribute { get; set; } //VAS
to ProductVariantAttributevalue.cs in Core\Domain\Catalog
STEP 3.
Modify Nop.Web\Models\Catalog\ProductDetailsModel.cs and add this to the ProductVariantAttributeValueModel class
public bool IsMasterAttribute { get; set; } //VAS
public string AffectsObjectId { get; set; } //VAS
public string CurrentObjectId { get; set; } //VAS
public List<RenderCombinationModel> RenderCombinations { get; set; } //VAS
public int GetStockQuantityById(int CombinationValue, List<RenderCombinationModel> Combinations)//VAS
{
foreach (RenderCombinationModel combination in Combinations)
if (combination.Value == CombinationValue)
return combination.Quantity;
return 0; //this will happen when the are no combinations added to the variant
}
Also, add a new class below to the same file.
public partial class RenderCombinationModel : BaseNopEntityModel //VAS
{
public string Name { get; set; }
public int Value { get; set; }
public int Quantity { get; set; }
public RenderCombinationModel(string Name, int Value, int Quantity)
{
this.Name = Name;
this.Value = Value;
this.Quantity = Quantity;
}
}
STEP 4.
Modify Nop.Web\Controllers\CatalogController.cs
In the PrepareProductDetailsPageModel method, add this code: (Line 871)
var pvaValueModel = new ProductDetailsModel.ProductVariantAttributeValueModel()
{
Id = pvaValue.Id,
Name = pvaValue.GetLocalized(x => x.Name),
ColorSquaresRgb = pvaValue.ColorSquaresRgb, //used with "Color squares" attribute type
IsPreSelected = pvaValue.IsPreSelected,
IsMasterAttribute = pvaValue.IsMasterAttribute
};
if (pvaValueModel.IsMasterAttribute)
{
pvaValueModel.RenderCombinations = new List<ProductDetailsModel.RenderCombinationModel>();
IList<ProductVariantAttributeCombination> combinations = _productAttributeService.GetAllProductVariantAttributeCombinations(pvaModel.ProductId);
foreach(ProductVariantAttributeCombination comb in combinations)
{
IList<ProductVariantAttributeValue> values = _productAttributeParser.ParseProductVariantAttributeValues(comb.AttributesXml);
if (values[0].Id == pvaValueModel.Id)
{
pvaValueModel.RenderCombinations.Add(new ProductDetailsModel.RenderCombinationModel(values[1].Name, values[1].Id, comb.StockQuantity));
if(pvaValueModel.AffectsObjectId == null)
{
pvaValueModel.CurrentObjectId = "product_attribute_" + pvaModel.ProductId.ToString() + "_" +
values[0].ProductVariantAttribute.ProductAttributeId.ToString() + "_" +
values[0].ProductVariantAttributeId.ToString();
pvaValueModel.AffectsObjectId = "product_attribute_" + pvaModel.ProductId.ToString() + "_" +
values[1].ProductVariantAttribute.ProductAttributeId.ToString() + "_" +
values[1].ProductVariantAttributeId.ToString();
}
}
}
}
pvaModel.Values.Add(pvaValueModel);
STEP 5.
Update your View. in Nop.Web\Views\Catalog.
Well, i didn't include the code here because it has several modifications along the file, and Its better to just replace with my updated file. Please download all files from here:
https://www.mediafire.com/folder/36lk4dz9fcufm/PVAChanges
All comments are in english. There are only two hardcoded words in spanish: 'Agotado' which means Out of Stock and 'Queda n piezas' means n items in stock left.
I've done basic testing and it works great. I haven't tested with multiple variants, but it should work.
Let me know if it works for you. I'll be check this post for questions.
Regards
Victor
[[[UPDATE 1.0]]]
I added a couple of validations in two files. For non-mastered items.
Also, In the shared webfolder, you will find ADMIN folder, which contains all the files necessary to set the Master Flag to true from the admin UI. I'm extending this, so I will keep posting stuff.