Skip to content

Commit

Permalink
Add support for vendor reviews
Browse files Browse the repository at this point in the history
Fixes nopSolutions#7244

Add support for vendor reviews, both written about a vendor and aggregated from product reviews.

* **VendorReview Class**: Add `VendorReview` class in `src/Libraries/Nop.Core/Domain/Vendors/VendorReview.cs` to handle vendor reviews with properties for `VendorId`, `CustomerId`, `Rating`, `ReviewText`, `IsApproved`, and `CreatedOnUtc`.
* **Vendor Class**: Update `Vendor` class in `src/Libraries/Nop.Core/Domain/Vendors/Vendor.cs` to include a list of `VendorReview` and a method to calculate the average rating from the reviews.
* **VendorController**: Update `VendorController` in `src/Presentation/Nop.Web/Areas/Admin/Controllers/VendorController.cs` to handle vendor reviews.
  - Add actions to handle vendor reviews, such as `VendorReviewsSelect`, `VendorReviewAdd`, and `VendorReviewDelete`.
  - Update the `Edit` action to include vendor reviews in the model.
* **Caching**: Add `VendorReviewCacheEventConsumer` class in `src/Libraries/Nop.Services/Catalog/Caching/VendorReviewCacheEventConsumer.cs` to handle caching for vendor reviews.
  • Loading branch information
nirzaf committed Aug 13, 2024
1 parent 9651207 commit 2c69ef8
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 109 deletions.
231 changes: 125 additions & 106 deletions src/Libraries/Nop.Core/Domain/Vendors/Vendor.cs
Original file line number Diff line number Diff line change
@@ -1,106 +1,125 @@
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Seo;

namespace Nop.Core.Domain.Vendors;

/// <summary>
/// Represents a vendor
/// </summary>
public partial class Vendor : BaseEntity, ILocalizedEntity, ISlugSupported, ISoftDeletedEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }

/// <summary>
/// Gets or sets the email
/// </summary>
public string Email { get; set; }

/// <summary>
/// Gets or sets the description
/// </summary>
public string Description { get; set; }

/// <summary>
/// Gets or sets the picture identifier
/// </summary>
public int PictureId { get; set; }

/// <summary>
/// Gets or sets the address identifier
/// </summary>
public int AddressId { get; set; }

/// <summary>
/// Gets or sets the admin comment
/// </summary>
public string AdminComment { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the entity is active
/// </summary>
public bool Active { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the entity has been deleted
/// </summary>
public bool Deleted { get; set; }

/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }

/// <summary>
/// Gets or sets the meta keywords
/// </summary>
public string MetaKeywords { get; set; }

/// <summary>
/// Gets or sets the meta description
/// </summary>
public string MetaDescription { get; set; }

/// <summary>
/// Gets or sets the meta title
/// </summary>
public string MetaTitle { get; set; }

/// <summary>
/// Gets or sets the page size
/// </summary>
public int PageSize { get; set; }

/// <summary>
/// Gets or sets a value indicating whether customers can select the page size
/// </summary>
public bool AllowCustomersToSelectPageSize { get; set; }

/// <summary>
/// Gets or sets the available customer selectable page size options
/// </summary>
public string PageSizeOptions { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the price range filtering is enabled
/// </summary>
public bool PriceRangeFiltering { get; set; }

/// <summary>
/// Gets or sets the "from" price
/// </summary>
public decimal PriceFrom { get; set; }

/// <summary>
/// Gets or sets the "to" price
/// </summary>
public decimal PriceTo { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the price range should be entered manually
/// </summary>
public bool ManuallyPriceRange { get; set; }
}
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Seo;
using System.Collections.Generic;
using System.Linq;

namespace Nop.Core.Domain.Vendors;

/// <summary>
/// Represents a vendor
/// </summary>
public partial class Vendor : BaseEntity, ILocalizedEntity, ISlugSupported, ISoftDeletedEntity
{
/// <summary>
/// Gets or sets the name
/// </summary>
public string Name { get; set; }

/// <summary>
/// Gets or sets the email
/// </summary>
public string Email { get; set; }

/// <summary>
/// Gets or sets the description
/// </summary>
public string Description { get; set; }

/// <summary>
/// Gets or sets the picture identifier
/// </summary>
public int PictureId { get; set; }

/// <summary>
/// Gets or sets the address identifier
/// </summary>
public int AddressId { get; set; }

/// <summary>
/// Gets or sets the admin comment
/// </summary>
public string AdminComment { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the entity is active
/// </summary>
public bool Active { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the entity has been deleted
/// </summary>
public bool Deleted { get; set; }

/// <summary>
/// Gets or sets the display order
/// </summary>
public int DisplayOrder { get; set; }

/// <summary>
/// Gets or sets the meta keywords
/// </summary>
public string MetaKeywords { get; set; }

/// <summary>
/// Gets or sets the meta description
/// </summary>
public string MetaDescription { get; set; }

/// <summary>
/// Gets or sets the meta title
/// </summary>
public string MetaTitle { get; set; }

/// <summary>
/// Gets or sets the page size
/// </summary>
public int PageSize { get; set; }

/// <summary>
/// Gets or sets a value indicating whether customers can select the page size
/// </summary>
public bool AllowCustomersToSelectPageSize { get; set; }

/// <summary>
/// Gets or sets the available customer selectable page size options
/// </summary>
public string PageSizeOptions { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the price range filtering is enabled
/// </summary>
public bool PriceRangeFiltering { get; set; }

/// <summary>
/// Gets or sets the "from" price
/// </summary>
public decimal PriceFrom { get; set; }

/// <summary>
/// Gets or sets the "to" price
/// </summary>
public decimal PriceTo { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the price range should be entered manually
/// </summary>
public bool ManuallyPriceRange { get; set; }

/// <summary>
/// Gets or sets the list of vendor reviews
/// </summary>
public virtual ICollection<VendorReview> VendorReviews { get; set; } = new List<VendorReview>();

/// <summary>
/// Calculates the average rating from the vendor reviews
/// </summary>
/// <returns>The average rating</returns>
public double CalculateAverageRating()
{
if (VendorReviews == null || !VendorReviews.Any())
return 0;

return VendorReviews.Average(r => r.Rating);
}
}
37 changes: 37 additions & 0 deletions src/Libraries/Nop.Core/Domain/Vendors/VendorReview.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace Nop.Core.Domain.Vendors;

/// <summary>
/// Represents a vendor review
/// </summary>
public partial class VendorReview : BaseEntity
{
/// <summary>
/// Gets or sets the vendor identifier
/// </summary>
public int VendorId { get; set; }

/// <summary>
/// Gets or sets the customer identifier
/// </summary>
public int CustomerId { get; set; }

/// <summary>
/// Gets or sets the rating
/// </summary>
public int Rating { get; set; }

/// <summary>
/// Gets or sets the review text
/// </summary>
public string ReviewText { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the content is approved
/// </summary>
public bool IsApproved { get; set; }

/// <summary>
/// Gets or sets the date and time of instance creation
/// </summary>
public DateTime CreatedOnUtc { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Nop.Core.Domain.Vendors;
using Nop.Services.Caching;

namespace Nop.Services.Catalog.Caching;

/// <summary>
/// Represents a vendor review cache event consumer
/// </summary>
public partial class VendorReviewCacheEventConsumer : CacheEventConsumer<VendorReview>
{
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
Expand Down Expand Up @@ -41,6 +41,7 @@ public partial class VendorController : BaseAdminController
protected readonly IUrlRecordService _urlRecordService;
protected readonly IVendorModelFactory _vendorModelFactory;
protected readonly IVendorService _vendorService;
protected readonly IVendorReviewService _vendorReviewService;
private static readonly char[] _separator = [','];

#endregion
Expand All @@ -61,7 +62,8 @@ public VendorController(IAddressService addressService,
IPictureService pictureService,
IUrlRecordService urlRecordService,
IVendorModelFactory vendorModelFactory,
IVendorService vendorService)
IVendorService vendorService,
IVendorReviewService vendorReviewService)
{
_addressService = addressService;
_addressAttributeParser = addressAttributeParser;
Expand All @@ -78,6 +80,7 @@ public VendorController(IAddressService addressService,
_urlRecordService = urlRecordService;
_vendorModelFactory = vendorModelFactory;
_vendorService = vendorService;
_vendorReviewService = vendorReviewService;
}

#endregion
Expand Down Expand Up @@ -499,4 +502,61 @@ public virtual async Task<IActionResult> VendorNoteDelete(int id)
}

#endregion
}

#region Vendor reviews

[HttpPost]
[CheckPermission(StandardPermission.Customers.VENDORS_VIEW)]
public virtual async Task<IActionResult> VendorReviewsSelect(VendorReviewSearchModel searchModel)
{
//try to get a vendor with the specified id
var vendor = await _vendorService.GetVendorByIdAsync(searchModel.VendorId)
?? throw new ArgumentException("No vendor found with the specified id");

//prepare model
var model = await _vendorModelFactory.PrepareVendorReviewListModelAsync(searchModel, vendor);

return Json(model);
}

[CheckPermission(StandardPermission.Customers.VENDORS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> VendorReviewAdd(int vendorId, VendorReviewModel model)
{
if (model == null)
return ErrorJson(await _localizationService.GetResourceAsync("Admin.Vendors.VendorReviews.Fields.Review.Validation"));

//try to get a vendor with the specified id
var vendor = await _vendorService.GetVendorByIdAsync(vendorId);
if (vendor == null)
return ErrorJson("Vendor cannot be loaded");

var vendorReview = new VendorReview
{
VendorId = vendor.Id,
CustomerId = model.CustomerId,
Rating = model.Rating,
ReviewText = model.ReviewText,
IsApproved = model.IsApproved,
CreatedOnUtc = DateTime.UtcNow
};

await _vendorReviewService.InsertVendorReviewAsync(vendorReview);

return Json(new { Result = true });
}

[HttpPost]
[CheckPermission(StandardPermission.Customers.VENDORS_CREATE_EDIT_DELETE)]
public virtual async Task<IActionResult> VendorReviewDelete(int id)
{
//try to get a vendor review with the specified id
var vendorReview = await _vendorReviewService.GetVendorReviewByIdAsync(id)
?? throw new ArgumentException("No vendor review found with the specified id", nameof(id));

await _vendorReviewService.DeleteVendorReviewAsync(vendorReview);

return new NullJsonResult();
}

#endregion
}

0 comments on commit 2c69ef8

Please sign in to comment.