improvements, fixes, etc...

This commit is contained in:
Loretta 2025-09-30 07:24:36 +02:00
parent 6e4e8f99e0
commit 53a336cb3e
6 changed files with 126 additions and 102 deletions

View File

@ -127,119 +127,114 @@ public class FruitBankDbContext : MgDbContextBase, IPartnerDbSet<PartnerDbTable>
{
//Mi van ha nem jött meg a termék? Nem fogják tudni menteni... - J.
if (shippingItem.MeasuredQuantity <= 0) shippingItem.MeasuredQuantity = null;
Product? product = null;
var productIsMeasurable = false;
if (!shippingItem.IsMeasurable || shippingItem.MeasuredNetWeight <= 0) shippingItem.MeasuredNetWeight = null;
if (!shippingItem.IsMeasurable || shippingItem.MeasuredGrossWeight <= 0) shippingItem.MeasuredGrossWeight = null;
//Update előtt kivesszük a korábbi ShippingItem-et a db-ből! - J.
var dbShippingItem = await ShippingItems.GetByIdAsync(shippingItem.Id);
if (dbShippingItem == null)
{
throw new Exception("dbShippingItem == null");
}
Product product = null;
if (shippingItem.ProductId > 0)
{
product = await Products.GetByIdAsync(shippingItem.ProductId);
if (product == null)
{
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);
}
productIsMeasurable = await _fruitBankAttributeService.IsMeasurableEntityAsync<Product>(product.Id);
}
shippingItem.IsMeasurable = productIsMeasurable;
if (shippingItem.MeasuredQuantity <= 0) shippingItem.MeasuredQuantity = null;
if (!shippingItem.IsMeasurable || shippingItem.MeasuredNetWeight <= 0) shippingItem.MeasuredNetWeight = null;
if (!shippingItem.IsMeasurable || shippingItem.MeasuredGrossWeight <= 0) shippingItem.MeasuredGrossWeight = null;
//Update előtt kivesszük a korábbi ShippingItem-et a db-ből! - J.
var dbShippingItem = await ShippingItems.GetByIdAsync(shippingItem.Id);
if (dbShippingItem == null) throw new Exception($"dbShippingItem == null; shippingItem.Id: {shippingItem.Id}");
shippingItem.IsMeasured = product != null && shippingItem.IsValidMeasuringValues();
await ShippingItems.UpdateAsync(shippingItem);
await ShippingItems.UpdateAsync(shippingItem, shippingItem.IsMeasured != dbShippingItem.IsMeasured);
if (shippingItem.ProductId != dbShippingItem.ProductId ||
shippingItem.IsMeasured != dbShippingItem.IsMeasured || shippingItem.IsMeasurable != dbShippingItem.IsMeasurable ||
shippingItem.MeasuredQuantity != dbShippingItem.MeasuredQuantity ||
shippingItem.MeasuredNetWeight != dbShippingItem.MeasuredNetWeight || shippingItem.MeasuredGrossWeight != dbShippingItem.MeasuredGrossWeight)
if (shippingItem.ProductId == dbShippingItem.ProductId &&
shippingItem.IsMeasured == dbShippingItem.IsMeasured && shippingItem.IsMeasurable == dbShippingItem.IsMeasurable &&
shippingItem.MeasuredQuantity == dbShippingItem.MeasuredQuantity &&
// ReSharper disable once CompareOfFloatsByEqualityOperator
shippingItem.MeasuredNetWeight == dbShippingItem.MeasuredNetWeight &&
// ReSharper disable once CompareOfFloatsByEqualityOperator
shippingItem.MeasuredGrossWeight == dbShippingItem.MeasuredGrossWeight)
{
var productIdUnchanged = shippingItem.ProductId == dbShippingItem.ProductId;
return true;
}
if (shippingItem.IsMeasured)
var productIdUnchanged = shippingItem.ProductId == dbShippingItem.ProductId;
if (shippingItem.IsMeasured)
{
product!.StockQuantity += productIdUnchanged ? shippingItem.MeasuredQuantity!.Value - dbShippingItem.MeasuredQuantity.GetValueOrDefault(0) : shippingItem.MeasuredQuantity!.Value;
if (!await UpdateProductStockQuantityAsync(product, true))
throw new Exception($"UpdateProductStockQuantity() == false; shippingItem! product.Id: {product.Id}");
if (productIsMeasurable)
{
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,
NetWeight = productIdUnchanged ? shippingItem.MeasuredNetWeight - dbShippingItem.MeasuredNetWeight.GetValueOrDefault(0) : shippingItem.MeasuredNetWeight,
GrossWeight = productIdUnchanged ? shippingItem.MeasuredGrossWeight - dbShippingItem.MeasuredGrossWeight.GetValueOrDefault(0) : shippingItem.MeasuredGrossWeight,
IsMeasurable = shippingItem.IsMeasurable
};
if (!await UpdateProductStockQuantityAsync(product))
{
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);
if (product != null)
{
product.StockQuantity -= dbShippingItem.MeasuredQuantity.GetValueOrDefault(0);
if (!await UpdateProductStockQuantityAsync(product))
{
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}");
}
}
if (productIdUnchanged || !dbShippingItem.IsMeasured) return true;
product = await Products.GetByIdAsync(dbShippingItem.ProductId);
if (product != null)
{
productIsMeasurable = await _fruitBankAttributeService.IsMeasurableEntityAsync<Product>(product.Id);
product.StockQuantity -= dbShippingItem.MeasuredQuantity.GetValueOrDefault(0);
if (!await UpdateProductStockQuantityAsync(product, true))
throw new Exception($"UpdateProductStockQuantity() == false; dbShippingItem! product.Id: {product.Id}");
if (!productIsMeasurable) return true;
var measuringValues = new MeasuringAttributeValues(-dbShippingItem.MeasuredNetWeight.GetValueOrDefault(0), -dbShippingItem.MeasuredGrossWeight.GetValueOrDefault(0), 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)
{
throw new Exception($"UpdateShippingItemAsync Transaction ERROR! Id: {shippingItem?.Id}; ex: {ex.Message}", ex);
throw new Exception($"UpdateShippingItemAsync->TransactionSafeAsync error! shippingItem.Id: {shippingItem.Id}; ex: {ex.Message}", ex);
}
});
}
private async Task<bool> UpdateProductStockQuantityAsync(int productId)
private async Task<bool> UpdateProductStockQuantityAsync(int productId, bool publishEvent)
{
var product = await Products.GetByIdAsync(productId);
if (product != null) return await UpdateProductStockQuantityAsync(product);
if (product != null) return await UpdateProductStockQuantityAsync(product, publishEvent);
Logger.Error($"product == null; id: {productId}");
return await Task.FromResult(false);
}
private async Task<bool> UpdateProductStockQuantityAsync(Product product)
private async Task<bool> UpdateProductStockQuantityAsync(Product product, bool publishEvent)
{
//Itt mi legyen? RollBack? - J.
if (product.StockQuantity < 0)
Logger.Error($"product.StockQuantity < 0; Id: {product.Id}; StockQuantity: {product.StockQuantity}");
await Products.UpdateAsync(product, true);
await Products.UpdateAsync(product, publishEvent);
return await Task.FromResult(true);
//var updatedRowsCount = await DataProvider.ExecuteNonQueryAsync($"update product set {nameof(Product.StockQuantity)} = {product.StockQuantity} where {nameof(Product.Id)} = {product.Id}");

View File

@ -16,8 +16,19 @@ public class ShippingItemDbTable : MgDbTableBase<ShippingItem>
{
}
public override IQueryable<ShippingItem> GetAll()
=> base.GetAll();
protected override void OnUpdate(ShippingItem entity)
{
RoundMeasuredValue(entity);
base.OnUpdate(entity);
}
protected override void OnInsert(ShippingItem entity)
{
RoundMeasuredValue(entity);
base.OnInsert(entity);
}
public override IQueryable<ShippingItem> GetAll() => base.GetAll();
public IQueryable<ShippingItem> GetAll(bool loadRelations)
{
@ -41,4 +52,11 @@ public class ShippingItemDbTable : MgDbTableBase<ShippingItem>
public IQueryable<ShippingItem> GetAllByShippingDocumentIdAsync(int shippingDocumentId, bool loadRelations)
=> GetAll(loadRelations).Where(si => si.ShippingDocumentId == shippingDocumentId);
private static void RoundMeasuredValue(ShippingItem shippingItem)
{
if (shippingItem.MeasuredNetWeight.HasValue) shippingItem.MeasuredNetWeight = double.Round(shippingItem.MeasuredNetWeight.Value, 1);
if (shippingItem.MeasuredGrossWeight.HasValue) shippingItem.MeasuredGrossWeight = double.Round(shippingItem.MeasuredGrossWeight.Value, 1);
}
}

View File

@ -11,20 +11,25 @@ using Nop.Core.Domain.Catalog;
using Nop.Core.Events;
using Nop.Plugin.Misc.FruitBankPlugin.Controllers;
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
using Nop.Plugin.Misc.FruitBankPlugin.Services;
using Nop.Services.Common;
using Nop.Services.Events;
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.EventConsumers;
public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, FruitBankDbContext ctx, IGenericAttributeService genericAttributeService, IStoreContext storeContext, IEnumerable<IAcLogWriterBase> logWriters) :
MgEventConsumer(httpContextAccessor, logWriters),
IConsumer<EntityUpdatedEvent<ShippingItem>>,
IConsumer<EntityUpdatedEvent<ShippingDocument>>
public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, FruitBankDbContext ctx, FruitBankAttributeService fruitBankAttributeService, IStoreContext storeContext, IEnumerable<IAcLogWriterBase> logWriters) :
MgEventConsumer(httpContextAccessor, logWriters), IConsumer<EntityUpdatedEvent<ShippingItem>>, IConsumer<EntityUpdatedEvent<ShippingDocument>>
{
public override async Task HandleEventAsync(EntityUpdatedEvent<Product> eventMessage)
{
var isMeasurableProduct = await genericAttributeService.GetAttributeAsync<bool>(eventMessage.Entity, FruitBankConst.IsMeasureableAttributeName, storeContext.GetCurrentStore().Id);
var product = eventMessage.Entity;
var isMeasurableProduct = await fruitBankAttributeService.IsMeasurableEntityAsync<Product>(product.Id);
var shippingItems = await ctx.ShippingItems.Table
.Where(si => si.ProductId == product.Id && !si.IsMeasured && si.IsMeasurable != isMeasurableProduct)
.ToListAsync();
await ctx.ShippingItems.UpdateAsync(shippingItems, false);
await base.HandleEventAsync(eventMessage);
}
@ -53,7 +58,7 @@ public class FruitBankEventConsumer(IHttpContextAccessor httpContextAccessor, Fr
private async Task UpdateShippingDocumentIsAllMeasuredAsync(ShippingItem shippingItem)
{
//TODO: where: && IsMeasureable!!!! - J.
//TODO: where: && IsMeasurable!!!! - J.
var isAllShippingItemMeasured = ctx.ShippingItems.GetAll(false).Where(si => si.ShippingDocumentId == shippingItem.ShippingDocumentId).All(si => si.IsMeasured);
var shippingDocument = await ctx.ShippingDocuments.GetByIdAsync(shippingItem.ShippingDocumentId);

View File

@ -56,7 +56,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin
//TODO: Add "Measuring" role - FruitBankConst.MeasuringRoleSystemName
//TODO: Add "MeasuringRevisor" role - FruitBankConst.MeasuringRevisorRoleSystemName
//TODO: Add "IsMeasurable" product attribute - FruitBankConst.IsMeasureableAttributeName
//TODO: Add "IsMeasurable" product attribute - FruitBankConst.IsMeasurableAttributeName
//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.

View File

@ -1,4 +1,5 @@
using System.Linq;
using FruitBank.Common.Interfaces;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Orders;
@ -96,7 +97,7 @@ namespace Nop.Plugin.Misc.FruitBankPlugin.Services
System.Diagnostics.Debug.WriteLine($"Spec Attribute: {specificationAttribute.Name}, Option: {specificationAttributeOption.Name}");
// Check if this is your "NeedsToBeMeasured" specification attribute
if (specificationAttribute.Name == "Measureable" &&
if (specificationAttribute.Name == "Measureable" && //nameof(MeasuringAttributeValues.IsMeasurable)
specificationAttributeOption.Name == "Yes") // or whatever value you set
{
requiresMeasurement = true;

View File

@ -9,14 +9,14 @@ 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)
public async Task<GenericAttribute?> GetGenericAttributeAsync<TEntity>(int entityId, string key, int storeId)
{
return (await genericAttributeService.GetAttributesForEntityAsync(entityId, typeof(TEntityType).Name)).SingleOrDefault(ga => ga.StoreId == storeId && ga.Key == key);
return (await genericAttributeService.GetAttributesForEntityAsync(entityId, typeof(TEntity).Name)).SingleOrDefault(ga => ga.StoreId == storeId && ga.Key == key);
}
public async Task<List<GenericAttribute>> GetMeasuringAttributesAsync<TEntityType>(int entityId, int storeId)
public async Task<List<GenericAttribute>> GetMeasuringAttributesAsync<TEntity>(int entityId, int storeId)
{
var measuringAttributes = (await genericAttributeService.GetAttributesForEntityAsync(entityId, typeof(TEntityType).Name))
var measuringAttributes = (await genericAttributeService.GetAttributesForEntityAsync(entityId, typeof(TEntity).Name))
.Where(ga => ga.StoreId == storeId &&
(ga.Key is nameof(MeasuringAttributeValues.NetWeight) or nameof(MeasuringAttributeValues.GrossWeight) or nameof(MeasuringAttributeValues.IsMeasurable)))
.ToList();
@ -24,12 +24,12 @@ public class FruitBankAttributeService(IGenericAttributeService genericAttribute
return measuringAttributes;
}
public Task<MeasuringAttributeValues?> GetMeasuringAttributeValuesAsync<TEntityType>(int entityId)
=> GetMeasuringAttributeValuesAsync<TEntityType>(entityId, storeContext.GetCurrentStore().Id);
public Task<MeasuringAttributeValues?> GetMeasuringAttributeValuesAsync<TEntity>(int entityId)
=> GetMeasuringAttributeValuesAsync<TEntity>(entityId, storeContext.GetCurrentStore().Id);
public async Task<MeasuringAttributeValues?> GetMeasuringAttributeValuesAsync<TEntityType>(int entityId, int storeId)
public async Task<MeasuringAttributeValues?> GetMeasuringAttributeValuesAsync<TEntity>(int entityId, int storeId)
{
var measuringAttributes = await GetMeasuringAttributesAsync<TEntityType>(entityId, storeId);
var measuringAttributes = await GetMeasuringAttributesAsync<TEntity>(entityId, storeId);
if (measuringAttributes.Count == 0) return null;
@ -41,28 +41,33 @@ public class FruitBankAttributeService(IGenericAttributeService genericAttribute
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)
public Task<bool> IsMeasurableEntityAsync<TEntity>(int entityId) => IsMeasurableEntityAsync<TEntity>(entityId, storeContext.GetCurrentStore().Id);
public async Task<bool> IsMeasurableEntityAsync<TEntity>(int entityId, int storeId)
{
if (!measuringAttributeValues.HasValues()) return false;
var measurableAttribute = await GetGenericAttributeAsync<TEntity>(entityId, nameof(MeasuringAttributeValues.IsMeasurable), storeId);
return measurableAttribute != null && CommonHelper.To<bool>(measurableAttribute.Value);
}
var measuringAttributes = await GetMeasuringAttributesAsync<TEntityType>(entityId, storeId);
public Task InsertOrUpdateMeasuringAttributeValuesAsync<TEntity>(int entityId, MeasuringAttributeValues measuringAttributeValues, bool cumulativeWeightUpdate)
=> InsertOrUpdateMeasuringAttributeValuesAsync<TEntity>(entityId, storeContext.GetCurrentStore().Id, measuringAttributeValues, cumulativeWeightUpdate);
public async Task InsertOrUpdateMeasuringAttributeValuesAsync<TEntity>(int entityId, int storeId, MeasuringAttributeValues measuringAttributeValues, bool cumulativeWeightUpdate)
{
if (!measuringAttributeValues.HasValues()) throw new Exception($"FruitBankAttributeService->InsertOrUpdateMeasuringAttributeValuesAsync; measuringAttributeValues.HasValues() == false; entityId: {entityId}; values: {measuringAttributeValues}");
var measuringAttributes = await GetMeasuringAttributesAsync<TEntity>(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);
else await InsertGenericAttributeAsync<TEntity, 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);
else await InsertGenericAttributeAsync<TEntity, 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;
else await InsertGenericAttributeAsync<TEntity, bool>(entityId, nameof(MeasuringAttributeValues.IsMeasurable), measuringAttributeValues.IsMeasurable!.Value, storeId);
}
private async Task UpdateMeasuringWeightAttributeValueAsync(GenericAttribute genericAttribute, double newWeightValue, bool cumulativeWeightUpdate)
@ -70,9 +75,9 @@ public class FruitBankAttributeService(IGenericAttributeService genericAttribute
await UpdateGenericAttributeAsync(genericAttribute, cumulativeWeightUpdate ? CommonHelper.To<double>(genericAttribute.Value) + newWeightValue : newWeightValue);
}
public async Task DeleteAllMeasuringAttributesAsync<TEntityType>(int entityId, int storeId)
public async Task DeleteAllMeasuringAttributesAsync<TEntity>(int entityId, int storeId)
{
var measuringAttributes = await GetMeasuringAttributesAsync<TEntityType>(entityId, storeId);
var measuringAttributes = await GetMeasuringAttributesAsync<TEntity>(entityId, storeId);
if (measuringAttributes.Count == 0) return;
foreach (var measuringAttribute in measuringAttributes)
@ -81,13 +86,13 @@ public class FruitBankAttributeService(IGenericAttributeService genericAttribute
}
}
public async Task InsertGenericAttributeAsync<TEntityType, TPropType>(int entityId, string key, TPropType value, int storeId)
public async Task InsertGenericAttributeAsync<TEntity, TPropType>(int entityId, string key, TPropType value, int storeId)
{
var genericAttribute = new GenericAttribute
{
Key = key,
EntityId = entityId,
KeyGroup = typeof(TEntityType).Name,
KeyGroup = typeof(TEntity).Name,
Value = CommonHelper.To<string>(value),
StoreId = storeId
};
@ -95,9 +100,9 @@ public class FruitBankAttributeService(IGenericAttributeService genericAttribute
await genericAttributeService.InsertAttributeAsync(genericAttribute);
}
public async Task UpdateGenericAttributeAsync<TEntityType, TPropType>(int entityId, string key, TPropType newValue, int storeId)
public async Task UpdateGenericAttributeAsync<TEntity, TPropType>(int entityId, string key, TPropType newValue, int storeId)
{
var ga = await GetGenericAttributeAsync<TEntityType>(entityId, key, storeId);
var ga = await GetGenericAttributeAsync<TEntity>(entityId, key, storeId);
await UpdateGenericAttributeAsync(ga!, newValue);
}
@ -107,9 +112,9 @@ public class FruitBankAttributeService(IGenericAttributeService genericAttribute
await genericAttributeService.UpdateAttributeAsync(genericAttribute);
}
public async Task DeleteGenericAttributeAsync<TEntityType>(int entityId, string key, int storeId)
public async Task DeleteGenericAttributeAsync<TEntity>(int entityId, string key, int storeId)
{
var ga = await GetGenericAttributeAsync<TEntityType>(entityId, key, storeId);
var ga = await GetGenericAttributeAsync<TEntity>(entityId, key, storeId);
if (ga == null) return;
await genericAttributeService.DeleteAttributeAsync(ga);