diff --git a/src/Libraries/Nop.Core/Domain/Vendors/Vendor.cs b/src/Libraries/Nop.Core/Domain/Vendors/Vendor.cs index a89652794f8..564037c34a5 100644 --- a/src/Libraries/Nop.Core/Domain/Vendors/Vendor.cs +++ b/src/Libraries/Nop.Core/Domain/Vendors/Vendor.cs @@ -1,106 +1,125 @@ -using Nop.Core.Domain.Common; -using Nop.Core.Domain.Localization; -using Nop.Core.Domain.Seo; - -namespace Nop.Core.Domain.Vendors; - -/// -/// Represents a vendor -/// -public partial class Vendor : BaseEntity, ILocalizedEntity, ISlugSupported, ISoftDeletedEntity -{ - /// - /// Gets or sets the name - /// - public string Name { get; set; } - - /// - /// Gets or sets the email - /// - public string Email { get; set; } - - /// - /// Gets or sets the description - /// - public string Description { get; set; } - - /// - /// Gets or sets the picture identifier - /// - public int PictureId { get; set; } - - /// - /// Gets or sets the address identifier - /// - public int AddressId { get; set; } - - /// - /// Gets or sets the admin comment - /// - public string AdminComment { get; set; } - - /// - /// Gets or sets a value indicating whether the entity is active - /// - public bool Active { get; set; } - - /// - /// Gets or sets a value indicating whether the entity has been deleted - /// - public bool Deleted { get; set; } - - /// - /// Gets or sets the display order - /// - public int DisplayOrder { get; set; } - - /// - /// Gets or sets the meta keywords - /// - public string MetaKeywords { get; set; } - - /// - /// Gets or sets the meta description - /// - public string MetaDescription { get; set; } - - /// - /// Gets or sets the meta title - /// - public string MetaTitle { get; set; } - - /// - /// Gets or sets the page size - /// - public int PageSize { get; set; } - - /// - /// Gets or sets a value indicating whether customers can select the page size - /// - public bool AllowCustomersToSelectPageSize { get; set; } - - /// - /// Gets or sets the available customer selectable page size options - /// - public string PageSizeOptions { get; set; } - - /// - /// Gets or sets a value indicating whether the price range filtering is enabled - /// - public bool PriceRangeFiltering { get; set; } - - /// - /// Gets or sets the "from" price - /// - public decimal PriceFrom { get; set; } - - /// - /// Gets or sets the "to" price - /// - public decimal PriceTo { get; set; } - - /// - /// Gets or sets a value indicating whether the price range should be entered manually - /// - public bool ManuallyPriceRange { get; set; } -} \ No newline at end of file +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; + +/// +/// Represents a vendor +/// +public partial class Vendor : BaseEntity, ILocalizedEntity, ISlugSupported, ISoftDeletedEntity +{ + /// + /// Gets or sets the name + /// + public string Name { get; set; } + + /// + /// Gets or sets the email + /// + public string Email { get; set; } + + /// + /// Gets or sets the description + /// + public string Description { get; set; } + + /// + /// Gets or sets the picture identifier + /// + public int PictureId { get; set; } + + /// + /// Gets or sets the address identifier + /// + public int AddressId { get; set; } + + /// + /// Gets or sets the admin comment + /// + public string AdminComment { get; set; } + + /// + /// Gets or sets a value indicating whether the entity is active + /// + public bool Active { get; set; } + + /// + /// Gets or sets a value indicating whether the entity has been deleted + /// + public bool Deleted { get; set; } + + /// + /// Gets or sets the display order + /// + public int DisplayOrder { get; set; } + + /// + /// Gets or sets the meta keywords + /// + public string MetaKeywords { get; set; } + + /// + /// Gets or sets the meta description + /// + public string MetaDescription { get; set; } + + /// + /// Gets or sets the meta title + /// + public string MetaTitle { get; set; } + + /// + /// Gets or sets the page size + /// + public int PageSize { get; set; } + + /// + /// Gets or sets a value indicating whether customers can select the page size + /// + public bool AllowCustomersToSelectPageSize { get; set; } + + /// + /// Gets or sets the available customer selectable page size options + /// + public string PageSizeOptions { get; set; } + + /// + /// Gets or sets a value indicating whether the price range filtering is enabled + /// + public bool PriceRangeFiltering { get; set; } + + /// + /// Gets or sets the "from" price + /// + public decimal PriceFrom { get; set; } + + /// + /// Gets or sets the "to" price + /// + public decimal PriceTo { get; set; } + + /// + /// Gets or sets a value indicating whether the price range should be entered manually + /// + public bool ManuallyPriceRange { get; set; } + + /// + /// Gets or sets the list of vendor reviews + /// + public virtual ICollection VendorReviews { get; set; } = new List(); + + /// + /// Calculates the average rating from the vendor reviews + /// + /// The average rating + public double CalculateAverageRating() + { + if (VendorReviews == null || !VendorReviews.Any()) + return 0; + + return VendorReviews.Average(r => r.Rating); + } +} diff --git a/src/Libraries/Nop.Core/Domain/Vendors/VendorReview.cs b/src/Libraries/Nop.Core/Domain/Vendors/VendorReview.cs new file mode 100644 index 00000000000..85c67963cb2 --- /dev/null +++ b/src/Libraries/Nop.Core/Domain/Vendors/VendorReview.cs @@ -0,0 +1,37 @@ +namespace Nop.Core.Domain.Vendors; + +/// +/// Represents a vendor review +/// +public partial class VendorReview : BaseEntity +{ + /// + /// Gets or sets the vendor identifier + /// + public int VendorId { get; set; } + + /// + /// Gets or sets the customer identifier + /// + public int CustomerId { get; set; } + + /// + /// Gets or sets the rating + /// + public int Rating { get; set; } + + /// + /// Gets or sets the review text + /// + public string ReviewText { get; set; } + + /// + /// Gets or sets a value indicating whether the content is approved + /// + public bool IsApproved { get; set; } + + /// + /// Gets or sets the date and time of instance creation + /// + public DateTime CreatedOnUtc { get; set; } +} diff --git a/src/Libraries/Nop.Services/Catalog/Caching/VendorReviewCacheEventConsumer.cs b/src/Libraries/Nop.Services/Catalog/Caching/VendorReviewCacheEventConsumer.cs new file mode 100644 index 00000000000..dc3497b25c7 --- /dev/null +++ b/src/Libraries/Nop.Services/Catalog/Caching/VendorReviewCacheEventConsumer.cs @@ -0,0 +1,11 @@ +using Nop.Core.Domain.Vendors; +using Nop.Services.Caching; + +namespace Nop.Services.Catalog.Caching; + +/// +/// Represents a vendor review cache event consumer +/// +public partial class VendorReviewCacheEventConsumer : CacheEventConsumer +{ +} diff --git a/src/Presentation/Nop.Web/Areas/Admin/Controllers/VendorController.cs b/src/Presentation/Nop.Web/Areas/Admin/Controllers/VendorController.cs index f8f693b3b9e..ee63ad2c5d5 100644 --- a/src/Presentation/Nop.Web/Areas/Admin/Controllers/VendorController.cs +++ b/src/Presentation/Nop.Web/Areas/Admin/Controllers/VendorController.cs @@ -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; @@ -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 @@ -61,7 +62,8 @@ public VendorController(IAddressService addressService, IPictureService pictureService, IUrlRecordService urlRecordService, IVendorModelFactory vendorModelFactory, - IVendorService vendorService) + IVendorService vendorService, + IVendorReviewService vendorReviewService) { _addressService = addressService; _addressAttributeParser = addressAttributeParser; @@ -78,6 +80,7 @@ public VendorController(IAddressService addressService, _urlRecordService = urlRecordService; _vendorModelFactory = vendorModelFactory; _vendorService = vendorService; + _vendorReviewService = vendorReviewService; } #endregion @@ -499,4 +502,61 @@ public virtual async Task VendorNoteDelete(int id) } #endregion -} \ No newline at end of file + + #region Vendor reviews + + [HttpPost] + [CheckPermission(StandardPermission.Customers.VENDORS_VIEW)] + public virtual async Task 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 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 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 +}