sonderangebot artikel
This commit is contained in:
@@ -49,5 +49,15 @@ namespace Webshop.Api.Controllers.Public
|
|||||||
|
|
||||||
return Ok(product);
|
return Ok(product);
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Ruft eine Liste der Sonderangebote f<>r die Startseite ab, sortiert nach Anzeigereihenfolge.
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("featured")]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<ProductDto>), 200)]
|
||||||
|
public async Task<ActionResult<IEnumerable<ProductDto>>> GetFeaturedProducts()
|
||||||
|
{
|
||||||
|
var products = await _productService.GetFeaturedProductsAsync();
|
||||||
|
return Ok(products);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,13 +16,16 @@ namespace Webshop.Application.DTOs.Products
|
|||||||
public bool IsInStock { get; set; } = true;
|
public bool IsInStock { get; set; } = true;
|
||||||
public int StockQuantity { get; set; }
|
public int StockQuantity { get; set; }
|
||||||
public decimal? Weight { get; set; }
|
public decimal? Weight { get; set; }
|
||||||
// << ENTFERNT: ImageUrl >>
|
|
||||||
public string Slug { get; set; } = string.Empty;
|
public string Slug { get; set; } = string.Empty;
|
||||||
public DateTimeOffset CreatedDate { get; set; } = DateTimeOffset.UtcNow;
|
public DateTimeOffset CreatedDate { get; set; } = DateTimeOffset.UtcNow;
|
||||||
public DateTimeOffset? LastModifiedDate { get; set; }
|
public DateTimeOffset? LastModifiedDate { get; set; }
|
||||||
public Guid? SupplierId { get; set; }
|
public Guid? SupplierId { get; set; }
|
||||||
public decimal? PurchasePrice { get; set; }
|
public decimal? PurchasePrice { get; set; }
|
||||||
public List<Guid> categorieIds { get; set; } = new List<Guid>();
|
public List<Guid> categorieIds { get; set; } = new List<Guid>();
|
||||||
public List<ProductImageDto> Images { get; set; } = new List<ProductImageDto>(); // << NEU >>
|
public List<ProductImageDto> Images { get; set; } = new List<ProductImageDto>();
|
||||||
|
|
||||||
|
// << NEU >>
|
||||||
|
public bool IsFeatured { get; set; }
|
||||||
|
public int FeaturedDisplayOrder { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,5 +30,8 @@ namespace Webshop.Application.DTOs.Products
|
|||||||
public decimal? OldPrice { get; set; }
|
public decimal? OldPrice { get; set; }
|
||||||
public Guid? SupplierId { get; set; }
|
public Guid? SupplierId { get; set; }
|
||||||
public decimal? PurchasePrice { get; set; }
|
public decimal? PurchasePrice { get; set; }
|
||||||
|
|
||||||
|
public bool IsFeatured { get; set; } = false;
|
||||||
|
public int FeaturedDisplayOrder { get; set; } = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,5 +33,7 @@ namespace Webshop.Application.DTOs.Products
|
|||||||
public decimal? OldPrice { get; set; }
|
public decimal? OldPrice { get; set; }
|
||||||
public Guid? SupplierId { get; set; }
|
public Guid? SupplierId { get; set; }
|
||||||
public decimal? PurchasePrice { get; set; }
|
public decimal? PurchasePrice { get; set; }
|
||||||
|
public bool IsFeatured { get; set; }
|
||||||
|
public int FeaturedDisplayOrder { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,6 +137,8 @@ namespace Webshop.Application.Services.Admin
|
|||||||
OldPrice = productDto.OldPrice,
|
OldPrice = productDto.OldPrice,
|
||||||
SupplierId = productDto.SupplierId,
|
SupplierId = productDto.SupplierId,
|
||||||
PurchasePrice = productDto.PurchasePrice,
|
PurchasePrice = productDto.PurchasePrice,
|
||||||
|
IsFeatured = productDto.IsFeatured, // << NEU >>
|
||||||
|
FeaturedDisplayOrder = productDto.FeaturedDisplayOrder, // << NEU >>
|
||||||
Images = images,
|
Images = images,
|
||||||
Productcategories = productDto.CategorieIds.Select(cId => new Productcategorie { categorieId = cId }).ToList()
|
Productcategories = productDto.CategorieIds.Select(cId => new Productcategorie { categorieId = cId }).ToList()
|
||||||
};
|
};
|
||||||
@@ -196,6 +198,8 @@ namespace Webshop.Application.Services.Admin
|
|||||||
existingProduct.SupplierId = productDto.SupplierId;
|
existingProduct.SupplierId = productDto.SupplierId;
|
||||||
existingProduct.PurchasePrice = productDto.PurchasePrice;
|
existingProduct.PurchasePrice = productDto.PurchasePrice;
|
||||||
existingProduct.LastModifiedDate = DateTimeOffset.UtcNow;
|
existingProduct.LastModifiedDate = DateTimeOffset.UtcNow;
|
||||||
|
existingProduct.IsFeatured = productDto.IsFeatured; // << NEU >>
|
||||||
|
existingProduct.FeaturedDisplayOrder = productDto.FeaturedDisplayOrder; // << NEU >>
|
||||||
|
|
||||||
// Kategorien synchronisieren
|
// Kategorien synchronisieren
|
||||||
existingProduct.Productcategories.Clear();
|
existingProduct.Productcategories.Clear();
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ namespace Webshop.Application.Services.Public.Interfaces
|
|||||||
Task<IEnumerable<ProductDto>> GetAllProductsAsync();
|
Task<IEnumerable<ProductDto>> GetAllProductsAsync();
|
||||||
|
|
||||||
Task<ProductDto?> GetProductBySlugAsync(string slug);
|
Task<ProductDto?> GetProductBySlugAsync(string slug);
|
||||||
|
Task<IEnumerable<ProductDto>> GetFeaturedProductsAsync(); // << NEU >>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,5 +89,42 @@ namespace Webshop.Application.Services.Public
|
|||||||
}).ToList()
|
}).ToList()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<ProductDto>> GetFeaturedProductsAsync()
|
||||||
|
{
|
||||||
|
var products = await _context.Products
|
||||||
|
.Where(p => p.IsActive && p.IsFeatured)
|
||||||
|
.OrderBy(p => p.FeaturedDisplayOrder)
|
||||||
|
.Include(p => p.Images)
|
||||||
|
.Include(p => p.Productcategories).ThenInclude(pc => pc.categorie)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
return products.Select(p => new ProductDto
|
||||||
|
{
|
||||||
|
Id = p.Id,
|
||||||
|
Name = p.Name,
|
||||||
|
Description = p.ShortDescription, // F<>r die Startseite ist die Kurzbeschreibung ideal
|
||||||
|
SKU = p.SKU,
|
||||||
|
Price = p.Price,
|
||||||
|
IsActive = p.IsActive,
|
||||||
|
IsInStock = p.IsInStock,
|
||||||
|
StockQuantity = p.StockQuantity,
|
||||||
|
Slug = p.Slug,
|
||||||
|
categories = p.Productcategories.Select(pc => new CategorieDto
|
||||||
|
{
|
||||||
|
Id = pc.categorie.Id,
|
||||||
|
Name = pc.categorie.Name,
|
||||||
|
Slug = pc.categorie.Slug
|
||||||
|
}).ToList(),
|
||||||
|
Images = p.Images.OrderBy(i => i.DisplayOrder).Select(img => new ProductImageDto
|
||||||
|
{
|
||||||
|
Id = img.Id,
|
||||||
|
Url = img.Url,
|
||||||
|
IsMainImage = img.IsMainImage,
|
||||||
|
DisplayOrder = img.DisplayOrder
|
||||||
|
}).ToList()
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,9 +33,6 @@ namespace Webshop.Domain.Entities
|
|||||||
public decimal? Height { get; set; }
|
public decimal? Height { get; set; }
|
||||||
public decimal? Length { get; set; }
|
public decimal? Length { get; set; }
|
||||||
|
|
||||||
// << ENTFERNT: ImageUrl wird durch Images ersetzt >>
|
|
||||||
// public string? ImageUrl { get; set; }
|
|
||||||
|
|
||||||
[Required, MaxLength(255)]
|
[Required, MaxLength(255)]
|
||||||
public string Slug { get; set; } = string.Empty;
|
public string Slug { get; set; } = string.Empty;
|
||||||
[Required]
|
[Required]
|
||||||
@@ -45,13 +42,16 @@ namespace Webshop.Domain.Entities
|
|||||||
public Guid? SupplierId { get; set; }
|
public Guid? SupplierId { get; set; }
|
||||||
public decimal? PurchasePrice { get; set; }
|
public decimal? PurchasePrice { get; set; }
|
||||||
|
|
||||||
|
// << NEUE EIGENSCHAFTEN FÜR SONDERANGEBOTE >>
|
||||||
|
public bool IsFeatured { get; set; } = false;
|
||||||
|
public int FeaturedDisplayOrder { get; set; } = 0;
|
||||||
|
// << ENDE NEUE EIGENSCHAFTEN >>
|
||||||
|
|
||||||
public virtual Supplier? Supplier { get; set; }
|
public virtual Supplier? Supplier { get; set; }
|
||||||
public virtual ICollection<ProductVariant> Variants { get; set; } = new List<ProductVariant>();
|
public virtual ICollection<ProductVariant> Variants { get; set; } = new List<ProductVariant>();
|
||||||
public virtual ICollection<Review> Reviews { get; set; } = new List<Review>();
|
public virtual ICollection<Review> Reviews { get; set; } = new List<Review>();
|
||||||
public virtual ICollection<ProductDiscount> ProductDiscounts { get; set; } = new List<ProductDiscount>();
|
public virtual ICollection<ProductDiscount> ProductDiscounts { get; set; } = new List<ProductDiscount>();
|
||||||
public virtual ICollection<Productcategorie> Productcategories { get; set; } = new List<Productcategorie>();
|
public virtual ICollection<Productcategorie> Productcategories { get; set; } = new List<Productcategorie>();
|
||||||
|
|
||||||
// << NEU: Navigation Property zu Bildern >>
|
|
||||||
public virtual ICollection<ProductImage> Images { get; set; } = new List<ProductImage>();
|
public virtual ICollection<ProductImage> Images { get; set; } = new List<ProductImage>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,8 +12,8 @@ using Webshop.Infrastructure.Data;
|
|||||||
namespace Webshop.Infrastructure.Migrations
|
namespace Webshop.Infrastructure.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(ApplicationDbContext))]
|
[DbContext(typeof(ApplicationDbContext))]
|
||||||
[Migration("20250812113218_checkout")]
|
[Migration("20250812123244_featureartikel")]
|
||||||
partial class checkout
|
partial class featureartikel
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
@@ -576,6 +576,9 @@ namespace Webshop.Infrastructure.Migrations
|
|||||||
.HasMaxLength(4000)
|
.HasMaxLength(4000)
|
||||||
.HasColumnType("character varying(4000)");
|
.HasColumnType("character varying(4000)");
|
||||||
|
|
||||||
|
b.Property<int>("FeaturedDisplayOrder")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
b.Property<decimal?>("Height")
|
b.Property<decimal?>("Height")
|
||||||
.HasPrecision(18, 2)
|
.HasPrecision(18, 2)
|
||||||
.HasColumnType("numeric(18,2)");
|
.HasColumnType("numeric(18,2)");
|
||||||
@@ -583,6 +586,9 @@ namespace Webshop.Infrastructure.Migrations
|
|||||||
b.Property<bool>("IsActive")
|
b.Property<bool>("IsActive")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("IsFeatured")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
b.Property<bool>("IsInStock")
|
b.Property<bool>("IsInStock")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||||||
namespace Webshop.Infrastructure.Migrations
|
namespace Webshop.Infrastructure.Migrations
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class checkout : Migration
|
public partial class featureartikel : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
@@ -460,7 +460,9 @@ namespace Webshop.Infrastructure.Migrations
|
|||||||
CreatedDate = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
CreatedDate = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
|
||||||
LastModifiedDate = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
LastModifiedDate = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
||||||
SupplierId = table.Column<Guid>(type: "uuid", nullable: true),
|
SupplierId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||||
PurchasePrice = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: true)
|
PurchasePrice = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: true),
|
||||||
|
IsFeatured = table.Column<bool>(type: "boolean", nullable: false),
|
||||||
|
FeaturedDisplayOrder = table.Column<int>(type: "integer", nullable: false)
|
||||||
},
|
},
|
||||||
constraints: table =>
|
constraints: table =>
|
||||||
{
|
{
|
||||||
@@ -573,6 +573,9 @@ namespace Webshop.Infrastructure.Migrations
|
|||||||
.HasMaxLength(4000)
|
.HasMaxLength(4000)
|
||||||
.HasColumnType("character varying(4000)");
|
.HasColumnType("character varying(4000)");
|
||||||
|
|
||||||
|
b.Property<int>("FeaturedDisplayOrder")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
b.Property<decimal?>("Height")
|
b.Property<decimal?>("Height")
|
||||||
.HasPrecision(18, 2)
|
.HasPrecision(18, 2)
|
||||||
.HasColumnType("numeric(18,2)");
|
.HasColumnType("numeric(18,2)");
|
||||||
@@ -580,6 +583,9 @@ namespace Webshop.Infrastructure.Migrations
|
|||||||
b.Property<bool>("IsActive")
|
b.Property<bool>("IsActive")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
b.Property<bool>("IsFeatured")
|
||||||
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
b.Property<bool>("IsInStock")
|
b.Property<bool>("IsInStock")
|
||||||
.HasColumnType("boolean");
|
.HasColumnType("boolean");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user