feat : add special offer

release
Amir Hossein Khademi 2024-02-03 10:34:48 +03:30
parent 36ae9bf0c3
commit 10892f9e82
21 changed files with 1765 additions and 31 deletions

View File

@ -16,6 +16,7 @@ bool HasPriceCeiling,
bool IsInfinity,
long UseCount,
bool IsForInvitation,
bool IsSpecialOffer,
Guid ProductId,
Guid CategoryId) : IRequest<DiscountLDto>;
@ -36,6 +37,7 @@ public sealed record UpdateDiscountCommand(Guid Id,
bool IsInfinity,
long UseCount,
bool IsForInvitation,
bool IsSpecialOffer,
Guid ProductId,
Guid CategoryId) : IRequest<bool>;

View File

@ -12,8 +12,10 @@ double Cost,
double PackingCost,
bool HasExpressDelivery,
int MaxOrderCount,
bool IsSpecialOffer,
Guid BrandId,
Guid CategoryId,
DiscountSDto SpecialOffer,
List<SpecificationSDto> Specifications,
List<StorageFileSDto> Files):IRequest<ProductLDto>;
@ -30,8 +32,11 @@ public sealed record UpdateProductCommand(
double PackingCost,
bool HasExpressDelivery,
int MaxOrderCount,
bool IsSpecialOffer,
Guid BrandId,
Guid CategoryId,
DiscountSDto SpecialOffer,
List<SpecificationSDto> Specifications,
List<StorageFileSDto> Files) : IRequest<bool>;
public sealed record DeleteProductCommand(Guid Id) : IRequest<bool>;

View File

@ -17,7 +17,10 @@ public class DiscountLDto : BaseDto<DiscountLDto,Discount>
public bool HasPriceCeiling { get; set; }
public bool IsInfinity { get; set; }
public long UseCount { get; set; }
public bool IsSpecialOffer { get; set; }
public bool IsForInvitation { get; set; }
public Guid ProductId { get; set; }
public string ProductName { get; set; } = string.Empty;
public Guid CategoryId { get; set; }
public string CategoryName { get; set; } = string.Empty;
}

View File

@ -17,9 +17,12 @@ public class ProductLDto : BaseDto<ProductLDto,Product>
public string BrandName { get; set; } = string.Empty;
public Guid CategoryId { get; set; }
public string CategoryName { get; set; } = string.Empty;
public bool IsSpecialOffer { get; set; }
public List<SpecificationSDto> Specifications { get; set; } = new();
public List<ReviewSDto> Reviews { get; set; } = new();
public List<ProductCategorySDto> Categories { get; set; } = new();
public List<StorageFileSDto> Files { get; set; } = new();
public DiscountSDto? SpecialOffer { get; set; }
}

View File

@ -17,5 +17,6 @@ public class DiscountSDto : BaseDto<DiscountSDto,Discount>
public bool HasPriceCeiling { get; set; }
public bool IsInfinity { get; set; }
public long UseCount { get; set; }
public bool IsSpecialOffer { get; set; }
public bool IsForInvitation { get; set; }
}

View File

@ -14,6 +14,7 @@ public class ProductSDto : BaseDto<ProductSDto, Product>
public bool HasDiscount { get; set; }
public double CostWithDiscount { get; set; }
public bool IsEnable { get; set; }
public bool IsSpecial { get; set; }
public bool BeDisplayed { get; set; }
public double PackingCost { get; set; }
public float Rate { get; set; }

View File

@ -9,9 +9,9 @@ public partial class CategoryDiscount : Discount
}
public CategoryDiscount(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation, Guid categoryId)
public CategoryDiscount(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation,bool isSpecialOffer, Guid categoryId)
: base(code, discountPercent, discountAmount, hasCode, amountType, type, count, startDate, expireDate, priceFloor, hasPriceFloor, priceCeiling, hasPriceCeiling, isInfinity, useCount,
isForInvitation)
isForInvitation, isSpecialOffer)
{
CategoryId = categoryId;
}

View File

@ -2,11 +2,25 @@
public partial class Discount
{
public static Discount Create(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation)
public static Discount Create(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation,bool isSpecialOffer)
{
return new Discount(code, discountPercent, discountAmount, hasCode, amountType, type, count, startDate,
expireDate, priceFloor, hasPriceFloor, priceCeiling, hasPriceCeiling, isInfinity, useCount,
isForInvitation);
return new Discount(code,
discountPercent,
discountAmount,
hasCode,
amountType,
type,
count,
startDate,
expireDate,
priceFloor,
hasPriceFloor,
priceCeiling,
hasPriceCeiling,
isInfinity,
useCount,
isForInvitation,
isSpecialOffer);
}
public bool IsExpired()
@ -15,20 +29,20 @@ public partial class Discount
public partial class ProductDiscount
{
public static ProductDiscount Create(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation , Guid productId)
public static ProductDiscount Create(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation ,bool isSpecialOffer, Guid productId)
{
return new ProductDiscount(code, discountPercent, discountAmount, hasCode, amountType, type, count, startDate,
expireDate, priceFloor, hasPriceFloor, priceCeiling, hasPriceCeiling, isInfinity, useCount,
isForInvitation, productId);
isForInvitation, isSpecialOffer, productId);
}
}
public partial class CategoryDiscount
{
public static CategoryDiscount Create(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation, Guid categoryId)
public static CategoryDiscount Create(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation, bool isSpecialOffer, Guid categoryId)
{
return new CategoryDiscount(code, discountPercent, discountAmount, hasCode, amountType, type, count, startDate,
expireDate, priceFloor, hasPriceFloor, priceCeiling, hasPriceCeiling, isInfinity, useCount,
isForInvitation, categoryId);
isForInvitation,isSpecialOffer, categoryId);
}
}

View File

@ -12,7 +12,23 @@ public partial class Discount : ApiEntity
}
public Discount(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation)
public Discount(string code,
int discountPercent,
long discountAmount,
bool hasCode,
DiscountAmountType amountType,
DiscountType type,
int count,
DateTime startDate,
DateTime expireDate,
long priceFloor,
bool hasPriceFloor,
long priceCeiling,
bool hasPriceCeiling,
bool isInfinity,
long useCount,
bool isForInvitation,
bool isSpecialOffer)
{
Code = code;
DiscountPercent = discountPercent;
@ -30,6 +46,7 @@ public partial class Discount : ApiEntity
IsInfinity = isInfinity;
UseCount = useCount;
IsForInvitation = isForInvitation;
IsSpecialOffer = isSpecialOffer;
}
public string Code { get; internal set; } = string.Empty;
public int DiscountPercent { get; internal set; }
@ -46,6 +63,7 @@ public partial class Discount : ApiEntity
public bool HasPriceCeiling { get; internal set; }
public bool IsInfinity { get; internal set; }
public long UseCount { get; internal set; }
public bool IsSpecialOffer { get; internal set; }
public bool IsForInvitation { get; internal set; }
public List<Order> Orders { get; internal set; } = new();

View File

@ -7,8 +7,8 @@ public partial class ProductDiscount : Discount
}
public ProductDiscount(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation,Guid productId)
: base(code, discountPercent, discountAmount, hasCode, amountType, type, count, startDate, expireDate, priceFloor, hasPriceFloor, priceCeiling, hasPriceCeiling, isInfinity, useCount, isForInvitation)
public ProductDiscount(string code, int discountPercent, long discountAmount, bool hasCode, DiscountAmountType amountType, DiscountType type, int count, DateTime startDate, DateTime expireDate, long priceFloor, bool hasPriceFloor, long priceCeiling, bool hasPriceCeiling, bool isInfinity, long useCount, bool isForInvitation,bool isSpecialOffer,Guid productId)
: base(code, discountPercent, discountAmount, hasCode, amountType, type, count, startDate, expireDate, priceFloor, hasPriceFloor, priceCeiling, hasPriceCeiling, isInfinity, useCount, isForInvitation, isSpecialOffer)
{
ProductId = productId;
}

View File

@ -13,14 +13,14 @@ public class CreateDiscountCommandHandler : IRequestHandler<CreateDiscountComman
switch (request.Type)
{
case DiscountType.All:
var ent = Discount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode, request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor, request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount, request.IsForInvitation);
var ent = Discount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode, request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor, request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount, request.IsForInvitation,request.IsSpecialOffer);
_repositoryWrapper.SetRepository<Discount>().Add(ent);
break;
case DiscountType.Category:
var catDis = CategoryDiscount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode,
request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor,
request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount,
request.IsForInvitation, request.CategoryId);
request.IsForInvitation,request.IsSpecialOffer, request.CategoryId);
_repositoryWrapper.SetRepository<CategoryDiscount>().Add(catDis);
break;
@ -28,14 +28,14 @@ public class CreateDiscountCommandHandler : IRequestHandler<CreateDiscountComman
var productDis = ProductDiscount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode,
request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor,
request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount,
request.IsForInvitation, request.ProductId);
request.IsForInvitation, request.IsSpecialOffer,request.ProductId);
_repositoryWrapper.SetRepository<ProductDiscount>().Add(productDis);
break;
default:
var def = Discount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode,
request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor,
request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount,
request.IsForInvitation);
request.IsForInvitation,request.IsSpecialOffer);
_repositoryWrapper.SetRepository<Discount>().Add(def);
break;
}

View File

@ -12,7 +12,7 @@ public class GetDiscountsQueryHandler : IRequestHandler<GetDiscountsQuery, List<
{
return await _repositoryWrapper.SetRepository<Discount>().TableNoTracking
.OrderByDescending(b => b.CreatedAt)
.Skip(request.Page * 10).Take(10)
.Skip(request.Page * 15).Take(15)
.Select(DiscountMapper.ProjectToSDto)
.ToListAsync(cancellationToken);
}

View File

@ -16,7 +16,7 @@ public class UpdateDiscountCommandHandler : IRequestHandler<UpdateDiscountComman
var ent = await _repositoryWrapper.SetRepository<Discount>().TableNoTracking.FirstOrDefaultAsync(d=>d.Id==request.Id,cancellationToken);
if (ent == null)
throw new AppException("Discount not found", ApiResultStatusCode.NotFound);
var newEnt = Discount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode, request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor, request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount, request.IsForInvitation);
var newEnt = Discount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode, request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor, request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount, request.IsForInvitation, request.IsSpecialOffer);
newEnt.Id = ent.Id;
_repositoryWrapper.SetRepository<Discount>().Update(newEnt);
break;
@ -28,7 +28,7 @@ public class UpdateDiscountCommandHandler : IRequestHandler<UpdateDiscountComman
var catDis = CategoryDiscount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode,
request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor,
request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount,
request.IsForInvitation, request.CategoryId);
request.IsForInvitation,request.IsSpecialOffer, request.CategoryId);
catDis.Id = catEnt.Id;
_repositoryWrapper.SetRepository<CategoryDiscount>().Update(catDis);
break;
@ -41,7 +41,7 @@ public class UpdateDiscountCommandHandler : IRequestHandler<UpdateDiscountComman
var productDis = ProductDiscount.Create(request.Code, request.DiscountPercent, request.DiscountAmount, request.HasCode,
request.AmountType, request.Type, request.Count, request.StartDate, request.ExpireDate, request.PriceFloor,
request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount,
request.IsForInvitation, request.ProductId);
request.IsForInvitation, request.IsSpecialOffer, request.ProductId);
productDis.Id = productEnt.Id;
_repositoryWrapper.SetRepository<ProductDiscount>().Update(productDis);
break;

View File

@ -3,10 +3,12 @@
public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, ProductLDto>
{
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly IMediator _mediator;
public CreateProductCommandHandler(IRepositoryWrapper repositoryWrapper)
public CreateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IMediator mediator)
{
_repositoryWrapper = repositoryWrapper;
_mediator = mediator;
}
public async Task<ProductLDto> Handle(CreateProductCommand request, CancellationToken cancellationToken)
@ -28,6 +30,27 @@ public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand,
_repositoryWrapper.SetRepository<Product>().Add(ent);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
if (request.IsSpecialOffer)
{
var discount = request.SpecialOffer.Adapt<DiscountLDto>();
discount.ProductId = ent.Id;
discount.IsSpecialOffer = true;
discount.Type = DiscountType.Product;
discount.HasCode = false;
discount.IsInfinity = true;
if (request.SpecialOffer.Id == default)
{
var discountRequest = discount.Adapt<CreateDiscountCommand>();
await _mediator.Send(discountRequest, cancellationToken);
}
else
{
var discountRequest = discount.Adapt<UpdateDiscountCommand>();
await _mediator.Send(discountRequest, cancellationToken);
}
}
return ent.AdaptToLDto();
}
}

View File

@ -14,8 +14,23 @@ public class GetProductQueryHandler : IRequestHandler<GetProductQuery, ProductLD
.Where(b => b.Id == request.Id)
.Select(ProductMapper.ProjectToLDto)
.FirstOrDefaultAsync(cancellationToken);
if (ent == null)
throw new AppException("Product not found", ApiResultStatusCode.NotFound);
var specialOffer = await _repositoryWrapper.SetRepository<ProductDiscount>()
.TableNoTracking
.Where(pd => pd.IsSpecialOffer && pd.ProductId == ent.Id)
.Select(DiscountMapper.ProjectToSDto)
.FirstOrDefaultAsync(cancellationToken);
ent.SpecialOffer = specialOffer;
if (ent.SpecialOffer == null || ent.SpecialOffer.ExpireDate.Date < DateTime.Today.Date)
ent.IsSpecialOffer = false;
else
ent.IsSpecialOffer = true;
return ent;
}
}

View File

@ -12,7 +12,7 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, List<Pr
{
var products = _repositoryWrapper.SetRepository<Product>().TableNoTracking;
if (request.ProductName != null)
products = products.Where( p => p.PersianName.ToLower().Trim().Contains(request.ProductName.ToLower().Trim()));
products = products.Where(p => p.PersianName.ToLower().Trim().Contains(request.ProductName.ToLower().Trim()));
if (request.CategoryId != default)
products = products.Where(p => p.CategoryId == request.CategoryId);
if (request.BrandId != default)
@ -62,7 +62,9 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, List<Pr
var productDiscount = await _repositoryWrapper.SetRepository<ProductDiscount>()
.TableNoTracking
.FirstOrDefaultAsync(d => d.HasCode == false && d.ProductId == productSDto.Id && d.ExpireDate.Date > DateTime.Today.Date, cancellationToken);
.Where(d => d.HasCode == false && d.ProductId == productSDto.Id && d.ExpireDate.Date > DateTime.Today.Date)
.OrderByDescending(d => d.CreatedAt)
.FirstOrDefaultAsync(cancellationToken);
if (productDiscount != null && !productDiscount.IsExpired())
{
@ -73,7 +75,10 @@ public class GetProductsQueryHandler : IRequestHandler<GetProductsQuery, List<Pr
productSDto.CostWithDiscount = productSDto.CostWithDiscount - discountPrice;
productSDto.HasDiscount = true;
productSDto.DiscountPercent = (100 * productSDto.CostWithDiscount) / productSDto.Cost;
if (productSDto.Cost > 0)
productSDto.DiscountPercent = (100 * productSDto.CostWithDiscount) / productSDto.Cost;
if (productDiscount.IsSpecialOffer)
productSDto.IsSpecial = true;
}
}

View File

@ -3,10 +3,12 @@
public class UpdateProductCommandHandler : IRequestHandler<UpdateProductCommand, bool>
{
private readonly IRepositoryWrapper _repositoryWrapper;
private readonly IMediator _mediator;
public UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper)
public UpdateProductCommandHandler(IRepositoryWrapper repositoryWrapper,IMediator mediator)
{
_repositoryWrapper = repositoryWrapper;
_mediator = mediator;
}
public async Task<bool> Handle(UpdateProductCommand request, CancellationToken cancellationToken)
{
@ -37,7 +39,6 @@ public class UpdateProductCommandHandler : IRequestHandler<UpdateProductCommand,
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
}
}
foreach (var specification in request.Specifications.Where(s => s.Id == default))
{
newEnt.AddSpecification(specification.Title, specification.Detail, specification.Value, specification.IsFeature, specification.ParentId);
@ -59,8 +60,31 @@ public class UpdateProductCommandHandler : IRequestHandler<UpdateProductCommand,
{
newEnt.AddFile(file.Name, file.FileLocation, file.FileName, file.IsHeader, file.IsPrimary, file.FileType);
}
_repositoryWrapper.SetRepository<Product>().Update(newEnt);
await _repositoryWrapper.SaveChangesAsync(cancellationToken);
if (request.IsSpecialOffer)
{
var discount = request.SpecialOffer.Adapt<DiscountLDto>();
discount.ProductId = newEnt.Id;
discount.IsSpecialOffer = true;
discount.Type = DiscountType.Product;
discount.HasCode = false;
discount.IsInfinity = true;
if (request.SpecialOffer.Id == default)
{
var discountRequest = discount.Adapt<CreateDiscountCommand>();
await _mediator.Send(discountRequest, cancellationToken);
}
else
{
var discountRequest = discount.Adapt<UpdateDiscountCommand>();
await _mediator.Send(discountRequest, cancellationToken);
}
}
return true;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace NetinaShop.Repository.Migrations
{
/// <inheritdoc />
public partial class editDiscount : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsSpecialOffer",
schema: "public",
table: "Discounts",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsSpecialOffer",
schema: "public",
table: "Discounts");
}
}
}

View File

@ -326,6 +326,9 @@ namespace NetinaShop.Repository.Migrations
b.Property<bool>("IsRemoved")
.HasColumnType("boolean");
b.Property<bool>("IsSpecialOffer")
.HasColumnType("boolean");
b.Property<DateTime>("ModifiedAt")
.HasColumnType("timestamp without time zone");

View File

@ -106,13 +106,13 @@ try
if (price != null && double.TryParse(price.meta_value, out double dPrice))
product = new CreateProductCommand(wordPressPostDto.post_title, string.Empty, wordPressPostDto.post_content,
wordPressPostDto.post_excerpt, string.Empty, string.Empty, true, dPrice, 0,
false,10, brandId, categoryId,
new List<SpecificationSDto>(), new List<StorageFileSDto>());
false,10,false,brandId, categoryId,
new DiscountSDto(),new List<SpecificationSDto>(), new List<StorageFileSDto>());
else
product = new CreateProductCommand(wordPressPostDto.post_title, string.Empty, wordPressPostDto.post_content,
wordPressPostDto.post_excerpt, string.Empty, string.Empty, true, 0, 0,false,10,
brandId,categoryId,
new List<SpecificationSDto>(), new List<StorageFileSDto>());
false,brandId,categoryId,
new DiscountSDto(),new List<SpecificationSDto>(), new List<StorageFileSDto>());
products.Add(product);
}