it's over...

This commit is contained in:
devil_1nc 2024-06-26 08:04:07 +04:00
parent 83d1365b68
commit 62372eb2a4
22 changed files with 1156 additions and 85 deletions

View File

@ -6,6 +6,7 @@ using Contracts.SearchModels;
using Contracts.StorageContracts;
using Contracts.ViewModels;
using DatabaseImplement.Implements;
using DatabaseImplement.Migrations;
using DatabaseImplement.Models;
using DataModels.Enums;
using DataModels.Models;
@ -21,12 +22,15 @@ namespace BusinessLogic.BusinessLogic
public class PurchaseLogic : IPurchaseLogic
{
private readonly IPurchaseStorage _purchaseStorage;
private readonly IProductStorage _productStorage;
private readonly ILogger _logger;
public PurchaseLogic(IPurchaseStorage purchaseStorage, ILogger<PurchaseLogic> logger)
public PurchaseLogic(IPurchaseStorage purchaseStorage, IProductStorage productStorage, ILogger<PurchaseLogic> logger)
{
_purchaseStorage = purchaseStorage;
_logger = logger;
_productStorage = productStorage;
}
public PurchaseViewModel Create(PurchaseBindingModel model)
@ -76,7 +80,7 @@ namespace BusinessLogic.BusinessLogic
public List<PurchaseViewModel> ReadElements(PurchaseSearchModel? model)
{
_logger.LogInformation("ReadList. Id: {Id}", model?.Id);
var purchase_list = _purchaseStorage.GetFullList(model);
var purchase_list = model == null ? _purchaseStorage.GetFullList(model) : _purchaseStorage.GetFilteredList(model);
if (purchase_list is null || purchase_list.Count() == 0)
{
_logger.LogWarning("ReadList return null list");
@ -99,5 +103,14 @@ namespace BusinessLogic.BusinessLogic
}
return purchase;
}
public PurchaseViewModel AddProduct(PurchaseSearchModel purchase_model, ProductSearchModel product_model, int count)
{
_purchaseStorage.AddProducts(purchase_model, product_model, count);
return _purchaseStorage.GetElement(purchase_model);
}
public Dictionary<Guid, int> GetProducts(PurchaseSearchModel model)
{
return _purchaseStorage.GetProducts(model);
}
}
}

View File

@ -14,6 +14,7 @@ namespace Contracts.BindingModels
public DateTime DatePurchase { get; set; }
public Guid UserId { get; set; }
public PurchaseStatus Status { get; set; }
public Dictionary<Guid, (IProduct, int)> PurchaseProducts { get; set; } = new();
public Dictionary<Guid, (IProduct, int)>? PurchaseProducts { get; set; } = new();
public double Cost { get; set; }
}
}

View File

@ -20,5 +20,7 @@ namespace Contracts.BusinessLogicContracts
List<PurchaseViewModel> ReadElements(PurchaseSearchModel? model);
PurchaseViewModel Delete(PurchaseSearchModel model);
PurchaseViewModel AddProduct(PurchaseSearchModel purchase, ProductSearchModel product, int count);
Dictionary<Guid, int> GetProducts(PurchaseSearchModel model);
}
}

View File

@ -13,8 +13,8 @@ namespace Contracts.SearchModels
public Guid? Id { get; set; }
public DateTime? DateFrom { get; set; }
public DateTime? DateTo { get; set; }
public double? PriceFrom { get; set; }
public double? PriceTo { get; set; }
public double? CostFrom { get; set; }
public double? CostTo { get; set; }
public PurchaseStatus? Status { get; set; }
}
}

View File

@ -21,5 +21,7 @@ namespace Contracts.StorageContracts
PurchaseViewModel? Update(PurchaseBindingModel model);
PurchaseViewModel? Delete(PurchaseSearchModel model);
PurchaseViewModel? AddProducts(PurchaseSearchModel purchaseModel, ProductSearchModel productModel, int count);
Dictionary<Guid, int> GetProducts(PurchaseSearchModel purchaseModel);
}
}

View File

@ -14,7 +14,7 @@ namespace Contracts.ViewModels
public DateTime DatePurchase { get; set; }
public required Guid UserId { get; set; }
public PurchaseStatus Status { get; set; }
public Dictionary<Guid, (IProduct, int)> PurchaseProducts { get; set; } = new();
public Dictionary<Guid, (IProduct, int)>? PurchaseProducts { get; set; } = new();
public double Cost { get; set; }
}
}

View File

@ -11,5 +11,6 @@ namespace DataModels.Models
{
DateTime DatePurchase { get; }
PurchaseStatus Status { get; }
double Cost { get; }
}
}

View File

@ -53,6 +53,59 @@ namespace DatabaseImplement.Implements
public List<PurchaseViewModel> GetFilteredList(PurchaseSearchModel? model)
{
using var context = new Database();
if (!model.CostFrom.HasValue && !model.CostTo.HasValue && !model.DateTo.HasValue && !model.DateFrom.HasValue && !model.Status.HasValue)
{
return new();
}
if (model.CostFrom.HasValue && model.CostTo.HasValue)
{
return context.Purchases
.Where(x => x.Cost <= model.CostTo && x.Cost >= model.CostFrom)
.ToList()
.Select(x => x.GetViewModel)
.ToList();
}
if (model.CostFrom.HasValue)
{
return context.Purchases
.Where(x => x.Cost >= model.CostFrom)
.ToList()
.Select(x => x.GetViewModel)
.ToList();
}
if (model.CostTo.HasValue)
{
return context.Purchases
.Where(x => x.Cost <= model.CostTo)
.ToList()
.Select(x => x.GetViewModel)
.ToList();
}
if (model.DateFrom.HasValue && model.DateTo.HasValue)
{
return context.Purchases
.Where(x => x.DatePurchase <= model.DateTo && x.DatePurchase >= model.DateFrom)
.ToList()
.Select(x => x.GetViewModel)
.ToList();
}
if (model.DateFrom.HasValue)
{
return context.Purchases
.Where(x => x.DatePurchase >= model.DateFrom)
.ToList()
.Select(x => x.GetViewModel)
.ToList();
}
if (model.DateTo.HasValue)
{
return context.Purchases
.Where(x => x.DatePurchase <= model.DateTo)
.ToList()
.Select(x => x.GetViewModel)
.ToList();
}
return context.Purchases
.Include(x => x.Products)
.ThenInclude(x => x.Product)
@ -96,5 +149,64 @@ namespace DatabaseImplement.Implements
throw;
}
}
public PurchaseViewModel? AddProducts(PurchaseSearchModel purchaseModel, ProductSearchModel productModel, int count)
{
using var context = new Database();
using var transaction = context.Database.BeginTransaction();
try
{
var purchase = context.Purchases.FirstOrDefault(rec =>
rec.Id == purchaseModel.Id);
var product = context.Products.FirstOrDefault(rec =>
rec.Id == productModel.Id);
if (purchase == null)
return null;
if (product == null)
return null;
if (count <= 0)
return null;
context.PurchaseProducts.Add(new PurchaseProducts
{
Purchase = purchase,
Product = product,
Count = count
});
context.SaveChanges();
return purchase.GetViewModel;
}
catch { transaction.Rollback(); throw; }
}
public Dictionary<Guid, int> GetProducts(PurchaseSearchModel model)
{
Dictionary<Guid, int> productsDict = new();
using var context = new Database();
var purchase = context.Purchases.FirstOrDefault(rec =>
rec.Id == model.Id);
if (purchase == null)
{
return null;
}
var purchaseProducts = context.PurchaseProducts
.Where(x => x.PurchaseId == model.Id)
.ToList();
foreach (var purchaseProduct in purchaseProducts)
{
productsDict.Add(purchaseProduct.ProductId, purchaseProduct.Count);
}
return productsDict;
}
}
}

View File

@ -0,0 +1,495 @@
// <auto-generated />
using System;
using DatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace DatabaseImplement.Migrations
{
[DbContext(typeof(Database))]
[Migration("20240625215017_purchase")]
partial class purchase
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.6")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("DatabaseImplement.Models.MediaFile", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte[]>("Image")
.IsRequired()
.HasColumnType("bytea");
b.Property<Guid>("ProductId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("ProductId");
b.ToTable("MediaFiles");
});
modelBuilder.Entity("DatabaseImplement.Models.Product", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("Amount")
.HasColumnType("integer");
b.Property<bool>("IsBeingSold")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<double>("Rate")
.HasColumnType("double precision");
b.HasKey("Id");
b.ToTable("Products");
});
modelBuilder.Entity("DatabaseImplement.Models.Purchase", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<double>("Cost")
.HasColumnType("double precision");
b.Property<DateTime>("DatePurchase")
.HasColumnType("timestamp without time zone");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Purchases");
});
modelBuilder.Entity("DatabaseImplement.Models.PurchaseProducts", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<Guid>("ProductId")
.HasColumnType("uuid");
b.Property<Guid>("PurchaseId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("ProductId");
b.HasIndex("PurchaseId");
b.ToTable("PurchaseProducts");
});
modelBuilder.Entity("DatabaseImplement.Models.Role", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Roles");
});
modelBuilder.Entity("DatabaseImplement.Models.Sell", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("DateSell")
.HasColumnType("timestamp without time zone");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Sells");
});
modelBuilder.Entity("DatabaseImplement.Models.SellProducts", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<Guid>("ProductId")
.HasColumnType("uuid");
b.Property<Guid>("SellId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("ProductId");
b.HasIndex("SellId");
b.ToTable("SellProducts");
});
modelBuilder.Entity("DatabaseImplement.Models.Supplier", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("Deals")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Suppliers");
});
modelBuilder.Entity("DatabaseImplement.Models.SupplierProduct", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<Guid>("ProductId")
.HasColumnType("uuid");
b.Property<Guid>("SupplierId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("ProductId");
b.HasIndex("SupplierId");
b.ToTable("SupplierProducts");
});
modelBuilder.Entity("DatabaseImplement.Models.Supply", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("Date")
.HasColumnType("timestamp without time zone");
b.Property<DateTime?>("DateArriving")
.HasColumnType("timestamp without time zone");
b.Property<DateTime?>("DateComplete")
.HasColumnType("timestamp without time zone");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<double>("Price")
.HasColumnType("double precision");
b.Property<int>("Status")
.HasColumnType("integer");
b.Property<Guid>("SupplierId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("SupplierId");
b.ToTable("Supplies");
});
modelBuilder.Entity("DatabaseImplement.Models.SupplyDoc", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("SupplyId")
.HasColumnType("uuid");
b.HasKey("Id");
b.ToTable("SupplyDocs");
});
modelBuilder.Entity("DatabaseImplement.Models.SupplyProduct", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<int>("Count")
.HasColumnType("integer");
b.Property<Guid>("ProductId")
.HasColumnType("uuid");
b.Property<Guid>("SupplyId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("ProductId");
b.HasIndex("SupplyId");
b.ToTable("SupplyProducts");
});
modelBuilder.Entity("DatabaseImplement.Models.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime>("Birthday")
.HasColumnType("timestamp without time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("OnlyImportantMails")
.HasColumnType("boolean");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<Guid?>("RoleId")
.HasColumnType("uuid");
b.Property<string>("SecondName")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("Users");
});
modelBuilder.Entity("DatabaseImplement.Models.MediaFile", b =>
{
b.HasOne("DatabaseImplement.Models.Product", "Product")
.WithMany()
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
});
modelBuilder.Entity("DatabaseImplement.Models.Purchase", b =>
{
b.HasOne("DatabaseImplement.Models.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("DatabaseImplement.Models.PurchaseProducts", b =>
{
b.HasOne("DatabaseImplement.Models.Product", "Product")
.WithMany("PurchaseProducts")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("DatabaseImplement.Models.Purchase", "Purchase")
.WithMany("Products")
.HasForeignKey("PurchaseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
b.Navigation("Purchase");
});
modelBuilder.Entity("DatabaseImplement.Models.Sell", b =>
{
b.HasOne("DatabaseImplement.Models.User", "User")
.WithMany()
.HasForeignKey("UserId");
b.Navigation("User");
});
modelBuilder.Entity("DatabaseImplement.Models.SellProducts", b =>
{
b.HasOne("DatabaseImplement.Models.Product", "Product")
.WithMany("SellProducts")
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("DatabaseImplement.Models.Sell", "Sell")
.WithMany("Products")
.HasForeignKey("SellId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
b.Navigation("Sell");
});
modelBuilder.Entity("DatabaseImplement.Models.SupplierProduct", b =>
{
b.HasOne("DatabaseImplement.Models.Product", "Product")
.WithMany()
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("DatabaseImplement.Models.Supplier", "Supplier")
.WithMany("Products")
.HasForeignKey("SupplierId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
b.Navigation("Supplier");
});
modelBuilder.Entity("DatabaseImplement.Models.Supply", b =>
{
b.HasOne("DatabaseImplement.Models.Supplier", "Supplier")
.WithMany()
.HasForeignKey("SupplierId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Supplier");
});
modelBuilder.Entity("DatabaseImplement.Models.SupplyProduct", b =>
{
b.HasOne("DatabaseImplement.Models.Product", "Product")
.WithMany()
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("DatabaseImplement.Models.Supply", "Supply")
.WithMany("Products")
.HasForeignKey("SupplyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Product");
b.Navigation("Supply");
});
modelBuilder.Entity("DatabaseImplement.Models.User", b =>
{
b.HasOne("DatabaseImplement.Models.Role", "Role")
.WithMany()
.HasForeignKey("RoleId");
b.Navigation("Role");
});
modelBuilder.Entity("DatabaseImplement.Models.Product", b =>
{
b.Navigation("PurchaseProducts");
b.Navigation("SellProducts");
});
modelBuilder.Entity("DatabaseImplement.Models.Purchase", b =>
{
b.Navigation("Products");
});
modelBuilder.Entity("DatabaseImplement.Models.Sell", b =>
{
b.Navigation("Products");
});
modelBuilder.Entity("DatabaseImplement.Models.Supplier", b =>
{
b.Navigation("Products");
});
modelBuilder.Entity("DatabaseImplement.Models.Supply", b =>
{
b.Navigation("Products");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,130 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace DatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class purchase : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<DateTime>(
name: "Birthday",
table: "Users",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "DateComplete",
table: "Supplies",
type: "timestamp without time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "DateArriving",
table: "Supplies",
type: "timestamp without time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "Date",
table: "Supplies",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "DateSell",
table: "Sells",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "DatePurchase",
table: "Purchases",
type: "timestamp without time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AddColumn<double>(
name: "Cost",
table: "Purchases",
type: "double precision",
nullable: false,
defaultValue: 0.0);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Cost",
table: "Purchases");
migrationBuilder.AlterColumn<DateTime>(
name: "Birthday",
table: "Users",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "DateComplete",
table: "Supplies",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "DateArriving",
table: "Supplies",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "Date",
table: "Supplies",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "DateSell",
table: "Sells",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
migrationBuilder.AlterColumn<DateTime>(
name: "DatePurchase",
table: "Purchases",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp without time zone");
}
}
}

View File

@ -75,8 +75,11 @@ namespace DatabaseImplement.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<double>("Cost")
.HasColumnType("double precision");
b.Property<DateTime>("DatePurchase")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp without time zone");
b.Property<int>("Status")
.HasColumnType("integer");
@ -137,7 +140,7 @@ namespace DatabaseImplement.Migrations
.HasColumnType("uuid");
b.Property<DateTime>("DateSell")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp without time zone");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
@ -222,13 +225,13 @@ namespace DatabaseImplement.Migrations
.HasColumnType("uuid");
b.Property<DateTime>("Date")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp without time zone");
b.Property<DateTime?>("DateArriving")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp without time zone");
b.Property<DateTime?>("DateComplete")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp without time zone");
b.Property<string>("Name")
.IsRequired()
@ -299,7 +302,7 @@ namespace DatabaseImplement.Migrations
.HasColumnType("uuid");
b.Property<DateTime>("Birthday")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp without time zone");
b.Property<string>("Email")
.IsRequired()

View File

@ -23,6 +23,7 @@ namespace DatabaseImplement.Models
public DateTime DatePurchase { get; set; }
[Required]
public Guid UserId { get; set; }
public double Cost { get; set; }
[Required]
public PurchaseStatus Status { get; private set; } = PurchaseStatus.Unknown;
private Dictionary<Guid, (IProduct, int)>? _purchaseProducts = null;
@ -59,7 +60,8 @@ namespace DatabaseImplement.Models
DatePurchase = DatePurchase,
UserId = UserId,
PurchaseProducts = PurchaseProducts,
Status = Status
Status = Status,
Cost = Cost
};
public PurchaseViewModel GetViewModel => new()
@ -68,7 +70,8 @@ namespace DatabaseImplement.Models
DatePurchase = DatePurchase,
UserId = UserId,
PurchaseProducts = PurchaseProducts,
Status = Status
Status = Status,
Cost = Cost
};
public static Purchase ToPurchaseFromView(PurchaseViewModel model, Purchase purchase) => new()
@ -77,7 +80,8 @@ namespace DatabaseImplement.Models
DatePurchase = model.DatePurchase,
UserId = model.UserId,
PurchaseProducts = model.PurchaseProducts,
Status = model.Status
Status = model.Status,
Cost = model.Cost
};
public static Purchase ToPurchaseFromBinding(PurchaseBindingModel model, Purchase purchase) => new()
@ -86,7 +90,8 @@ namespace DatabaseImplement.Models
DatePurchase = model.DatePurchase,
UserId = model.UserId,
PurchaseProducts = model.PurchaseProducts,
Status = model.Status
Status = model.Status,
Cost = model.Cost
};
public void Update(PurchaseBindingModel model)
@ -100,6 +105,8 @@ namespace DatabaseImplement.Models
UserId = model.UserId;
PurchaseProducts = model.PurchaseProducts;
Status = model.Status;
Cost = model.Cost;
}
public void UpdateProducts(Database context, PurchaseBindingModel model)
{

View File

@ -15,7 +15,7 @@ namespace RestAPI.Controllers
private readonly IMediaFileLogic _mediaFileLogic;
private readonly IProductLogic _productLogic;
private readonly ILogger _logger;
public MediaFileController(ILogger<MediaFileLogic> logger, IMediaFileLogic mediaFileLogic, IProductLogic productLogic)
public MediaFileController(ILogger<MediaFileController> logger, IMediaFileLogic mediaFileLogic, IProductLogic productLogic)
{
_logger = logger;
_mediaFileLogic = mediaFileLogic;

View File

@ -44,6 +44,20 @@ namespace RestAPI.Controllers
}
}
[HttpGet]
public ProductViewModel GetProduct(Guid id)
{
try
{
return _product.ReadElement(new ProductSearchModel() {Id = id});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения продукта");
throw;
}
}
[HttpPatch]
public IResult Update([FromBody] ProductBindingModel model)
{

View File

@ -1,83 +1,152 @@
using Microsoft.AspNetCore.Http;
using BusinessLogic.BusinessLogic;
using Contracts.BindingModels;
using Contracts.BusinessLogicContracts;
using Contracts.Exceptions;
using Contracts.SearchModels;
using Contracts.ViewModels;
using DatabaseImplement.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace RestAPI.Controllers
{
[Route("[controller]/[action]")]
[ApiController]
public class PurchaseController : Controller
{
// GET: PurchaseController
public ActionResult Index()
{
return View();
}
private readonly ILogger _logger;
private readonly IPurchaseLogic _purchaseLogic;
// GET: PurchaseController/Details/5
public ActionResult Details(int id)
public PurchaseController(ILogger<PurchaseController> logger, IPurchaseLogic purchaseLogic)
{
return View();
_logger = logger;
_purchaseLogic = purchaseLogic;
}
// GET: PurchaseController/Create
public ActionResult Create()
{
return View();
}
// POST: PurchaseController/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(IFormCollection collection)
[HttpGet]
public List<PurchaseViewModel>? GetList(double? costfrom, double? costto, DateTime? datefrom, DateTime? dateto)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
if (costfrom == null && costto == null && datefrom == null && dateto == null)
return _purchaseLogic.ReadElements(null);
else
return _purchaseLogic.ReadElements(new PurchaseSearchModel()
{
return View();
CostFrom = costfrom,
CostTo = costto,
DateFrom = datefrom,
DateTo = dateto
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка получения списка продуктов");
throw;
}
}
// GET: PurchaseController/Edit/5
public ActionResult Edit(int id)
{
return View();
}
// POST: PurchaseController/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, IFormCollection collection)
[HttpGet]
public PurchaseViewModel Get(Guid id)
{
try
{
return RedirectToAction(nameof(Index));
return _purchaseLogic.ReadElement(new PurchaseSearchModel() { Id = id });
}
catch
catch (Exception ex)
{
return View();
_logger.LogError(ex, "Ошибка получения продукта");
throw;
}
}
// GET: PurchaseController/Delete/5
public ActionResult Delete(int id)
{
return View();
}
// POST: PurchaseController/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id, IFormCollection collection)
public PurchaseViewModel Create(Guid UserId)
{
try
{
return RedirectToAction(nameof(Index));
}
catch
var purchase = _purchaseLogic.Create(new PurchaseBindingModel()
{
return View();
}
Cost = 0,
DatePurchase = DateTime.Now,
UserId = UserId
});
return new PurchaseViewModel()
{
DatePurchase = purchase.DatePurchase,
UserId = purchase.UserId,
Cost = purchase.Cost,
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Error update purchase");
return null;
}
}
[HttpPatch]
public PurchaseViewModel Update([FromBody] PurchaseBindingModel model)
{
try
{
var res = _purchaseLogic.Update(model);
return new PurchaseViewModel()
{
Id = res.Id,
Cost = res.Cost,
DatePurchase = res.DatePurchase,
PurchaseProducts = res.PurchaseProducts,
UserId = res.UserId,
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Error update purchase");
return null;
}
}
[HttpPatch]
public PurchaseViewModel AddProducts(Guid purchaseId, Guid productId, int count)
{
try
{
var purchase = _purchaseLogic.AddProduct(
new PurchaseSearchModel()
{
Id = purchaseId
},
new ProductSearchModel()
{
Id = productId
},
count);
return new PurchaseViewModel()
{
Id = purchase.Id,
Cost = purchase.Cost,
DatePurchase = purchase.DatePurchase,
PurchaseProducts = purchase.PurchaseProducts,
UserId = purchase.UserId,
};
}
catch (Exception ex)
{
_logger.LogError(ex, "Error update purchase");
return null;
}
}
[HttpGet]
public Dictionary<Guid, int> GetProducts(Guid productId)
{
return _purchaseLogic.GetProducts(new PurchaseSearchModel
{
Id = productId,
});
}
}
}

View File

@ -1,4 +1,56 @@
@page
@model WebApp.Pages.CartModel
@{
ViewData["Title"] = "Cart";
}
<div class="container my-5">
<h1>Корзина</h1>
@* @if (Model.Amount == 0)
{
<p>Ваша корзина пуста.</p>
} *@
else
{
<table class="table">
<thead>
<tr>
<th>Товар</th>
<th>Цена</th>
<th>Количество</th>
<th>Итого</th>
<th></th>
</tr>
</thead>
<tbody>
@* @foreach (var item in Model.CartItems)
{
<tr>
<td>
<div class="d-flex align-items-center">
<img src="data:image/png;base64,@Convert.ToBase64String(Model.GetMediaByProduct(item.Product))" class="img-fluid me-3" style="max-height: 50px;" alt="@item.Product.Name">
<a asp-page="ProductDetails" asp-route-id="@item.Product.Id">@item.Product.Name</a>
</div>
</td>
<td>@item.Product.Price.ToString("C")</td>
<td>
<input type="number" class="form-control" value="@item.Quantity" min="1" max="100" onchange="updateCartItem('@item.Product.Id', this.value)">
</td>
<td>@((item.Product.Price * item.Quantity).ToString("C"))</td>
<td>
<button class="btn btn-danger" onclick="removeFromCart('@item.Product.Id')">Удалить</button>
</td>
</tr>
} *@
</tbody>
</table>
<div class="d-flex justify-content-end">
@* <h3>Итого: @Model.TotalPrice.ToString("C")</h3> *@
</div>
<div class="d-flex justify-content-end">
<a asp-page="Checkout" class="btn btn-primary">Оформить заказ</a>
</div>
}
</div>

View File

@ -1,13 +1,35 @@
using Contracts.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Diagnostics.Eventing.Reader;
using WebApp.Helpers;
namespace WebApp.Pages
{
[Authorize(Roles = Roles.User)]
public class CartModel : PageModel
{
public void OnGet()
public PurchaseViewModel purchaseModel = null;
public Dictionary<Guid, int> Products { get; set; }
public void OnGet(Guid id, int count)
{
if (purchaseModel == null)
{
purchaseModel = APIClient.GetRequest<PurchaseViewModel>($"Purchase/Create/{this.GetUserId()}");
APIClient.GetRequest<PurchaseViewModel>($"Purchase/AddProducts?purchaseId={purchaseModel.Id}?productId={id}?count={count}");
}
purchaseModel = APIClient.GetRequest<PurchaseViewModel>($"Purchase/Get/");
Products = APIClient.GetRequest<Dictionary<Guid, int>>($"Purchase/GetProducts?id={purchaseModel.Id}");
}
public IActionResult OnPostAsync()
{
return RedirectToAction("");
}
}
}

View File

@ -7,7 +7,7 @@
<!-- Шапка -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="#">Catalog</a>
<a asp-page="Index" class="navbar-brand">Catalog</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
@ -31,12 +31,12 @@
</form>
<div class="form-group ms-3">
<div class="d-flex align-items-center">
<input type="range" step="1000" min="0" max="10000" value="" class="custom-range me-2" id="priceFrom">
<label for="priceFrom">От: <span id="priceLabelFrom">50 000</span> руб.</label>
<input type="range" step="1" min="0" max="100" value="" class="custom-range me-2" id="priceFrom">
<label asp-for="ProductsModel" s for="pricefrom">От: <span id="priceLabelFrom"></span> руб.</label>
</div>
<div class="d-flex align-items-center">
<input type="range" step="1000" min="0" max="100000" value="" class="custom-range me-2" id="priceTo">
<label for="priceTo">До: <span id="priceLabelTo">50 000</span> руб.</label>
<input type="range" step="1" min="0" max="100" value="" class="custom-range me-2" id="priceTo">
<label asp-for="ProductsModel" for="priceto">До: <span id="priceLabelTo"></span> руб.</label>
</div>
</div>
</div>
@ -54,8 +54,31 @@
<div class="card-body">
<h5 class="card-title">@weapon.Name</h5>
<p class="card-text">Цена: @weapon.Price руб.</p>
<a href="#" class="btn btn-primary">В корзину</a>
<a href="#" class="btn btn-secondary">Просмотр</a>
<div class="star-rating">
@for (int i = 0; i < (int)Math.Round(@weapon.Rate); i++)
{
<span class="filled-star">&#9733;</span>
}
@for (int i = 0; i < 5 - (int)Math.Round(@weapon.Rate); i++)
{
<span class="empty-star">&#9733;</span>
}
(@weapon.Rate)
</div>
@if (User.Identity.IsAuthenticated)
{
<a asp-page="Cart" asp-route-id="@weapon.Id" asp-route-count=1 class="btn btn-primary">To cart</a>
}
else
{
<a asp-page="Login" asp-route-count=1 class="btn btn-primary">To cart</a>
}
<a asp-page="ProductPage" asp-route-id="@weapon.Id" class="btn btn-secondary">View Product</a>
</div>
</div>
</div>

View File

@ -25,7 +25,7 @@ namespace WebApp.Pages
request += $"?priceto={priceto}";
ProductsModel = APIClient.GetRequest<List<ProductViewModel>>(request);
MediaByProductsModel = APIClient.GetRequest<Dictionary<Guid, List<MediaFileViewModel>>>($"MediaFile/GetByProducts?");
MediaByProductsModel = APIClient.GetRequest<Dictionary<Guid, List<MediaFileViewModel>>>($"MediaFile/GetByProducts");
}
public byte[] GetMediaByProduct(ProductViewModel productModel)
{

View File

@ -0,0 +1,69 @@
@page
@model WebApp.Pages.ProductPageModel
@{
ViewData["Title"] = "Product Page";
}
<!-- Шапка -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a asp-page="Index" class="navbar-brand">Catalog</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<div class="container my-5">
<div class="row">
<div class="col-md-6">
<img src="data:image/png;base64,@Convert.ToBase64String(Model.GetMediaByProduct(Model.productModel))" class="img-fluid" alt="@Model.productModel.Name">
</div>
<div class="col-md-6">
<h1>@Model.productModel.Name</h1>
<div class="star-rating">
@for (int i = 0; i < (int)Math.Round(@Model.productModel.Rate); i++)
{
<span class="filled-star">&#9733;</span>
}
@for (int i = 0; i < 5 - (int)Math.Round(@Model.productModel.Rate); i++)
{
<span class="empty-star">&#9733;</span>
}
(@Model.productModel.Rate)
</div>
<p class="lead">Цена: @Model.productModel.Price руб.</p>
<p>Количество товара на складе: @Model.productModel.Amount</p>
@if (User.Identity.IsAuthenticated)
{
<form method="post">
<div class="d-flex align-items-center mb-3">
<input type="hidden" name="id" value="@Model.productModel.Id" />
<input type="number" name="count" min="1" max="@Model.productModel.Amount" value="1" class="form-control w-auto" />
<button type="submit" class="btn btn-primary me-2">В корзину</button>
</div>
</form>
}
else
{
<div class="d-flex align-items-center mb-3">
<label for="quantity" class="me-2">Количество:</label>
<input type="number" id="quantity" name="quantity" min="1" max="@Model.productModel.Amount" value="1" class="form-control w-auto">
</div>
<a asp-page="Login" class="btn btn-primary me-2">
В корзину
</a>
}
<button class="btn btn-secondary">Купить сейчас</button>
</div>
</div>
<div class="row mt-5">
<div class="col">
<h2>Описание</h2>
<p>@Model.productModel.Amount</p>
</div>
</div>
</div>

View File

@ -0,0 +1,43 @@
using Contracts.BindingModels;
using Contracts.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace WebApp.Pages
{
public class ProductPageModel : PageModel
{
public PurchaseViewModel purchaseModel { get; set; }
public ProductViewModel productModel { get; set; }
public MediaFileViewModel mediaFileModel { get; set; }
public Dictionary<Guid, List<MediaFileViewModel>> MediaByProductsModel { get; set; }
public int Amount { get; set; } // Ñâîéñòâî äëÿ õðàíåíèÿ êîëè÷åñòâà òîâàðà
public void OnGet(Guid id)
{
productModel = APIClient.GetRequest<ProductViewModel>($"Product/GetProduct?id={id}");
}
public byte[] GetMediaByProduct(ProductViewModel productModel)
{
MediaByProductsModel = APIClient.GetRequest<Dictionary<Guid, List<MediaFileViewModel>>>($"MediaFile/GetByProducts");
MediaByProductsModel.TryGetValue(productModel.Id, out List<MediaFileViewModel> models);
return models[0].Image;
}
public IActionResult OnPostAsync(Guid id, int count)
{
Amount = count;
if (purchaseModel == null)
{
var model = new PurchaseBindingModel()
{
Cost = 0,
DatePurchase = DateTime.Now,
Status = 0,
UserId = new Guid(this.GetUserId())
};
//purchaseModel = APIClient.PostRequest<PurchaseBindingModel>($"Purchase/Create", model);
}
APIClient.GetRequest<PurchaseViewModel>($"Purchase/AddProducts?purchaseId={purchaseModel.Id}?productId={id}?count={count}");
return RedirectToPage("Cart");
}
}
}

View File

@ -1,4 +1,4 @@
html {
html {
font-size: 14px;
}
@ -26,3 +26,16 @@ body {
width: 100%;
object-fit: cover;
}
.star-rating span {
font-size: 20px;
margin-right: 10px;
}
.filled-star {
color: gold;
}
.empty-star {
color: gray;
}