improvements, fixes, etc...

This commit is contained in:
Loretta 2025-09-29 13:33:40 +02:00
parent 23e7b6a603
commit 6e43a1d18f
11 changed files with 263 additions and 66 deletions

View File

@ -190,11 +190,18 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Controllers
{
_logger.Detail($"GetMeasuringUsers invoked");
var customers = await ctx.GetCustormersBySystemRoleName(FruitBankConst.MeasuringRoleSystemName).Select(c => new CustomerDto(c)).ToListAsync();
var customers = await ctx.GetCustomersBySystemRoleName(FruitBankConst.MeasuringRoleSystemName).Select(c => new CustomerDto(c)).ToListAsync();
return customers; //.ToModelDto<CustomerDto>();
}
[SignalR(SignalRTags.GetCustomerRolesByCustomerId)]
public async Task<List<CustomerRole>> GetCustomerRolesByCustomerId(int customerId)
{
_logger.Detail($"GetCustomerRolesByCustomerId invoked; customerId: {customerId}");
return await ctx.GetCustomerRolesByCustomerId(customerId).ToListAsync();
}
[SignalR(SignalRTags.GetProductDtos)]
public async Task<List<ProductDto>> GetProductDtos()
{

View File

@ -1,24 +1,32 @@
using AyCode.Core.Loggers;
#nullable enable
using AyCode.Core.Loggers;
using AyCode.Utils.Extensions;
using FruitBank.Common.Entities;
using FruitBank.Common.Interfaces;
using FruitBank.Common.Models;
using FruitBank.Common.Server;
using LinqToDB;
using LinqToDB.Common;
using Mango.Nop.Core.Loggers;
using Mango.Nop.Core.Repositories;
using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.ComponentModel;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Customers;
using Nop.Data;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces;
using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Services.Catalog;
using NUglify.Helpers;
using Nop.Services.Common;
using System.Transactions;
using LinqToDB;
using Nop.Core.ComponentModel;
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>, IShippingDbSet<ShippingDbTable>, IShippingItemDbSet<ShippingItemDbTable>, IShippingDocumentDbSet<ShippingDocumentDbTable>
{
private readonly FruitBankAttributeService _fruitBankAttributeService;
private readonly IStoreContext _storeContext;
private readonly IProductService _productService;
private readonly IStaticCacheManager _staticCacheManager;
@ -33,16 +41,19 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
public IRepository<CustomerCustomerRoleMapping> CustomerRoleMappings { get; set; }
public FruitBankDbContext(INopDataProvider dataProvider, PartnerDbTable partnerDbTable, ShippingDbTable shippingDbTable, ShippingItemDbTable shippingItemDbTable,
public FruitBankDbContext(INopDataProvider dataProvider, ILockService lockService, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext,
PartnerDbTable partnerDbTable, ShippingDbTable shippingDbTable, ShippingItemDbTable shippingItemDbTable,
ShippingDocumentDbTable shippingDocumentDbTable, IProductService productService, IStaticCacheManager staticCacheManager,
IRepository<Product> productRepository,
IRepository<Customer> customerRepository,
IRepository<CustomerCustomerRoleMapping> customerCustomerRoleMappingRepository,
IRepository<CustomerRole> customerRoleRepository,
IEnumerable<IAcLogWriterBase> logWriters) : base(dataProvider, logWriters)
IEnumerable<IAcLogWriterBase> logWriters) : base(dataProvider, lockService, logWriters)
{
_storeContext = storeContext;
_productService = productService;
_staticCacheManager = staticCacheManager;
_fruitBankAttributeService = fruitBankAttributeService;
Partners = partnerDbTable;
Shippings = shippingDbTable;
@ -66,7 +77,7 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
return query;
}
public IQueryable<Customer> GetCustormersBySystemRoleName(string systemRoleName)
public IQueryable<Customer> GetCustomersBySystemRoleName(string systemRoleName)
{
if (systemRoleName.IsNullOrWhiteSpace()) throw new ArgumentException("systemRoleName.IsNullOrWhiteSpace()", nameof(systemRoleName));
@ -80,32 +91,38 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
return query.Distinct().OrderBy(o => o.Username);
}
public IQueryable<CustomerRole> GetCustomerRolesByCustomerId(int customerId)
{
var query =
from cr in CustomerRoles.Table
join crm in CustomerRoleMappings.Table on cr.Id equals crm.CustomerRoleId
where crm.CustomerId == customerId
select cr;
return query.Distinct();
}
public IQueryable<Product> GetAllProducts()
=> Products.Table.Where(p => !p.Deleted).OrderBy(o => o.Name);
public Task<bool> UpdateMeasuredShippingItemAsync(ShippingItem shippingItem)
{
if (!shippingItem.IsMeasurable || shippingItem.IsValidMeasuringValues()) return UpdateShippingItemAsync(shippingItem);
if (shippingItem.IsValidMeasuringValues()) return UpdateShippingItemAsync(shippingItem);
Logger.Error("shippingItem.IsMeasurable && !shippingItem.IsValidMeasuringValues()");
return Task.FromResult(false);
}
private static readonly ReaderWriterLockSlim _locker = new(LockRecursionPolicy.NoRecursion);
public async Task<bool> UpdateShippingItemAsync(ShippingItem shippingItem)
public Task<bool> UpdateShippingItemAsync(ShippingItem shippingItem)
{
if (shippingItem == null)
{
Logger.Error("shippingItem == null");
return await Task.FromResult(false);
return Task.FromResult(false);
}
//using (new ReaderWriteLockDisposable(_locker))
//_locker.EnterWriteLock();
//try
//{
using var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled);
return TransactionSafeAsync(async tr =>
{
try
{
//Mi van ha nem jött meg a termék? Nem fogják tudni menteni... - J.
@ -119,8 +136,7 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
var dbShippingItem = await ShippingItems.GetByIdAsync(shippingItem.Id);
if (dbShippingItem == null)
{
Logger.Error("dbShippingItem == null");
return await Task.FromResult(false);
throw new Exception("dbShippingItem == null");
}
Product product = null;
@ -130,8 +146,12 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
if (product == null)
{
Logger.Error($"shippingItem.ProductId > 0 && product == null; shippingItem.ProductId: {shippingItem.ProductId}");
return await Task.FromResult(false);
throw new Exception($"shippingItem.ProductId > 0 && product == null; shippingItem.ProductId: {shippingItem.ProductId}");
//shippingItem.ProductId = null;
//if (!dbShippingItem.IsMeasured) shippingItem.ProductId = null;
//else return await Task.FromResult(false);
}
}
@ -139,7 +159,6 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
await ShippingItems.UpdateAsync(shippingItem);
//TODO: a measuredweight-eket is! - J.
if (shippingItem.ProductId != dbShippingItem.ProductId ||
shippingItem.IsMeasured != dbShippingItem.IsMeasured || shippingItem.IsMeasurable != dbShippingItem.IsMeasurable ||
shippingItem.MeasuredQuantity != dbShippingItem.MeasuredQuantity ||
@ -149,15 +168,28 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
if (shippingItem.IsMeasured)
{
product!.StockQuantity += shippingItem.MeasuredQuantity.GetValueOrDefault(0);
product!.StockQuantity += shippingItem.MeasuredQuantity.GetValueOrDefault(0) - dbShippingItem.MeasuredQuantity.GetValueOrDefault(0);
//IsMeasurable
//TODO: ROUND!!!! - J.
var measuringValues = new MeasuringAttributeValues
{
NetWeight = shippingItem.MeasuredNetWeight - dbShippingItem.MeasuredNetWeight,
GrossWeight = shippingItem.MeasuredGrossWeight- dbShippingItem.MeasuredGrossWeight,
IsMeasurable = shippingItem.IsMeasurable
};
if (!await UpdateProductStockQuantityAsync(product))
{
Logger.Error($"UpdateProductStockQuantity() == false; shippingItem! id: {product.Id}");
return await Task.FromResult(false);
throw new Exception($"UpdateProductStockQuantity() == false; shippingItem! id: {product.Id}");
}
//var measuringValues = new MeasuringAttributeValues(shippingItem.MeasuredNetWeight, shippingItem.MeasuredGrossWeight, shippingItem.IsMeasurable);
await _fruitBankAttributeService.InsertOrUpdateMeasuringAttributeValuesAsync<Product>(product.Id, measuringValues, true);
}
if (productIdUnchanged) return true;
if (dbShippingItem.IsMeasured)
{
product = await Products.GetByIdAsync(dbShippingItem.ProductId);
@ -168,31 +200,30 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
if (!await UpdateProductStockQuantityAsync(product))
{
Logger.Error($"UpdateProductStockQuantity() == false; dbShippingItem! id: {product.Id}");
return await Task.FromResult(false);
throw new Exception($"UpdateProductStockQuantity() == false; dbShippingItem! id: {product.Id}");
//return await Task.FromResult(false);
}
var measuringValues = new MeasuringAttributeValues(-dbShippingItem.MeasuredNetWeight, -dbShippingItem.MeasuredGrossWeight, dbShippingItem.IsMeasurable);
await _fruitBankAttributeService.InsertOrUpdateMeasuringAttributeValuesAsync<Product>(product.Id, measuringValues, true);
}
else Logger.Warning($"product == null; dbShippingItem.ProductId: {dbShippingItem.ProductId}");
}
}
//else //TODO: productIdUnchanged-et lekezelni! - J.
return true;
}
catch (Exception ex)
{
Logger.Error($"UpdateShippingItemAsync Transaction ERROR! Id: {shippingItem?.Id}", ex);
return await Task.FromResult(false);
throw new Exception($"UpdateShippingItemAsync Transaction ERROR! Id: {shippingItem?.Id}; ex: {ex.Message}", ex);
}
transaction.Complete();
//}
//finally
//{
// _locker.ExitWriteLock();
//}
return await Task.FromResult(true);
});
}
private async Task<bool> UpdateProductStockQuantityAsync(int productId)
{
var product = await Products.GetByIdAsync(productId);

View File

@ -29,9 +29,16 @@ public class ShippingDbTable : MgDbTableBase<Shipping>
}
public IQueryable<Shipping> GetAllNotMeasured(bool loadRelations)
=> GetAll(loadRelations).Where(s => !s.IsAllMeasured);
=> GetAll(loadRelations).Where(s => !s.IsAllMeasured || s.MeasuredDate == null || s.MeasuredDate < DateTime.Now.AddDays(1000));
public Task<Shipping> GetByIdAsync(int id, bool loadRelations)
=> GetAll(loadRelations).FirstOrDefaultAsync(s => s.Id == id);
protected override void OnUpdate(Shipping entity)
{
if (entity is { IsAllMeasured: true, MeasuredDate: null }) entity.MeasuredDate = DateTime.Now;
base.OnUpdate(entity);
}
}

View File

@ -41,5 +41,4 @@ public class ShippingItemDbTable : MgDbTableBase<ShippingItem>
public IQueryable<ShippingItem> GetAllByShippingDocumentIdAsync(int shippingDocumentId, bool loadRelations)
=> GetAll(loadRelations).Where(si => si.ShippingDocumentId == shippingDocumentId);
}

View File

@ -2,26 +2,30 @@
using FruitBank.Common.Entities;
using FruitBank.Common.Interfaces;
using FruitBank.Common.Loggers;
using FruitBank.Common.Server;
using Mango.Nop.Core.Loggers;
using Mango.Nop.Services;
using Microsoft.AspNetCore.Http;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Events;
using Nop.Plugin.Misc.FruitBankPlugin.Controllers;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Services.Common;
using Nop.Services.Events;
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.EventConsumers;
public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, FruitBankDbContext ctx, IEnumerable<IAcLogWriterBase> logWriters) :
public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, FruitBankDbContext ctx, IGenericAttributeService genericAttributeService, IStoreContext storeContext, IEnumerable<IAcLogWriterBase> logWriters) :
MgEventConsumer(httpContextAccessor, logWriters),
IConsumer<EntityUpdatedEvent<ShippingItem>>,
IConsumer<EntityUpdatedEvent<ShippingDocument>>
{
public override Task HandleEventAsync(EntityUpdatedEvent<Product> eventMessage)
public override async Task HandleEventAsync(EntityUpdatedEvent<Product> eventMessage)
{
return base.HandleEventAsync(eventMessage);
var isMeasurableProduct = await genericAttributeService.GetAttributeAsync<bool>(eventMessage.Entity, FruitBankConst.IsMeasureableAttributeName, storeContext.GetCurrentStore().Id);
await base.HandleEventAsync(eventMessage);
}
public async Task HandleEventAsync(EntityInsertedEvent<ShippingItem> eventMessage)

View File

@ -21,7 +21,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
public class FruitBankPlugin : BasePlugin, IWidgetPlugin
{
protected readonly IActionContextAccessor _actionContextAccessor;
private readonly ISettingService _settingService;
//private readonly IWebHelper _webHelper;
protected readonly IPermissionService _permissionService;
protected readonly ILocalizationService _localizationService;
@ -35,9 +37,9 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
ISettingService settingService,
//IWebHelper webHelper,
ILocalizationService localizationService,
IPermissionService permissionService,
IUrlHelperFactory urlHelperFactory,
IAdminMenu adminMenu)
IPermissionService permissionService,
IUrlHelperFactory urlHelperFactory,
IAdminMenu adminMenu)
{
_actionContextAccessor = actionContextAccessor;
_settingService = settingService;
@ -52,8 +54,13 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
public override async Task InstallAsync()
{
//TODO: Add "Measuring" role - FruitBankConst.MeasuringRoleSystemName
//TODO: Add "MeasuringRevisor" role - FruitBankConst.MeasuringRevisorRoleSystemName
//TODO: Add "IsMeasurable" product attribute - FruitBankConst.IsMeasureableAttributeName
//TODO: Add "NeedsToBeMeasured" product attribute if not exists
//TODO: Add unique index to GenericAttribute[EntityId, KeyGroup, Key]???!? ÁTGONDOLNI, mert lehet esetleg lista is a visszaadott, de a nopcommerce kódban felülírja ha azonos key-el vannak! - J.
// Default settings
var settings = new OpenAiSettings
{
@ -129,24 +136,24 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
Title = await _localizationService.GetResourceAsync("Plugins.Misc.SignalRApi.Menu.AI"),
IconClass = "far fa-dot-circle",
ChildNodes = new List<AdminMenuItem>
{
new()
{
// SystemName = "FruitBankPlugin.Configure",
// Title = "AI Assistant",
// Url = $"{_webHelper.GetStoreLocation()}Admin/FruitBankPluginAdmin/Configure",
// Visible = true
Visible = true,
SystemName = PluginDescriptor.SystemName,
Title = PluginDescriptor.FriendlyName,
IconClass = "far fa-circle",
Url = _adminMenu.GetMenuItemUrl("FruitBankPlugin", "Configure"),
//Url = "Admin/SignalRApi/Configure",
//ControllerName = "SignalRApi",
//ActionName = "Configure",
//RouteValues = new RouteValueDictionary { { "area", AreaNames.ADMIN } }
new()
{
// SystemName = "FruitBankPlugin.Configure",
// Title = "AI Assistant",
// Url = $"{_webHelper.GetStoreLocation()}Admin/FruitBankPluginAdmin/Configure",
// Visible = true
Visible = true,
SystemName = PluginDescriptor.SystemName,
Title = PluginDescriptor.FriendlyName,
IconClass = "far fa-circle",
Url = _adminMenu.GetMenuItemUrl("FruitBankPlugin", "Configure"),
//Url = "Admin/SignalRApi/Configure",
//ControllerName = "SignalRApi",
//ActionName = "Configure",
//RouteValues = new RouteValueDictionary { { "area", AreaNames.ADMIN } }
}
}
}
});
}

View File

@ -6,6 +6,7 @@ using FruitBank.Common.Interfaces;
using FruitBank.Common.Server.Services.Loggers;
using FruitBank.Common.Server.Services.SignalRs;
using Mango.Nop.Core.Loggers;
using Mango.Nop.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.SignalR;
@ -36,12 +37,14 @@ public class PluginNopStartup : INopStartup
//register services and interfaces
services.AddSingleton<ILockService, LockService>();
services.AddScoped<IAcLogWriterBase, ConsoleLogWriter>();
//services.AddScoped<IAcLogWriterBase, NopLogWriter>();
services.AddScoped<LoggerToLoggerApiController2>();
//services.AddSingleton<SessionService>();
services.AddScoped<FruitBankAttributeService>();
services.AddScoped<PartnerDbTable>();
services.AddScoped<ShippingDbTable>();
services.AddScoped<ShippingItemDbTable>();

View File

@ -99,6 +99,9 @@
<Reference Include="AyCode.Services.Server">
<HintPath>..\..\..\..\FruitBankHybridApp\FruitBank.Common.Server\bin\Debug\net9.0\AyCode.Services.Server.dll</HintPath>
</Reference>
<Reference Include="AyCode.Utils">
<HintPath>..\..\..\..\FruitBankHybridApp\FruitBank.Common.Server\bin\Debug\net9.0\AyCode.Utils.dll</HintPath>
</Reference>
<Reference Include="FruitBank.Common">
<HintPath>..\..\..\..\FruitBankHybridApp\FruitBank.Common.Server\bin\Debug\net9.0\FruitBank.Common.dll</HintPath>
</Reference>

View File

@ -0,0 +1,117 @@
#nullable enable
using FruitBank.Common.Interfaces;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Services.Common;
namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
public class FruitBankAttributeService(IGenericAttributeService genericAttributeService, IStoreContext storeContext)
{
public async Task<GenericAttribute?> GetGenericAttributeAsync<TEntityType>(int entityId, string key, int storeId)
{
return (await genericAttributeService.GetAttributesForEntityAsync(entityId, typeof(TEntityType).Name)).SingleOrDefault(ga => ga.StoreId == storeId && ga.Key == key);
}
public async Task<List<GenericAttribute>> GetMeasuringAttributesAsync<TEntityType>(int entityId, int storeId)
{
var measuringAttributes = (await genericAttributeService.GetAttributesForEntityAsync(entityId, typeof(TEntityType).Name))
.Where(ga => ga.StoreId == storeId &&
(ga.Key is nameof(MeasuringAttributeValues.NetWeight) or nameof(MeasuringAttributeValues.GrossWeight) or nameof(MeasuringAttributeValues.IsMeasurable)))
.ToList();
return measuringAttributes;
}
public Task<MeasuringAttributeValues?> GetMeasuringAttributeValuesAsync<TEntityType>(int entityId)
=> GetMeasuringAttributeValuesAsync<TEntityType>(entityId, storeContext.GetCurrentStore().Id);
public async Task<MeasuringAttributeValues?> GetMeasuringAttributeValuesAsync<TEntityType>(int entityId, int storeId)
{
var measuringAttributes = await GetMeasuringAttributesAsync<TEntityType>(entityId, storeId);
if (measuringAttributes.Count == 0) return null;
var measuringAttributeValues = new MeasuringAttributeValues(
CommonHelper.To<double?>(measuringAttributes.FirstOrDefault(ga => ga.Key == nameof(MeasuringAttributeValues.NetWeight))),
CommonHelper.To<double?>(measuringAttributes.FirstOrDefault(ga => ga.Key == nameof(MeasuringAttributeValues.GrossWeight))),
CommonHelper.To<bool?>(measuringAttributes.FirstOrDefault(ga => ga.Key == nameof(MeasuringAttributeValues.IsMeasurable))));
return measuringAttributeValues;
}
public Task<bool> InsertOrUpdateMeasuringAttributeValuesAsync<TEntityType>(int entityId, MeasuringAttributeValues measuringAttributeValues, bool cumulativeWeightUpdate)
=> InsertOrUpdateMeasuringAttributeValuesAsync<TEntityType>(entityId, storeContext.GetCurrentStore().Id, measuringAttributeValues, cumulativeWeightUpdate);
public async Task<bool> InsertOrUpdateMeasuringAttributeValuesAsync<TEntityType>(int entityId, int storeId, MeasuringAttributeValues measuringAttributeValues, bool cumulativeWeightUpdate)
{
if (!measuringAttributeValues.HasValues()) return false;
var measuringAttributes = await GetMeasuringAttributesAsync<TEntityType>(entityId, storeId);
var netWeightAttribute = measuringAttributes.FirstOrDefault(ma => ma.Key == nameof(MeasuringAttributeValues.NetWeight));
if (netWeightAttribute != null) await UpdateMeasuringWeightAttributeValueAsync(netWeightAttribute, measuringAttributeValues.NetWeight!.Value, cumulativeWeightUpdate);
else await InsertGenericAttributeAsync<TEntityType, double>(entityId, nameof(MeasuringAttributeValues.NetWeight), measuringAttributeValues.NetWeight!.Value, storeId);
var grossWeightAttribute = measuringAttributes.FirstOrDefault(ma => ma.Key == nameof(MeasuringAttributeValues.GrossWeight));
if (grossWeightAttribute != null) await UpdateMeasuringWeightAttributeValueAsync(grossWeightAttribute, measuringAttributeValues.GrossWeight!.Value, cumulativeWeightUpdate);
else await InsertGenericAttributeAsync<TEntityType, double>(entityId, nameof(MeasuringAttributeValues.GrossWeight), measuringAttributeValues.GrossWeight!.Value, storeId);
var isMeasurableAttribute = measuringAttributes.FirstOrDefault(ma => ma.Key == nameof(MeasuringAttributeValues.IsMeasurable));
if (isMeasurableAttribute != null) await UpdateGenericAttributeAsync(isMeasurableAttribute, measuringAttributeValues.IsMeasurable!.Value);
else await InsertGenericAttributeAsync<TEntityType, bool>(entityId, nameof(MeasuringAttributeValues.IsMeasurable), measuringAttributeValues.IsMeasurable!.Value, storeId);
return true;
}
private async Task UpdateMeasuringWeightAttributeValueAsync(GenericAttribute genericAttribute, double newWeightValue, bool cumulativeWeightUpdate)
{
await UpdateGenericAttributeAsync(genericAttribute, cumulativeWeightUpdate ? CommonHelper.To<double>(genericAttribute.Value) + newWeightValue : newWeightValue);
}
public async Task DeleteAllMeasuringAttributesAsync<TEntityType>(int entityId, int storeId)
{
var measuringAttributes = await GetMeasuringAttributesAsync<TEntityType>(entityId, storeId);
if (measuringAttributes.Count == 0) return;
foreach (var measuringAttribute in measuringAttributes)
{
await genericAttributeService.DeleteAttributeAsync(measuringAttribute);
}
}
public async Task InsertGenericAttributeAsync<TEntityType, TPropType>(int entityId, string key, TPropType value, int storeId)
{
var genericAttribute = new GenericAttribute
{
Key = key,
EntityId = entityId,
KeyGroup = typeof(TEntityType).Name,
Value = CommonHelper.To<string>(value),
StoreId = storeId
};
await genericAttributeService.InsertAttributeAsync(genericAttribute);
}
public async Task UpdateGenericAttributeAsync<TEntityType, TPropType>(int entityId, string key, TPropType newValue, int storeId)
{
var ga = await GetGenericAttributeAsync<TEntityType>(entityId, key, storeId);
await UpdateGenericAttributeAsync(ga!, newValue);
}
public async Task UpdateGenericAttributeAsync<TPropType>(GenericAttribute genericAttribute, TPropType newValue)
{
genericAttribute.Value = CommonHelper.To<string>(newValue);
await genericAttributeService.UpdateAttributeAsync(genericAttribute);
}
public async Task DeleteGenericAttributeAsync<TEntityType>(int entityId, string key, int storeId)
{
var ga = await GetGenericAttributeAsync<TEntityType>(entityId, key, storeId);
if (ga == null) return;
await genericAttributeService.DeleteAttributeAsync(ga);
}
}

View File

@ -0,0 +1,5 @@
using Mango.Nop.Services;
namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
public interface ILockService : IMgLockService{}

View File

@ -0,0 +1,14 @@
using Mango.Nop.Services;
namespace Nop.Plugin.Misc.FruitBankPlugin.Services;
public class LockService : MgLockService, ILockService
{
public LockService() : this(new SemaphoreSlim(1))
{}
public LockService(SemaphoreSlim semaphoreSlim) : base(semaphoreSlim)
{
}
}