diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 0000000..c74e6db --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,31 @@ +# This workflow will build a .NET project +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net + +name: .NET + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + - name: Restore dependencies + run: dotnet restore + working-directory: Reverse-Analytics + - name: Build + run: dotnet build --no-restore + working-directory: Reverse-Analytics + - name: Test + run: dotnet test --no-build --verbosity normal + working-directory: Reverse-Analytics diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240317223310_Initial_Create.Designer.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240317223310_Initial_Create.Designer.cs new file mode 100644 index 0000000..c08cc96 --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240317223310_Initial_Create.Designer.cs @@ -0,0 +1,649 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using ReverseAnalytics.Infrastructure.Persistence; + +#nullable disable + +namespace ReverseAnalytics.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20240317223310_Initial_Create")] + partial class Initial_Create + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Company") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("float(18)") + .HasDefaultValue(0.0); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Customer", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SalePrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("SupplyPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("int"); + + b.Property("Volume") + .HasPrecision(18, 2) + .HasColumnType("float(18)"); + + b.Property("Weight") + .HasPrecision(18, 2) + .HasColumnType("float(18)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("Product", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ParentId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("ProductCategory", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Currency") + .HasColumnType("int"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("SaleType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TotalDiscount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.ToTable("Sale", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)") + .HasDefaultValue(0m); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SaleId") + .HasColumnType("int"); + + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("SaleId"); + + b.ToTable("SaleItem", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Company") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Supplier", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Currency") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("SupplierId") + .HasColumnType("int"); + + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Supply", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SupplyId") + .HasColumnType("int"); + + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("SupplyId"); + + b.ToTable("SupplyItem", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Transaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("SourceId") + .IsRequired() + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Category") + .WithMany("Products") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Parent") + .WithMany("SubCategories") + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Customer", "Customer") + .WithMany("Sales") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") + .WithMany("SaleItems") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ReverseAnalytics.Domain.Entities.Sale", "Sale") + .WithMany("SaleItems") + .HasForeignKey("SaleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Sale"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Supplier", "Supplier") + .WithMany("Supplies") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") + .WithMany("SupplyItems") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ReverseAnalytics.Domain.Entities.Supply", "Supply") + .WithMany("SupplyItems") + .HasForeignKey("SupplyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Supply"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => + { + b.Navigation("Sales"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.Navigation("SaleItems"); + + b.Navigation("SupplyItems"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.Navigation("Products"); + + b.Navigation("SubCategories"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.Navigation("SaleItems"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => + { + b.Navigation("Supplies"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.Navigation("SupplyItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240317223310_Initial_Create.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240317223310_Initial_Create.cs new file mode 100644 index 0000000..c82d46e --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240317223310_Initial_Create.cs @@ -0,0 +1,350 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ReverseAnalytics.Infrastructure.Persistence.Migrations +{ + /// + public partial class Initial_Create : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Customer", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FirstName = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + LastName = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: true), + PhoneNumber = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Address = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), + Company = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), + Balance = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + Discount = table.Column(type: "float(18)", precision: 18, scale: 2, nullable: false, defaultValue: 0.0), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Customer", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "ProductCategory", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + Description = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: false), + ParentId = table.Column(type: "int", nullable: true), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProductCategory", x => x.Id); + table.ForeignKey( + name: "FK_ProductCategory_ProductCategory_ParentId", + column: x => x.ParentId, + principalTable: "ProductCategory", + principalColumn: "Id"); + }); + + migrationBuilder.CreateTable( + name: "Supplier", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FirstName = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + LastName = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: true), + PhoneNumber = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false), + Company = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), + Balance = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Supplier", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Transaction", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Date = table.Column(type: "datetime2", nullable: false), + SourceId = table.Column(type: "int", nullable: false), + Amount = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + Type = table.Column(type: "int", nullable: false), + Source = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Transaction", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Sale", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Date = table.Column(type: "datetime2", nullable: false), + Comments = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), + TotalDue = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + TotalPaid = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + TotalDiscount = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + SaleType = table.Column(type: "int", nullable: false), + Status = table.Column(type: "int", nullable: false), + PaymentType = table.Column(type: "int", nullable: false), + Currency = table.Column(type: "int", nullable: false), + CustomerId = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Sale", x => x.Id); + table.ForeignKey( + name: "FK_Sale_Customer_CustomerId", + column: x => x.CustomerId, + principalTable: "Customer", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Product", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Name = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + Code = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + Description = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), + SalePrice = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + SupplyPrice = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + Volume = table.Column(type: "float(18)", precision: 18, scale: 2, nullable: true), + Weight = table.Column(type: "float(18)", precision: 18, scale: 2, nullable: true), + UnitOfMeasurement = table.Column(type: "int", nullable: false), + CategoryId = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Product", x => x.Id); + table.ForeignKey( + name: "FK_Product_ProductCategory_CategoryId", + column: x => x.CategoryId, + principalTable: "ProductCategory", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Supply", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Date = table.Column(type: "datetime2", nullable: false), + Comments = table.Column(type: "nvarchar(4000)", maxLength: 4000, nullable: true), + TotalDue = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + TotalPaid = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + PaymentType = table.Column(type: "int", nullable: false), + Currency = table.Column(type: "int", nullable: false), + SupplierId = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Supply", x => x.Id); + table.ForeignKey( + name: "FK_Supply_Supplier_SupplierId", + column: x => x.SupplierId, + principalTable: "Supplier", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SaleItem", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Quantity = table.Column(type: "int", nullable: false), + UnitPrice = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + Discount = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false, defaultValue: 0m), + SaleId = table.Column(type: "int", nullable: false), + ProductId = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_SaleItem", x => x.Id); + table.ForeignKey( + name: "FK_SaleItem_Product_ProductId", + column: x => x.ProductId, + principalTable: "Product", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_SaleItem_Sale_SaleId", + column: x => x.SaleId, + principalTable: "Sale", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "SupplyItem", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Quantity = table.Column(type: "int", nullable: false), + UnitPrice = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false), + SupplyId = table.Column(type: "int", nullable: false), + ProductId = table.Column(type: "int", nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + LastModifiedAt = table.Column(type: "datetime2", nullable: true), + CreatedBy = table.Column(type: "nvarchar(max)", nullable: true), + LastModifiedBy = table.Column(type: "nvarchar(max)", nullable: true), + CreatedById = table.Column(type: "int", nullable: true), + LastModifiedById = table.Column(type: "int", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_SupplyItem", x => x.Id); + table.ForeignKey( + name: "FK_SupplyItem_Product_ProductId", + column: x => x.ProductId, + principalTable: "Product", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_SupplyItem_Supply_SupplyId", + column: x => x.SupplyId, + principalTable: "Supply", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Product_CategoryId", + table: "Product", + column: "CategoryId"); + + migrationBuilder.CreateIndex( + name: "IX_ProductCategory_ParentId", + table: "ProductCategory", + column: "ParentId"); + + migrationBuilder.CreateIndex( + name: "IX_Sale_CustomerId", + table: "Sale", + column: "CustomerId"); + + migrationBuilder.CreateIndex( + name: "IX_SaleItem_ProductId", + table: "SaleItem", + column: "ProductId"); + + migrationBuilder.CreateIndex( + name: "IX_SaleItem_SaleId", + table: "SaleItem", + column: "SaleId"); + + migrationBuilder.CreateIndex( + name: "IX_Supply_SupplierId", + table: "Supply", + column: "SupplierId"); + + migrationBuilder.CreateIndex( + name: "IX_SupplyItem_ProductId", + table: "SupplyItem", + column: "ProductId"); + + migrationBuilder.CreateIndex( + name: "IX_SupplyItem_SupplyId", + table: "SupplyItem", + column: "SupplyId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SaleItem"); + + migrationBuilder.DropTable( + name: "SupplyItem"); + + migrationBuilder.DropTable( + name: "Transaction"); + + migrationBuilder.DropTable( + name: "Sale"); + + migrationBuilder.DropTable( + name: "Product"); + + migrationBuilder.DropTable( + name: "Supply"); + + migrationBuilder.DropTable( + name: "Customer"); + + migrationBuilder.DropTable( + name: "ProductCategory"); + + migrationBuilder.DropTable( + name: "Supplier"); + } + } +} diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240321224718_Nullable_Category_Description.Designer.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240321224718_Nullable_Category_Description.Designer.cs new file mode 100644 index 0000000..7657892 --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240321224718_Nullable_Category_Description.Designer.cs @@ -0,0 +1,648 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using ReverseAnalytics.Infrastructure.Persistence; + +#nullable disable + +namespace ReverseAnalytics.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20240321224718_Nullable_Category_Description")] + partial class Nullable_Category_Description + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Company") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("float(18)") + .HasDefaultValue(0.0); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Customer", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SalePrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("SupplyPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("int"); + + b.Property("Volume") + .HasPrecision(18, 2) + .HasColumnType("float(18)"); + + b.Property("Weight") + .HasPrecision(18, 2) + .HasColumnType("float(18)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("Product", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ParentId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("ProductCategory", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Currency") + .HasColumnType("int"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("SaleType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TotalDiscount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.ToTable("Sale", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)") + .HasDefaultValue(0m); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SaleId") + .HasColumnType("int"); + + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("SaleId"); + + b.ToTable("SaleItem", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Company") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Supplier", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Currency") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("SupplierId") + .HasColumnType("int"); + + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Supply", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SupplyId") + .HasColumnType("int"); + + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("SupplyId"); + + b.ToTable("SupplyItem", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Transaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("SourceId") + .IsRequired() + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Category") + .WithMany("Products") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Parent") + .WithMany("SubCategories") + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Customer", "Customer") + .WithMany("Sales") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") + .WithMany("SaleItems") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ReverseAnalytics.Domain.Entities.Sale", "Sale") + .WithMany("SaleItems") + .HasForeignKey("SaleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Sale"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Supplier", "Supplier") + .WithMany("Supplies") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") + .WithMany("SupplyItems") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ReverseAnalytics.Domain.Entities.Supply", "Supply") + .WithMany("SupplyItems") + .HasForeignKey("SupplyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Supply"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => + { + b.Navigation("Sales"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.Navigation("SaleItems"); + + b.Navigation("SupplyItems"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.Navigation("Products"); + + b.Navigation("SubCategories"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.Navigation("SaleItems"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => + { + b.Navigation("Supplies"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.Navigation("SupplyItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240321224718_Nullable_Category_Description.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240321224718_Nullable_Category_Description.cs new file mode 100644 index 0000000..c444ad0 --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/20240321224718_Nullable_Category_Description.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ReverseAnalytics.Infrastructure.Persistence.Migrations +{ + /// + public partial class Nullable_Category_Description : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Description", + table: "ProductCategory", + type: "nvarchar(4000)", + maxLength: 4000, + nullable: true, + oldClrType: typeof(string), + oldType: "nvarchar(4000)", + oldMaxLength: 4000); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Description", + table: "ProductCategory", + type: "nvarchar(4000)", + maxLength: 4000, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "nvarchar(4000)", + oldMaxLength: 4000, + oldNullable: true); + } + } +} diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/ApplicationDbContextModelSnapshot.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/ApplicationDbContextModelSnapshot.cs new file mode 100644 index 0000000..56960ff --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/ApplicationDbContextModelSnapshot.cs @@ -0,0 +1,645 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using ReverseAnalytics.Infrastructure.Persistence; + +#nullable disable + +namespace ReverseAnalytics.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + partial class ApplicationDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Address") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Company") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("float(18)") + .HasDefaultValue(0.0); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Customer", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("int"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SalePrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("SupplyPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("UnitOfMeasurement") + .HasColumnType("int"); + + b.Property("Volume") + .HasPrecision(18, 2) + .HasColumnType("float(18)"); + + b.Property("Weight") + .HasPrecision(18, 2) + .HasColumnType("float(18)"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("Product", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ParentId") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("ProductCategory", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Currency") + .HasColumnType("int"); + + b.Property("CustomerId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("SaleType") + .HasColumnType("int"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("TotalDiscount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.ToTable("Sale", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)") + .HasDefaultValue(0m); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SaleId") + .HasColumnType("int"); + + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("SaleId"); + + b.ToTable("SaleItem", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Company") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.ToTable("Supplier", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("nvarchar(4000)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Currency") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("PaymentType") + .HasColumnType("int"); + + b.Property("SupplierId") + .HasColumnType("int"); + + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Supply", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("ProductId") + .HasColumnType("int"); + + b.Property("Quantity") + .HasColumnType("int"); + + b.Property("SupplyId") + .HasColumnType("int"); + + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("SupplyId"); + + b.ToTable("SupplyItem", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Transaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedById") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("LastModifiedAt") + .HasColumnType("datetime2"); + + b.Property("LastModifiedBy") + .HasColumnType("nvarchar(max)"); + + b.Property("LastModifiedById") + .HasColumnType("int"); + + b.Property("Source") + .HasColumnType("int"); + + b.Property("SourceId") + .IsRequired() + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Category") + .WithMany("Products") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Parent") + .WithMany("SubCategories") + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Customer", "Customer") + .WithMany("Sales") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") + .WithMany("SaleItems") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ReverseAnalytics.Domain.Entities.Sale", "Sale") + .WithMany("SaleItems") + .HasForeignKey("SaleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Sale"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Supplier", "Supplier") + .WithMany("Supplies") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") + .WithMany("SupplyItems") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ReverseAnalytics.Domain.Entities.Supply", "Supply") + .WithMany("SupplyItems") + .HasForeignKey("SupplyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Supply"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => + { + b.Navigation("Sales"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.Navigation("SaleItems"); + + b.Navigation("SupplyItems"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.Navigation("Products"); + + b.Navigation("SubCategories"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.Navigation("SaleItems"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => + { + b.Navigation("Supplies"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.Navigation("SupplyItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/ReverseAnalytics.Migrations.SqlServer.csproj b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/ReverseAnalytics.Migrations.SqlServer.csproj new file mode 100644 index 0000000..90cdb1a --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.SqlServer/ReverseAnalytics.Migrations.SqlServer.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/20230209114628_Initial_Create.Designer.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240317223222_Initial_Create.Designer.cs similarity index 60% rename from Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/20230209114628_Initial_Create.Designer.cs rename to Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240317223222_Initial_Create.Designer.cs index 53709a0..327cbf7 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/20230209114628_Initial_Create.Designer.cs +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240317223222_Initial_Create.Designer.cs @@ -11,318 +11,434 @@ namespace ReverseAnalytics.Infrastructure.Persistence.Migrations { [DbContext(typeof(ApplicationDbContext))] - [Migration("20230209114628_Initial_Create")] + [Migration("20240317223222_Initial_Create")] partial class Initial_Create { + /// protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "6.0.5"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.3"); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Debt", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("Address") + .HasMaxLength(4000) .HasColumnType("TEXT"); - b.Property("CreatedBy") + b.Property("Balance") + .HasPrecision(18, 2) .HasColumnType("TEXT"); - b.Property("DueDate") - .HasColumnType("date"); - - b.Property("LastModified") + b.Property("Company") + .HasMaxLength(4000) .HasColumnType("TEXT"); - b.Property("LastModifiedBy") + b.Property("CreatedAt") .HasColumnType("TEXT"); - b.Property("PaidDate") - .HasColumnType("date"); + b.Property("CreatedBy") + .HasColumnType("TEXT"); - b.Property("Remained") - .HasPrecision(2) - .HasColumnType("money"); + b.Property("CreatedById") + .HasColumnType("INTEGER"); - b.Property("Status") + b.Property("Discount") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasDefaultValue(0); + .HasPrecision(18, 2) + .HasColumnType("REAL") + .HasDefaultValue(0.0); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); - b.Property("TotalAmount") - .HasPrecision(2) - .HasColumnType("money"); + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); - b.Property("TransactionId") + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") .HasColumnType("INTEGER"); - b.HasKey("Id"); + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); - b.HasIndex("TransactionId") - .IsUnique(); + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); - b.ToTable("Debt", (string)null); + b.ToTable("Customer", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Inventory", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("CategoryId") + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + b.Property("Name") .IsRequired() - .HasMaxLength(150) + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SalePrice") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("SupplyPrice") + .HasPrecision(18, 2) .HasColumnType("TEXT"); + b.Property("UnitOfMeasurement") + .HasColumnType("INTEGER"); + + b.Property("Volume") + .HasPrecision(18, 2) + .HasColumnType("REAL"); + + b.Property("Weight") + .HasPrecision(18, 2) + .HasColumnType("REAL"); + b.HasKey("Id"); - b.ToTable("Inventory", (string)null); + b.HasIndex("CategoryId"); + + b.ToTable("Product", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.InventoryDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("InventoryId") + b.Property("CreatedById") .HasColumnType("INTEGER"); - b.Property("LastModified") + b.Property("Description") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); - b.Property("ProductId") + b.Property("LastModifiedById") .HasColumnType("INTEGER"); - b.Property("ProductsRemained") - .ValueGeneratedOnAdd() - .HasColumnType("REAL") - .HasDefaultValue(0.0); + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("INTEGER"); b.HasKey("Id"); - b.HasIndex("InventoryId"); + b.HasIndex("ParentId"); - b.HasIndex("ProductId"); - - b.ToTable("Inventory_Detail", (string)null); + b.ToTable("ProductCategory", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Person", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Address") - .HasMaxLength(250) + b.Property("Comments") + .HasMaxLength(4000) .HasColumnType("TEXT"); - b.Property("Balance") - .ValueGeneratedOnAdd() - .HasPrecision(2) - .HasColumnType("money") - .HasDefaultValue(0m); + b.Property("CreatedAt") + .HasColumnType("TEXT"); - b.Property("CompanyName") - .HasMaxLength(50) + b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("Created") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("CustomerId") + .HasColumnType("INTEGER"); + + b.Property("Date") .HasColumnType("TEXT"); - b.Property("CreatedBy") + b.Property("LastModifiedAt") .HasColumnType("TEXT"); - b.Property("FullName") - .IsRequired() - .HasMaxLength(250) + b.Property("LastModifiedBy") .HasColumnType("TEXT"); - b.Property("IsActive") + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("PaymentType") + .HasColumnType("INTEGER"); + + b.Property("SaleType") + .HasColumnType("INTEGER"); + + b.Property("Status") .HasColumnType("INTEGER"); - b.Property("LastModified") + b.Property("TotalDiscount") + .HasPrecision(18, 2) .HasColumnType("TEXT"); - b.Property("LastModifiedBy") + b.Property("TotalDue") + .HasPrecision(18, 2) .HasColumnType("TEXT"); - b.Property("PhoneNumber") - .HasMaxLength(50) + b.Property("TotalPaid") + .HasPrecision(18, 2) .HasColumnType("TEXT"); b.HasKey("Id"); - b.ToTable("Person", (string)null); + b.HasIndex("CustomerId"); + + b.ToTable("Sale", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("CategoryId") - .HasColumnType("INTEGER"); - - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") - .HasColumnType("TEXT"); + b.Property("CreatedById") + .HasColumnType("INTEGER"); - b.Property("LastModifiedBy") - .HasColumnType("TEXT"); + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("TEXT") + .HasDefaultValue(0m); - b.Property("ProductCode") - .IsRequired() - .HasMaxLength(50) + b.Property("LastModifiedAt") .HasColumnType("TEXT"); - b.Property("ProductName") - .IsRequired() - .HasMaxLength(250) + b.Property("LastModifiedBy") .HasColumnType("TEXT"); - b.Property("SalePrice") - .HasColumnType("money"); + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); - b.Property("SupplyPrice") - .HasColumnType("money"); + b.Property("ProductId") + .HasColumnType("INTEGER"); - b.Property("UnitOfMeasurement") + b.Property("Quantity") .HasColumnType("INTEGER"); - b.Property("Volume") - .HasPrecision(2) - .HasColumnType("REAL"); + b.Property("SaleId") + .HasColumnType("INTEGER"); - b.Property("Weight") - .HasPrecision(2) - .HasColumnType("REAL"); + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); b.HasKey("Id"); - b.HasIndex("CategoryId"); + b.HasIndex("ProductId"); - b.ToTable("Product", (string)null); + b.HasIndex("SaleId"); + + b.ToTable("SaleItem", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("CategoryName") - .IsRequired() - .HasMaxLength(150) + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("Company") + .HasMaxLength(4000) .HasColumnType("TEXT"); - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + b.HasKey("Id"); - b.ToTable("Product_Category", (string)null); + b.ToTable("Supplier", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); - b.Property("ProductId") + b.Property("LastModifiedById") .HasColumnType("INTEGER"); - b.Property("Quantity") + b.Property("PaymentType") .HasColumnType("INTEGER"); - b.Property("SaleId") + b.Property("SupplierId") .HasColumnType("INTEGER"); - b.Property("UnitPrice") - .HasPrecision(2) - .HasColumnType("money"); + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); - b.HasKey("Id"); + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); - b.HasIndex("ProductId"); + b.HasKey("Id"); - b.HasIndex("SaleId"); + b.HasIndex("SupplierId"); - b.ToTable("Sale_Detail", (string)null); + b.ToTable("Supply", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + b.Property("ProductId") .HasColumnType("INTEGER"); @@ -333,7 +449,8 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("INTEGER"); b.Property("UnitPrice") - .HasColumnType("money"); + .HasPrecision(18, 2) + .HasColumnType("TEXT"); b.HasKey("Id"); @@ -341,7 +458,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasIndex("SupplyId"); - b.ToTable("Supply_Detail", (string)null); + b.ToTable("SupplyItem", (string)null); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Transaction", b => @@ -350,155 +467,87 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Comments") - .HasMaxLength(500) + b.Property("Amount") + .HasPrecision(18, 2) .HasColumnType("TEXT"); - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") - .HasColumnType("TEXT"); + b.Property("CreatedById") + .HasColumnType("INTEGER"); - b.Property("LastModifiedBy") + b.Property("Date") .HasColumnType("TEXT"); - b.Property("Status") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasDefaultValue(0); - - b.Property("TotalDue") - .HasPrecision(2) - .HasColumnType("money"); - - b.Property("TotalPaid") - .HasPrecision(2) - .HasColumnType("money"); - - b.Property("TransactionDate") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.ToTable("Transaction", (string)null); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => - { - b.HasBaseType("ReverseAnalytics.Domain.Entities.Person"); - - b.Property("Discount") - .HasPrecision(2) - .HasColumnType("REAL"); - - b.ToTable("Customer", (string)null); - }); + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => - { - b.HasBaseType("ReverseAnalytics.Domain.Entities.Transaction"); + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); - b.Property("CustomerId") + b.Property("LastModifiedById") .HasColumnType("INTEGER"); - b.Property("Discount") - .ValueGeneratedOnAdd() - .HasColumnType("money") - .HasDefaultValue(0m); + b.Property("Source") + .HasColumnType("INTEGER"); - b.Property("Receipt") + b.Property("SourceId") .IsRequired() - .HasMaxLength(250) - .HasColumnType("TEXT"); - - b.Property("SaleType") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasDefaultValue(3); - - b.HasIndex("CustomerId"); - - b.ToTable("Sale", (string)null); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => - { - b.HasBaseType("ReverseAnalytics.Domain.Entities.Person"); - - b.ToTable("Supplier", (string)null); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => - { - b.HasBaseType("ReverseAnalytics.Domain.Entities.Transaction"); - - b.Property("ReceivedBy") - .HasMaxLength(500) - .HasColumnType("TEXT"); + .HasColumnType("INTEGER"); - b.Property("SupplierId") + b.Property("Type") .HasColumnType("INTEGER"); - b.HasIndex("SupplierId"); + b.HasKey("Id"); - b.ToTable("Supply", (string)null); + b.ToTable("Transaction", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Debt", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => { - b.HasOne("ReverseAnalytics.Domain.Entities.Transaction", "Transaction") - .WithOne("Debt") - .HasForeignKey("ReverseAnalytics.Domain.Entities.Debt", "TransactionId") + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Category") + .WithMany("Products") + .HasForeignKey("CategoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Transaction"); + b.Navigation("Category"); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.InventoryDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => { - b.HasOne("ReverseAnalytics.Domain.Entities.Inventory", "Inventory") - .WithMany("Details") - .HasForeignKey("InventoryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") - .WithMany("InventoryProducts") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Inventory"); + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Parent") + .WithMany("SubCategories") + .HasForeignKey("ParentId"); - b.Navigation("Product"); + b.Navigation("Parent"); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => { - b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Category") - .WithMany("Products") - .HasForeignKey("CategoryId") + b.HasOne("ReverseAnalytics.Domain.Entities.Customer", "Customer") + .WithMany("Sales") + .HasForeignKey("CustomerId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Category"); + b.Navigation("Customer"); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => { b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") - .WithMany("SaleDetails") + .WithMany("SaleItems") .HasForeignKey("ProductId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.HasOne("ReverseAnalytics.Domain.Entities.Sale", "Sale") - .WithMany("OrderDetails") + .WithMany("SaleItems") .HasForeignKey("SaleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -508,16 +557,27 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Sale"); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Supplier", "Supplier") + .WithMany("Supplies") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => { b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") - .WithMany("PurchaseDetails") + .WithMany("SupplyItems") .HasForeignKey("ProductId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.HasOne("ReverseAnalytics.Domain.Entities.Supply", "Supply") - .WithMany("SupplyDetails") + .WithMany("SupplyItems") .HasForeignKey("SupplyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -529,89 +589,26 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => { - b.HasOne("ReverseAnalytics.Domain.Entities.Person", null) - .WithOne() - .HasForeignKey("ReverseAnalytics.Domain.Entities.Customer", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => - { - b.HasOne("ReverseAnalytics.Domain.Entities.Customer", "Customer") - .WithMany("Sales") - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ReverseAnalytics.Domain.Entities.Transaction", null) - .WithOne() - .HasForeignKey("ReverseAnalytics.Domain.Entities.Sale", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Customer"); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => - { - b.HasOne("ReverseAnalytics.Domain.Entities.Person", null) - .WithOne() - .HasForeignKey("ReverseAnalytics.Domain.Entities.Supplier", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => - { - b.HasOne("ReverseAnalytics.Domain.Entities.Transaction", null) - .WithOne() - .HasForeignKey("ReverseAnalytics.Domain.Entities.Supply", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ReverseAnalytics.Domain.Entities.Supplier", "Supplier") - .WithMany("Supplies") - .HasForeignKey("SupplierId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Supplier"); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Inventory", b => - { - b.Navigation("Details"); + b.Navigation("Sales"); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => { - b.Navigation("InventoryProducts"); + b.Navigation("SaleItems"); - b.Navigation("PurchaseDetails"); - - b.Navigation("SaleDetails"); + b.Navigation("SupplyItems"); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => { b.Navigation("Products"); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Transaction", b => - { - b.Navigation("Debt") - .IsRequired(); - }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => - { - b.Navigation("Sales"); + b.Navigation("SubCategories"); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => { - b.Navigation("OrderDetails"); + b.Navigation("SaleItems"); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => @@ -621,7 +618,7 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => { - b.Navigation("SupplyDetails"); + b.Navigation("SupplyItems"); }); #pragma warning restore 612, 618 } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/20230209114628_Initial_Create.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240317223222_Initial_Create.cs similarity index 50% rename from Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/20230209114628_Initial_Create.cs rename to Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240317223222_Initial_Create.cs index 081a923..f802ed5 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/20230209114628_Initial_Create.cs +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240317223222_Initial_Create.cs @@ -5,64 +5,84 @@ namespace ReverseAnalytics.Infrastructure.Persistence.Migrations { + /// public partial class Initial_Create : Migration { + /// protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( - name: "Inventory", + name: "Customer", columns: table => new { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - Name = table.Column(type: "TEXT", maxLength: 150, nullable: false), - Created = table.Column(type: "TEXT", nullable: false), + FirstName = table.Column(type: "TEXT", maxLength: 255, nullable: false), + LastName = table.Column(type: "TEXT", maxLength: 255, nullable: true), + PhoneNumber = table.Column(type: "TEXT", maxLength: 50, nullable: false), + Address = table.Column(type: "TEXT", maxLength: 4000, nullable: true), + Company = table.Column(type: "TEXT", maxLength: 4000, nullable: true), + Balance = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + Discount = table.Column(type: "REAL", precision: 18, scale: 2, nullable: false, defaultValue: 0.0), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { - table.PrimaryKey("PK_Inventory", x => x.Id); + table.PrimaryKey("PK_Customer", x => x.Id); }); migrationBuilder.CreateTable( - name: "Person", + name: "ProductCategory", columns: table => new { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - FullName = table.Column(type: "TEXT", maxLength: 250, nullable: false), - CompanyName = table.Column(type: "TEXT", maxLength: 50, nullable: true), - PhoneNumber = table.Column(type: "TEXT", maxLength: 50, nullable: true), - Address = table.Column(type: "TEXT", maxLength: 250, nullable: true), - Balance = table.Column(type: "money", precision: 2, nullable: false, defaultValue: 0m), - IsActive = table.Column(type: "INTEGER", nullable: false), - Created = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 255, nullable: false), + Description = table.Column(type: "TEXT", maxLength: 4000, nullable: false), + ParentId = table.Column(type: "INTEGER", nullable: true), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { - table.PrimaryKey("PK_Person", x => x.Id); + table.PrimaryKey("PK_ProductCategory", x => x.Id); + table.ForeignKey( + name: "FK_ProductCategory_ProductCategory_ParentId", + column: x => x.ParentId, + principalTable: "ProductCategory", + principalColumn: "Id"); }); migrationBuilder.CreateTable( - name: "Product_Category", + name: "Supplier", columns: table => new { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - CategoryName = table.Column(type: "TEXT", maxLength: 150, nullable: false), - Created = table.Column(type: "TEXT", nullable: false), + FirstName = table.Column(type: "TEXT", maxLength: 255, nullable: false), + LastName = table.Column(type: "TEXT", maxLength: 255, nullable: true), + PhoneNumber = table.Column(type: "TEXT", maxLength: 50, nullable: false), + Company = table.Column(type: "TEXT", maxLength: 4000, nullable: true), + Balance = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { - table.PrimaryKey("PK_Product_Category", x => x.Id); + table.PrimaryKey("PK_Supplier", x => x.Id); }); migrationBuilder.CreateTable( @@ -71,15 +91,17 @@ protected override void Up(MigrationBuilder migrationBuilder) { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - TotalDue = table.Column(type: "money", precision: 2, nullable: false), - TotalPaid = table.Column(type: "money", precision: 2, nullable: false), - TransactionDate = table.Column(type: "date", nullable: false), - Comments = table.Column(type: "TEXT", maxLength: 500, nullable: true), - Status = table.Column(type: "INTEGER", nullable: false, defaultValue: 0), - Created = table.Column(type: "TEXT", nullable: false), + Date = table.Column(type: "TEXT", nullable: false), + SourceId = table.Column(type: "INTEGER", nullable: false), + Amount = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + Type = table.Column(type: "INTEGER", nullable: false), + Source = table.Column(type: "INTEGER", nullable: false), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { @@ -87,38 +109,35 @@ protected override void Up(MigrationBuilder migrationBuilder) }); migrationBuilder.CreateTable( - name: "Customer", + name: "Sale", columns: table => new { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - Discount = table.Column(type: "REAL", precision: 2, nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Customer", x => x.Id); - table.ForeignKey( - name: "FK_Customer_Person_Id", - column: x => x.Id, - principalTable: "Person", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Supplier", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true) + Date = table.Column(type: "TEXT", nullable: false), + Comments = table.Column(type: "TEXT", maxLength: 4000, nullable: true), + TotalDue = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + TotalPaid = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + TotalDiscount = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + SaleType = table.Column(type: "INTEGER", nullable: false), + Status = table.Column(type: "INTEGER", nullable: false), + PaymentType = table.Column(type: "INTEGER", nullable: false), + Currency = table.Column(type: "INTEGER", nullable: false), + CustomerId = table.Column(type: "INTEGER", nullable: false), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), + CreatedBy = table.Column(type: "TEXT", nullable: true), + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { - table.PrimaryKey("PK_Supplier", x => x.Id); + table.PrimaryKey("PK_Sale", x => x.Id); table.ForeignKey( - name: "FK_Supplier_Person_Id", - column: x => x.Id, - principalTable: "Person", + name: "FK_Sale_Customer_CustomerId", + column: x => x.CustomerId, + principalTable: "Customer", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); @@ -129,82 +148,29 @@ protected override void Up(MigrationBuilder migrationBuilder) { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - ProductName = table.Column(type: "TEXT", maxLength: 250, nullable: false), - ProductCode = table.Column(type: "TEXT", maxLength: 50, nullable: false), + Name = table.Column(type: "TEXT", maxLength: 255, nullable: false), + Code = table.Column(type: "TEXT", maxLength: 255, nullable: false), + Description = table.Column(type: "TEXT", maxLength: 4000, nullable: true), + SalePrice = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + SupplyPrice = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + Volume = table.Column(type: "REAL", precision: 18, scale: 2, nullable: true), + Weight = table.Column(type: "REAL", precision: 18, scale: 2, nullable: true), UnitOfMeasurement = table.Column(type: "INTEGER", nullable: false), - Volume = table.Column(type: "REAL", precision: 2, nullable: true), - Weight = table.Column(type: "REAL", precision: 2, nullable: true), - SupplyPrice = table.Column(type: "money", nullable: false), - SalePrice = table.Column(type: "money", nullable: false), CategoryId = table.Column(type: "INTEGER", nullable: false), - Created = table.Column(type: "TEXT", nullable: false), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { table.PrimaryKey("PK_Product", x => x.Id); table.ForeignKey( - name: "FK_Product_Product_Category_CategoryId", + name: "FK_Product_ProductCategory_CategoryId", column: x => x.CategoryId, - principalTable: "Product_Category", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Debt", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - TotalAmount = table.Column(type: "money", precision: 2, nullable: false), - Remained = table.Column(type: "money", precision: 2, nullable: false), - PaidDate = table.Column(type: "date", nullable: true), - DueDate = table.Column(type: "date", nullable: true), - Status = table.Column(type: "INTEGER", nullable: false, defaultValue: 0), - TransactionId = table.Column(type: "INTEGER", nullable: false), - Created = table.Column(type: "TEXT", nullable: false), - CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Debt", x => x.Id); - table.ForeignKey( - name: "FK_Debt_Transaction_TransactionId", - column: x => x.TransactionId, - principalTable: "Transaction", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Sale", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Receipt = table.Column(type: "TEXT", maxLength: 250, nullable: false), - Discount = table.Column(type: "money", nullable: false, defaultValue: 0m), - SaleType = table.Column(type: "INTEGER", nullable: false, defaultValue: 3), - CustomerId = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Sale", x => x.Id); - table.ForeignKey( - name: "FK_Sale_Customer_CustomerId", - column: x => x.CustomerId, - principalTable: "Customer", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Sale_Transaction_Id", - column: x => x.Id, - principalTable: "Transaction", + principalTable: "ProductCategory", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); @@ -215,8 +181,19 @@ protected override void Up(MigrationBuilder migrationBuilder) { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), - ReceivedBy = table.Column(type: "TEXT", maxLength: 500, nullable: true), - SupplierId = table.Column(type: "INTEGER", nullable: false) + Date = table.Column(type: "TEXT", nullable: false), + Comments = table.Column(type: "TEXT", maxLength: 4000, nullable: true), + TotalDue = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + TotalPaid = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + PaymentType = table.Column(type: "INTEGER", nullable: false), + Currency = table.Column(type: "INTEGER", nullable: false), + SupplierId = table.Column(type: "INTEGER", nullable: false), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), + CreatedBy = table.Column(type: "TEXT", nullable: true), + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { @@ -227,71 +204,37 @@ protected override void Up(MigrationBuilder migrationBuilder) principalTable: "Supplier", principalColumn: "Id", onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Supply_Transaction_Id", - column: x => x.Id, - principalTable: "Transaction", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Inventory_Detail", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - ProductsRemained = table.Column(type: "REAL", nullable: false, defaultValue: 0.0), - InventoryId = table.Column(type: "INTEGER", nullable: false), - ProductId = table.Column(type: "INTEGER", nullable: false), - Created = table.Column(type: "TEXT", nullable: false), - CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Inventory_Detail", x => x.Id); - table.ForeignKey( - name: "FK_Inventory_Detail_Inventory_InventoryId", - column: x => x.InventoryId, - principalTable: "Inventory", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Inventory_Detail_Product_ProductId", - column: x => x.ProductId, - principalTable: "Product", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); }); migrationBuilder.CreateTable( - name: "Sale_Detail", + name: "SaleItem", columns: table => new { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), Quantity = table.Column(type: "INTEGER", nullable: false), - UnitPrice = table.Column(type: "money", precision: 2, nullable: false), + UnitPrice = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), + Discount = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false, defaultValue: 0m), SaleId = table.Column(type: "INTEGER", nullable: false), ProductId = table.Column(type: "INTEGER", nullable: false), - Created = table.Column(type: "TEXT", nullable: false), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { - table.PrimaryKey("PK_Sale_Detail", x => x.Id); + table.PrimaryKey("PK_SaleItem", x => x.Id); table.ForeignKey( - name: "FK_Sale_Detail_Product_ProductId", + name: "FK_SaleItem_Product_ProductId", column: x => x.ProductId, principalTable: "Product", principalColumn: "Id", onDelete: ReferentialAction.Cascade); table.ForeignKey( - name: "FK_Sale_Detail_Sale_SaleId", + name: "FK_SaleItem_Sale_SaleId", column: x => x.SaleId, principalTable: "Sale", principalColumn: "Id", @@ -299,71 +242,62 @@ protected override void Up(MigrationBuilder migrationBuilder) }); migrationBuilder.CreateTable( - name: "Supply_Detail", + name: "SupplyItem", columns: table => new { Id = table.Column(type: "INTEGER", nullable: false) .Annotation("Sqlite:Autoincrement", true), Quantity = table.Column(type: "INTEGER", nullable: false), - UnitPrice = table.Column(type: "money", nullable: false), + UnitPrice = table.Column(type: "TEXT", precision: 18, scale: 2, nullable: false), SupplyId = table.Column(type: "INTEGER", nullable: false), ProductId = table.Column(type: "INTEGER", nullable: false), - Created = table.Column(type: "TEXT", nullable: false), + CreatedAt = table.Column(type: "TEXT", nullable: false), + LastModifiedAt = table.Column(type: "TEXT", nullable: true), CreatedBy = table.Column(type: "TEXT", nullable: true), - LastModified = table.Column(type: "TEXT", nullable: true), - LastModifiedBy = table.Column(type: "TEXT", nullable: true) + LastModifiedBy = table.Column(type: "TEXT", nullable: true), + CreatedById = table.Column(type: "INTEGER", nullable: true), + LastModifiedById = table.Column(type: "INTEGER", nullable: true) }, constraints: table => { - table.PrimaryKey("PK_Supply_Detail", x => x.Id); + table.PrimaryKey("PK_SupplyItem", x => x.Id); table.ForeignKey( - name: "FK_Supply_Detail_Product_ProductId", + name: "FK_SupplyItem_Product_ProductId", column: x => x.ProductId, principalTable: "Product", principalColumn: "Id", onDelete: ReferentialAction.Cascade); table.ForeignKey( - name: "FK_Supply_Detail_Supply_SupplyId", + name: "FK_SupplyItem_Supply_SupplyId", column: x => x.SupplyId, principalTable: "Supply", principalColumn: "Id", onDelete: ReferentialAction.Cascade); }); - migrationBuilder.CreateIndex( - name: "IX_Debt_TransactionId", - table: "Debt", - column: "TransactionId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Inventory_Detail_InventoryId", - table: "Inventory_Detail", - column: "InventoryId"); - - migrationBuilder.CreateIndex( - name: "IX_Inventory_Detail_ProductId", - table: "Inventory_Detail", - column: "ProductId"); - migrationBuilder.CreateIndex( name: "IX_Product_CategoryId", table: "Product", column: "CategoryId"); + migrationBuilder.CreateIndex( + name: "IX_ProductCategory_ParentId", + table: "ProductCategory", + column: "ParentId"); + migrationBuilder.CreateIndex( name: "IX_Sale_CustomerId", table: "Sale", column: "CustomerId"); migrationBuilder.CreateIndex( - name: "IX_Sale_Detail_ProductId", - table: "Sale_Detail", + name: "IX_SaleItem_ProductId", + table: "SaleItem", column: "ProductId"); migrationBuilder.CreateIndex( - name: "IX_Sale_Detail_SaleId", - table: "Sale_Detail", + name: "IX_SaleItem_SaleId", + table: "SaleItem", column: "SaleId"); migrationBuilder.CreateIndex( @@ -372,32 +306,27 @@ protected override void Up(MigrationBuilder migrationBuilder) column: "SupplierId"); migrationBuilder.CreateIndex( - name: "IX_Supply_Detail_ProductId", - table: "Supply_Detail", + name: "IX_SupplyItem_ProductId", + table: "SupplyItem", column: "ProductId"); migrationBuilder.CreateIndex( - name: "IX_Supply_Detail_SupplyId", - table: "Supply_Detail", + name: "IX_SupplyItem_SupplyId", + table: "SupplyItem", column: "SupplyId"); } + /// protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable( - name: "Debt"); - - migrationBuilder.DropTable( - name: "Inventory_Detail"); - - migrationBuilder.DropTable( - name: "Sale_Detail"); + name: "SaleItem"); migrationBuilder.DropTable( - name: "Supply_Detail"); + name: "SupplyItem"); migrationBuilder.DropTable( - name: "Inventory"); + name: "Transaction"); migrationBuilder.DropTable( name: "Sale"); @@ -412,16 +341,10 @@ protected override void Down(MigrationBuilder migrationBuilder) name: "Customer"); migrationBuilder.DropTable( - name: "Product_Category"); + name: "ProductCategory"); migrationBuilder.DropTable( name: "Supplier"); - - migrationBuilder.DropTable( - name: "Transaction"); - - migrationBuilder.DropTable( - name: "Person"); } } } diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240321224617_Nullable_Category_Description.Designer.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240321224617_Nullable_Category_Description.Designer.cs new file mode 100644 index 0000000..4b6b4d5 --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240321224617_Nullable_Category_Description.Designer.cs @@ -0,0 +1,625 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using ReverseAnalytics.Infrastructure.Persistence; + +#nullable disable + +namespace ReverseAnalytics.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20240321224617_Nullable_Category_Description")] + partial class Nullable_Category_Description + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.3"); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Address") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("Company") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("REAL") + .HasDefaultValue(0.0); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Customer", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CategoryId") + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SalePrice") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("SupplyPrice") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("UnitOfMeasurement") + .HasColumnType("INTEGER"); + + b.Property("Volume") + .HasPrecision(18, 2) + .HasColumnType("REAL"); + + b.Property("Weight") + .HasPrecision(18, 2) + .HasColumnType("REAL"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.ToTable("Product", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("ParentId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("ProductCategory", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("CustomerId") + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("PaymentType") + .HasColumnType("INTEGER"); + + b.Property("SaleType") + .HasColumnType("INTEGER"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("TotalDiscount") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CustomerId"); + + b.ToTable("Sale", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("TEXT") + .HasDefaultValue(0m); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("INTEGER"); + + b.Property("SaleId") + .HasColumnType("INTEGER"); + + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("SaleId"); + + b.ToTable("SaleItem", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("Company") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Supplier", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("PaymentType") + .HasColumnType("INTEGER"); + + b.Property("SupplierId") + .HasColumnType("INTEGER"); + + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SupplierId"); + + b.ToTable("Supply", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("ProductId") + .HasColumnType("INTEGER"); + + b.Property("Quantity") + .HasColumnType("INTEGER"); + + b.Property("SupplyId") + .HasColumnType("INTEGER"); + + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProductId"); + + b.HasIndex("SupplyId"); + + b.ToTable("SupplyItem", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Transaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Amount") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") + .HasColumnType("TEXT"); + + b.Property("CreatedBy") + .HasColumnType("TEXT"); + + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); + + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("Source") + .HasColumnType("INTEGER"); + + b.Property("SourceId") + .IsRequired() + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Category") + .WithMany("Products") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Parent") + .WithMany("SubCategories") + .HasForeignKey("ParentId"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Customer", "Customer") + .WithMany("Sales") + .HasForeignKey("CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Customer"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") + .WithMany("SaleItems") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ReverseAnalytics.Domain.Entities.Sale", "Sale") + .WithMany("SaleItems") + .HasForeignKey("SaleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Sale"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Supplier", "Supplier") + .WithMany("Supplies") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") + .WithMany("SupplyItems") + .HasForeignKey("ProductId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("ReverseAnalytics.Domain.Entities.Supply", "Supply") + .WithMany("SupplyItems") + .HasForeignKey("SupplyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Product"); + + b.Navigation("Supply"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => + { + b.Navigation("Sales"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + { + b.Navigation("SaleItems"); + + b.Navigation("SupplyItems"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + { + b.Navigation("Products"); + + b.Navigation("SubCategories"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => + { + b.Navigation("SaleItems"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => + { + b.Navigation("Supplies"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.Navigation("SupplyItems"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240321224617_Nullable_Category_Description.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240321224617_Nullable_Category_Description.cs new file mode 100644 index 0000000..a9845ea --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/20240321224617_Nullable_Category_Description.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ReverseAnalytics.Infrastructure.Persistence.Migrations +{ + /// + public partial class Nullable_Category_Description : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Description", + table: "ProductCategory", + type: "TEXT", + maxLength: 4000, + nullable: true, + oldClrType: typeof(string), + oldType: "TEXT", + oldMaxLength: 4000); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Description", + table: "ProductCategory", + type: "TEXT", + maxLength: 4000, + nullable: false, + defaultValue: "", + oldClrType: typeof(string), + oldType: "TEXT", + oldMaxLength: 4000, + oldNullable: true); + } + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/ApplicationDbContextModelSnapshot.cs similarity index 60% rename from Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs rename to Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/ApplicationDbContextModelSnapshot.cs index 82c2d88..fb723bd 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/ApplicationDbContextModelSnapshot.cs @@ -15,312 +15,426 @@ partial class ApplicationDbContextModelSnapshot : ModelSnapshot protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "6.0.5"); + modelBuilder.HasAnnotation("ProductVersion", "8.0.3"); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Debt", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("Address") + .HasMaxLength(4000) .HasColumnType("TEXT"); - b.Property("CreatedBy") + b.Property("Balance") + .HasPrecision(18, 2) .HasColumnType("TEXT"); - b.Property("DueDate") - .HasColumnType("date"); - - b.Property("LastModified") + b.Property("Company") + .HasMaxLength(4000) .HasColumnType("TEXT"); - b.Property("LastModifiedBy") + b.Property("CreatedAt") .HasColumnType("TEXT"); - b.Property("PaidDate") - .HasColumnType("date"); + b.Property("CreatedBy") + .HasColumnType("TEXT"); - b.Property("Remained") - .HasPrecision(2) - .HasColumnType("money"); + b.Property("CreatedById") + .HasColumnType("INTEGER"); - b.Property("Status") + b.Property("Discount") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasDefaultValue(0); + .HasPrecision(18, 2) + .HasColumnType("REAL") + .HasDefaultValue(0.0); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); - b.Property("TotalAmount") - .HasPrecision(2) - .HasColumnType("money"); + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); - b.Property("TransactionId") + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); + + b.Property("LastModifiedById") .HasColumnType("INTEGER"); - b.HasKey("Id"); + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); - b.HasIndex("TransactionId") - .IsUnique(); + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Id"); - b.ToTable("Debt", (string)null); + b.ToTable("Customer", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Inventory", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("CategoryId") + .HasColumnType("INTEGER"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + b.Property("Name") .IsRequired() - .HasMaxLength(150) + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("SalePrice") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("SupplyPrice") + .HasPrecision(18, 2) .HasColumnType("TEXT"); + b.Property("UnitOfMeasurement") + .HasColumnType("INTEGER"); + + b.Property("Volume") + .HasPrecision(18, 2) + .HasColumnType("REAL"); + + b.Property("Weight") + .HasPrecision(18, 2) + .HasColumnType("REAL"); + b.HasKey("Id"); - b.ToTable("Inventory", (string)null); + b.HasIndex("CategoryId"); + + b.ToTable("Product", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.InventoryDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("InventoryId") + b.Property("CreatedById") .HasColumnType("INTEGER"); - b.Property("LastModified") + b.Property("Description") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); - b.Property("ProductId") + b.Property("LastModifiedById") .HasColumnType("INTEGER"); - b.Property("ProductsRemained") - .ValueGeneratedOnAdd() - .HasColumnType("REAL") - .HasDefaultValue(0.0); + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); - b.HasKey("Id"); + b.Property("ParentId") + .HasColumnType("INTEGER"); - b.HasIndex("InventoryId"); + b.HasKey("Id"); - b.HasIndex("ProductId"); + b.HasIndex("ParentId"); - b.ToTable("Inventory_Detail", (string)null); + b.ToTable("ProductCategory", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Person", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Address") - .HasMaxLength(250) + b.Property("Comments") + .HasMaxLength(4000) .HasColumnType("TEXT"); - b.Property("Balance") - .ValueGeneratedOnAdd() - .HasPrecision(2) - .HasColumnType("money") - .HasDefaultValue(0m); + b.Property("CreatedAt") + .HasColumnType("TEXT"); - b.Property("CompanyName") - .HasMaxLength(50) + b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("Created") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("CustomerId") + .HasColumnType("INTEGER"); + + b.Property("Date") .HasColumnType("TEXT"); - b.Property("CreatedBy") + b.Property("LastModifiedAt") .HasColumnType("TEXT"); - b.Property("FullName") - .IsRequired() - .HasMaxLength(250) + b.Property("LastModifiedBy") .HasColumnType("TEXT"); - b.Property("IsActive") + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("PaymentType") + .HasColumnType("INTEGER"); + + b.Property("SaleType") + .HasColumnType("INTEGER"); + + b.Property("Status") .HasColumnType("INTEGER"); - b.Property("LastModified") + b.Property("TotalDiscount") + .HasPrecision(18, 2) .HasColumnType("TEXT"); - b.Property("LastModifiedBy") + b.Property("TotalDue") + .HasPrecision(18, 2) .HasColumnType("TEXT"); - b.Property("PhoneNumber") - .HasMaxLength(50) + b.Property("TotalPaid") + .HasPrecision(18, 2) .HasColumnType("TEXT"); b.HasKey("Id"); - b.ToTable("Person", (string)null); + b.HasIndex("CustomerId"); + + b.ToTable("Sale", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("CategoryId") - .HasColumnType("INTEGER"); - - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") - .HasColumnType("TEXT"); + b.Property("CreatedById") + .HasColumnType("INTEGER"); - b.Property("LastModifiedBy") - .HasColumnType("TEXT"); + b.Property("Discount") + .ValueGeneratedOnAdd() + .HasPrecision(18, 2) + .HasColumnType("TEXT") + .HasDefaultValue(0m); - b.Property("ProductCode") - .IsRequired() - .HasMaxLength(50) + b.Property("LastModifiedAt") .HasColumnType("TEXT"); - b.Property("ProductName") - .IsRequired() - .HasMaxLength(250) + b.Property("LastModifiedBy") .HasColumnType("TEXT"); - b.Property("SalePrice") - .HasColumnType("money"); + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); - b.Property("SupplyPrice") - .HasColumnType("money"); + b.Property("ProductId") + .HasColumnType("INTEGER"); - b.Property("UnitOfMeasurement") + b.Property("Quantity") .HasColumnType("INTEGER"); - b.Property("Volume") - .HasPrecision(2) - .HasColumnType("REAL"); + b.Property("SaleId") + .HasColumnType("INTEGER"); - b.Property("Weight") - .HasPrecision(2) - .HasColumnType("REAL"); + b.Property("UnitPrice") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); b.HasKey("Id"); - b.HasIndex("CategoryId"); + b.HasIndex("ProductId"); - b.ToTable("Product", (string)null); + b.HasIndex("SaleId"); + + b.ToTable("SaleItem", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("CategoryName") - .IsRequired() - .HasMaxLength(150) + b.Property("Balance") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); + + b.Property("Company") + .HasMaxLength(4000) .HasColumnType("TEXT"); - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + + b.Property("LastName") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + b.HasKey("Id"); - b.ToTable("Product_Category", (string)null); + b.ToTable("Supplier", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("Comments") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("Currency") + .HasColumnType("INTEGER"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); - b.Property("ProductId") + b.Property("LastModifiedById") .HasColumnType("INTEGER"); - b.Property("Quantity") + b.Property("PaymentType") .HasColumnType("INTEGER"); - b.Property("SaleId") + b.Property("SupplierId") .HasColumnType("INTEGER"); - b.Property("UnitPrice") - .HasPrecision(2) - .HasColumnType("money"); + b.Property("TotalDue") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); - b.HasKey("Id"); + b.Property("TotalPaid") + .HasPrecision(18, 2) + .HasColumnType("TEXT"); - b.HasIndex("ProductId"); + b.HasKey("Id"); - b.HasIndex("SaleId"); + b.HasIndex("SupplierId"); - b.ToTable("Sale_Detail", (string)null); + b.ToTable("Supply", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => { b.Property("Id") .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") + b.Property("CreatedById") + .HasColumnType("INTEGER"); + + b.Property("LastModifiedAt") .HasColumnType("TEXT"); b.Property("LastModifiedBy") .HasColumnType("TEXT"); + b.Property("LastModifiedById") + .HasColumnType("INTEGER"); + b.Property("ProductId") .HasColumnType("INTEGER"); @@ -331,7 +445,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("INTEGER"); b.Property("UnitPrice") - .HasColumnType("money"); + .HasPrecision(18, 2) + .HasColumnType("TEXT"); b.HasKey("Id"); @@ -339,7 +454,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("SupplyId"); - b.ToTable("Supply_Detail", (string)null); + b.ToTable("SupplyItem", (string)null); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Transaction", b => @@ -348,155 +463,87 @@ protected override void BuildModel(ModelBuilder modelBuilder) .ValueGeneratedOnAdd() .HasColumnType("INTEGER"); - b.Property("Comments") - .HasMaxLength(500) + b.Property("Amount") + .HasPrecision(18, 2) .HasColumnType("TEXT"); - b.Property("Created") + b.Property("CreatedAt") .HasColumnType("TEXT"); b.Property("CreatedBy") .HasColumnType("TEXT"); - b.Property("LastModified") - .HasColumnType("TEXT"); + b.Property("CreatedById") + .HasColumnType("INTEGER"); - b.Property("LastModifiedBy") + b.Property("Date") .HasColumnType("TEXT"); - b.Property("Status") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasDefaultValue(0); - - b.Property("TotalDue") - .HasPrecision(2) - .HasColumnType("money"); - - b.Property("TotalPaid") - .HasPrecision(2) - .HasColumnType("money"); - - b.Property("TransactionDate") - .HasColumnType("date"); - - b.HasKey("Id"); - - b.ToTable("Transaction", (string)null); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => - { - b.HasBaseType("ReverseAnalytics.Domain.Entities.Person"); - - b.Property("Discount") - .HasPrecision(2) - .HasColumnType("REAL"); - - b.ToTable("Customer", (string)null); - }); + b.Property("LastModifiedAt") + .HasColumnType("TEXT"); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => - { - b.HasBaseType("ReverseAnalytics.Domain.Entities.Transaction"); + b.Property("LastModifiedBy") + .HasColumnType("TEXT"); - b.Property("CustomerId") + b.Property("LastModifiedById") .HasColumnType("INTEGER"); - b.Property("Discount") - .ValueGeneratedOnAdd() - .HasColumnType("money") - .HasDefaultValue(0m); + b.Property("Source") + .HasColumnType("INTEGER"); - b.Property("Receipt") + b.Property("SourceId") .IsRequired() - .HasMaxLength(250) - .HasColumnType("TEXT"); - - b.Property("SaleType") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER") - .HasDefaultValue(3); - - b.HasIndex("CustomerId"); - - b.ToTable("Sale", (string)null); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => - { - b.HasBaseType("ReverseAnalytics.Domain.Entities.Person"); - - b.ToTable("Supplier", (string)null); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => - { - b.HasBaseType("ReverseAnalytics.Domain.Entities.Transaction"); - - b.Property("ReceivedBy") - .HasMaxLength(500) - .HasColumnType("TEXT"); + .HasColumnType("INTEGER"); - b.Property("SupplierId") + b.Property("Type") .HasColumnType("INTEGER"); - b.HasIndex("SupplierId"); + b.HasKey("Id"); - b.ToTable("Supply", (string)null); + b.ToTable("Transaction", (string)null); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Debt", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => { - b.HasOne("ReverseAnalytics.Domain.Entities.Transaction", "Transaction") - .WithOne("Debt") - .HasForeignKey("ReverseAnalytics.Domain.Entities.Debt", "TransactionId") + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Category") + .WithMany("Products") + .HasForeignKey("CategoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Transaction"); + b.Navigation("Category"); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.InventoryDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => { - b.HasOne("ReverseAnalytics.Domain.Entities.Inventory", "Inventory") - .WithMany("Details") - .HasForeignKey("InventoryId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") - .WithMany("InventoryProducts") - .HasForeignKey("ProductId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Inventory"); + b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Parent") + .WithMany("SubCategories") + .HasForeignKey("ParentId"); - b.Navigation("Product"); + b.Navigation("Parent"); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => { - b.HasOne("ReverseAnalytics.Domain.Entities.ProductCategory", "Category") - .WithMany("Products") - .HasForeignKey("CategoryId") + b.HasOne("ReverseAnalytics.Domain.Entities.Customer", "Customer") + .WithMany("Sales") + .HasForeignKey("CustomerId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.Navigation("Category"); + b.Navigation("Customer"); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SaleItem", b => { b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") - .WithMany("SaleDetails") + .WithMany("SaleItems") .HasForeignKey("ProductId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.HasOne("ReverseAnalytics.Domain.Entities.Sale", "Sale") - .WithMany("OrderDetails") + .WithMany("SaleItems") .HasForeignKey("SaleId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -506,16 +553,27 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Sale"); }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyDetail", b => + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => + { + b.HasOne("ReverseAnalytics.Domain.Entities.Supplier", "Supplier") + .WithMany("Supplies") + .HasForeignKey("SupplierId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Supplier"); + }); + + modelBuilder.Entity("ReverseAnalytics.Domain.Entities.SupplyItem", b => { b.HasOne("ReverseAnalytics.Domain.Entities.Product", "Product") - .WithMany("PurchaseDetails") + .WithMany("SupplyItems") .HasForeignKey("ProductId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); b.HasOne("ReverseAnalytics.Domain.Entities.Supply", "Supply") - .WithMany("SupplyDetails") + .WithMany("SupplyItems") .HasForeignKey("SupplyId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -527,89 +585,26 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => { - b.HasOne("ReverseAnalytics.Domain.Entities.Person", null) - .WithOne() - .HasForeignKey("ReverseAnalytics.Domain.Entities.Customer", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => - { - b.HasOne("ReverseAnalytics.Domain.Entities.Customer", "Customer") - .WithMany("Sales") - .HasForeignKey("CustomerId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ReverseAnalytics.Domain.Entities.Transaction", null) - .WithOne() - .HasForeignKey("ReverseAnalytics.Domain.Entities.Sale", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Customer"); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => - { - b.HasOne("ReverseAnalytics.Domain.Entities.Person", null) - .WithOne() - .HasForeignKey("ReverseAnalytics.Domain.Entities.Supplier", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => - { - b.HasOne("ReverseAnalytics.Domain.Entities.Transaction", null) - .WithOne() - .HasForeignKey("ReverseAnalytics.Domain.Entities.Supply", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ReverseAnalytics.Domain.Entities.Supplier", "Supplier") - .WithMany("Supplies") - .HasForeignKey("SupplierId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Supplier"); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Inventory", b => - { - b.Navigation("Details"); + b.Navigation("Sales"); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Product", b => { - b.Navigation("InventoryProducts"); + b.Navigation("SaleItems"); - b.Navigation("PurchaseDetails"); - - b.Navigation("SaleDetails"); + b.Navigation("SupplyItems"); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.ProductCategory", b => { b.Navigation("Products"); - }); - - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Transaction", b => - { - b.Navigation("Debt") - .IsRequired(); - }); - modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Customer", b => - { - b.Navigation("Sales"); + b.Navigation("SubCategories"); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Sale", b => { - b.Navigation("OrderDetails"); + b.Navigation("SaleItems"); }); modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supplier", b => @@ -619,7 +614,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("ReverseAnalytics.Domain.Entities.Supply", b => { - b.Navigation("SupplyDetails"); + b.Navigation("SupplyItems"); }); #pragma warning restore 612, 618 } diff --git a/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/ReverseAnalytics.Migrations.Sqlite.csproj b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/ReverseAnalytics.Migrations.Sqlite.csproj new file mode 100644 index 0000000..5ae0642 --- /dev/null +++ b/Reverse-Analytics/Migrations/ReverseAnalytics.Migrations.Sqlite/ReverseAnalytics.Migrations.Sqlite.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Configurations/DataSeedConfiguration.cs b/Reverse-Analytics/Reverse-Analytics.Api/Configurations/DataSeedConfiguration.cs new file mode 100644 index 0000000..98c6ea4 --- /dev/null +++ b/Reverse-Analytics/Reverse-Analytics.Api/Configurations/DataSeedConfiguration.cs @@ -0,0 +1,15 @@ +namespace Reverse_Analytics.Api.Configurations; + +public sealed class DataSeedConfiguration +{ + public const string SECTION = "DataSeed"; + + public int CategoriesCount { get; init; } + public int ProductsCount { get; init; } + public int CustomersCount { get; init; } + public int SalesCount { get; init; } + public int SaleItemsCount { get; set; } + public int SuppliersCount { get; init; } + public int SuppliesCount { get; init; } + public int SupplyItemsCount { get; set; } +} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/AccountsController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/AccountsController.cs deleted file mode 100644 index f8091aa..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/AccountsController.cs +++ /dev/null @@ -1,87 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.PasswordReset; -using ReverseAnalytics.Domain.DTOs.UserAccount; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - [Authorize] - [ApiController] - [Route("api/accounts")] - public class AccountsController : Controller - { - private readonly IAccountService _accountService; - - public AccountsController(IAccountService accountService) - { - _accountService = accountService; - } - - [HttpGet] - public async Task>> GetUserAccountsAsync() - { - var userAccounts = await _accountService.GetAllAccountsAsync(); - - return Ok(userAccounts); - } - - [HttpGet("{id}")] - public async Task> GetUserAccountByIdAsync(string id) - { - var userAccount = await _accountService.GetAccountByIdAsync(id); - - if (userAccount is null) - return NotFound($"User account with id: {id} does not exist."); - - return Ok(userAccount); - } - - [HttpPost] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task CreateUserAccountAsync(UserAccountForCreateDto userAccountToCreate) - { - await _accountService.CreateAccountAsync(userAccountToCreate); - - return Created("User Accout was successfully created.", userAccountToCreate); - } - - [HttpPost("PasswordReset")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> ResetPasswordAsync(PasswordResetRequest request) - { - var result = await _accountService.ResetPasswordAsync(request); - - if (!result.IsSuccess) - { - foreach (var error in result.Errors) - { - ModelState.AddModelError(error.Code, error.Description); - } - } - - return StatusCode(201, result); - } - - [HttpPut("{id}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateUserAccountAsync(UserAccountForUpdateDto userAccountToUpdate, string id) - { - if (userAccountToUpdate.Id != id) - return BadRequest($"Account id: {userAccountToUpdate.Id} does not match with route id: {id}."); - - await _accountService.UpdateAccountAsync(userAccountToUpdate); - - return NoContent(); - } - - [HttpDelete("{id}")] - public async Task DeleteUserAccountByIdAsync(string id) - { - await _accountService.DeleteAccountAsync(id); - - return NoContent(); - } - } -} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/AuthenticationController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/AuthenticationController.cs deleted file mode 100644 index da1f2a3..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/AuthenticationController.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.Authentication; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - [Authorize] - [ApiController] - [Route("api/authentication")] - public class AuthenticationController : ControllerBase - { - private readonly IAuthenticationService _authService; - - public AuthenticationController(IAuthenticationService authenticationService) - { - _authService = authenticationService; - } - - [AllowAnonymous] - [HttpPost("login")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> LoginAsync([FromBody] AuthenticationRequest userRequest) - { - var result = await _authService.LoginAsync(userRequest); - - if (!result.IsSuccess) - { - return Unauthorized(result); - } - - return Ok(result); - } - } -} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/CommonControllerBase.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/CommonControllerBase.cs new file mode 100644 index 0000000..4fd532f --- /dev/null +++ b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/CommonControllerBase.cs @@ -0,0 +1,7 @@ +using Microsoft.AspNetCore.Mvc; + +namespace Reverse_Analytics.Api.Controllers; + +public class CommonControllerBase : ControllerBase +{ +} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/CustomersController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/CustomersController.cs deleted file mode 100644 index d888239..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/CustomersController.cs +++ /dev/null @@ -1,143 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.Customer; -using ReverseAnalytics.Domain.DTOs.Debt; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - [Authorize] - [ApiController] - [Route("api/customers")] - public class CustomersController : Controller - { - private readonly ICustomerService _customerService; - private readonly IDebtService _debtService; - - private const int pageSize = 15; - - public CustomersController(ICustomerService customerService, IDebtService debtService) - { - _customerService = customerService; - _debtService = debtService; - } - - #region CRUD - - [HttpGet] - public async Task>> GetCustomersAsync(string? searchString, int pageNumber = 1, int pageSize = pageSize) - { - var customers = await _customerService.GetAllCustomerAsync(searchString, pageNumber, pageSize); - - return Ok(customers); - } - - [HttpGet("{customerId}")] - public async Task> GetCustomerByIdAsync(int customerId) - { - var customer = await _customerService.GetCustomerByIdAsync(customerId); - - if (customer is null) - return NotFound($"Customer with id: {customerId} does not exist."); - - return Ok(customer); - } - - [HttpPost] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateCustomerAsync([FromBody] CustomerForCreateDto customerToCreate) - { - var createdCustomer = await _customerService.CreateCustomerAsync(customerToCreate); - - if (createdCustomer is null) - return StatusCode(500, "Something went wrong while creating new customer. Please, try again later."); - - return Created("Customer was successfully created.", createdCustomer); - } - - [HttpPut("{customerId}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateCustomerAsync([FromBody] CustomerForUpdateDto customerToUpdate, int customerId) - { - if (customerToUpdate.Id != customerId) - return BadRequest($"Customer id: {customerToUpdate.Id}, does not match with route id: {customerId}."); - - await _customerService.UpdateCustomerAsync(customerToUpdate); - - return NoContent(); - } - - [HttpDelete("{customerId}")] - public async Task DeleteCustomerAsync(int customerId) - { - await _customerService.DeleteCustomerAsync(customerId); - - return NoContent(); - } - - #endregion - - #region Debts - - [HttpGet("{customerId}/debts")] - public async Task>> GetCustomerDebtsAsync(int customerId) - { - var debts = await _debtService.GetAllDebtsByPersonIdAsync(customerId); - - return Ok(debts); - } - - [HttpGet("{customerId}/debts/{debtId}")] - public async Task> GetDebtByCustomerAndDebtId(int customerId, int debtId) - { - var debt = await _debtService.GetByPersonAndDebtId(customerId, debtId); - - if (debt is null) - return NotFound($"Customer with id: {customerId} does not have Debt with id: {debtId}."); - - return Ok(debt); - } - - [HttpPost("{customerId}/debts")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateCustomerDebt([FromBody] DebtForCreateDto debtToCreate, int customerId) - { - if (debtToCreate.PersonId != customerId) - return BadRequest($"Customer Id: {debtToCreate.PersonId} does not match with route id: {customerId}"); - - var createdCustomerDebt = await _debtService.CreateDebtAsync(debtToCreate); - - if (createdCustomerDebt is null) - return StatusCode(500, - "Something went wrong while creating new Customer Debt. Please, try again later."); - - return Created("Debt was successfully created.", createdCustomerDebt); - } - - [HttpPut("{customerId}/debts/{debtId}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateCustomerDebtAsync([FromBody] DebtForUpdateDto debtToUpdate, int customerId, int debtId) - { - if (debtId != debtToUpdate.Id) - return BadRequest($"Debt id: {debtToUpdate.Id} does not match with route id: {debtId}."); - - if (customerId != debtToUpdate.PersonId) - return BadRequest($"Customer id: {debtToUpdate.PersonId} does not match with route id: {customerId}."); - - await _debtService.UpdateDebtAsync(debtToUpdate); - - return NoContent(); - } - - [HttpDelete("{customerId}/debts/{debtId}")] - public async Task DeleteCustomerDebtAsync(int debtId) - { - await _debtService.DeleteDebtAsync(debtId); - - return NoContent(); - } - - #endregion - } -} \ No newline at end of file diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/DebtsController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/DebtsController.cs deleted file mode 100644 index 9c2a164..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/DebtsController.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.Debt; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - [Authorize] - [ApiController] - [Route("api/debts")] - public class DebtsController : ControllerBase - { - private readonly IDebtService _debtService; - - public DebtsController(IDebtService debtService) - { - _debtService = debtService; - } - - [HttpGet] - public async Task>> GetAllDebtsAsync() - { - var debts = await _debtService.GetAllDebtsAsync(); - - return Ok(debts); - } - - [HttpGet("{id}")] - public async Task> GetDebtByIdAsync(int id) - { - var debt = await _debtService.GetDebtByIdAsync(id); - - if (debt is null) - return NotFound($"Debt with id: {id} does not exist."); - - return Ok(debt); - } - - [HttpPost] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateDebtAsync([FromBody] DebtForCreateDto debtToCreate) - { - var createdDebt = await _debtService.CreateDebtAsync(debtToCreate); - - if (createdDebt is null) - return StatusCode(500, - "Something went wrong while creating new Debt. Please, try again later."); - - return Created("Debt was sucessfully created.", createdDebt); - } - - [HttpPut("{id}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateDebtAsync([FromBody] DebtForUpdateDto debtToUpdate, int id) - { - if (id != debtToUpdate.Id) - return BadRequest($"Debt id: {debtToUpdate.Id} does not match with route id: {id}."); - - await _debtService.UpdateDebtAsync(debtToUpdate); - - return NoContent(); - } - - [HttpDelete("{id}")] - public async Task DeleteDebtAsync(int id) - { - await _debtService.DeleteDebtAsync(id); - - return NoContent(); - } - } -} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/HomeController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/HomeController.cs new file mode 100644 index 0000000..a4c48e6 --- /dev/null +++ b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/HomeController.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Mvc; + +namespace Reverse_Analytics.Api.Controllers; + +[Route("api/[controller]")] +[ApiController] +public class HomeController() : CommonControllerBase +{ + // GET: api/ + [HttpGet] + public IEnumerable Get() + { + return new string[] { "value1", "value2" }; + } + + // GET api//5 + [HttpGet("{id}")] + public string Get(int id) + { + return "value"; + } + + // POST api/ + [HttpPost] + public void Post([FromBody] string value) + { + } + + // PUT api//5 + [HttpPut("{id}")] + public void Put(int id, [FromBody] string value) + { + } + + // DELETE api//5 + [HttpDelete("{id}")] + public void Delete(int id) + { + } +} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductCategoriesController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductCategoriesController.cs deleted file mode 100644 index 48bef65..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductCategoriesController.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.ProductCategory; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - // [Authorize] - [ApiController] - [Route("api/categories")] - public class ProductCategoriesController : ControllerBase - { - private readonly IProductCategoryService _productCategoryService; - - public ProductCategoriesController(IProductCategoryService productCategoryService) - { - _productCategoryService = productCategoryService; - } - - [HttpGet] - public async Task>> GetCategories(string? searchQuery) - { - var categories = await _productCategoryService.GetProductCategoriesAsync(searchQuery); - - return Ok(categories); - } - - [HttpGet("{id}")] - public async Task> GetCategory(int id) - { - var category = await _productCategoryService.GetProductCategoryByIdAsync(id); - - if (category is null) - return NotFound($"Product category with id: {id} does not exist."); - - return Ok(category); - } - - [HttpPost] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateCategoryAsync([FromBody] ProductCategoryForCreateDto categoryToCreate) - { - var category = await _productCategoryService.CreateProductCategoryAsync(categoryToCreate); - - if (category is null) - return StatusCode(500, - "Something went wrong while adding product category. Please, try again later."); - - return Created("Category was successfully created.", category); - } - - [HttpPut("{id}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateCategoryAsync([FromBody] ProductCategoryForUpdateDto categoryToUpdate, int id) - { - if (categoryToUpdate.Id != id) - return BadRequest($"Product Category id: {categoryToUpdate.Id} does not match with route id: {id}."); - - await _productCategoryService.UpdateProductCategoryAsync(categoryToUpdate); - - return NoContent(); - } - - [HttpDelete("{id}")] - public async Task DeleteCategoryAsync(int id) - { - await _productCategoryService.DeleteProductCategoryAsync(id); - - return NoContent(); - } - } -} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductCategoryController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductCategoryController.cs new file mode 100644 index 0000000..c0ca34a --- /dev/null +++ b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductCategoryController.cs @@ -0,0 +1,127 @@ +using FluentValidation; +using FluentValidation.AspNetCore; +using Microsoft.AspNetCore.JsonPatch; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using ReverseAnalytics.Domain.DTOs.Product; +using ReverseAnalytics.Domain.DTOs.ProductCategory; +using ReverseAnalytics.Domain.Interfaces.Services; +using ReverseAnalytics.Domain.QueryParameters; + +namespace Reverse_Analytics.Api.Controllers; + +[Route("api/categories")] +[ApiController] +public class ProductCategoryController( + IProductService productService, + IProductCategoryService productCategoryService, + IValidator validator) : CommonControllerBase +{ + private readonly IProductService _productService = productService ?? throw new ArgumentNullException(nameof(productService)); + private readonly IProductCategoryService _productCategoryService = productCategoryService ?? throw new ArgumentNullException(nameof(productCategoryService)); + private readonly IValidator _validator = validator ?? throw new ArgumentNullException(nameof(validator)); + + [HttpGet] + [HttpHead] + public async Task>> GetCategoriesAsync([FromQuery] ProductCategoryQueryParameters queryParameters) + { + var (categories, metadata) = await _productCategoryService.GetAllAsync(queryParameters); + var json = JsonConvert.SerializeObject(metadata, Formatting.Indented); + Response.Headers.Append("X-Pagination", json); + + return Ok(categories); + } + + [HttpGet("{id}")] + public async Task> GetByIdAsync(int id) + { + var category = await _productCategoryService.GetByIdAsync(id); + + if (category is null) + { + return NotFound($"Category with id: {id} does not exist."); + } + + return Ok(category); + } + + [HttpGet("{id}/products")] + public async Task>> GetProductsAsync(int id) + { + var products = await _productService.GetByCategoryAsync(id); + + return Ok(products); + } + + [HttpGet("{id}/children")] + public async Task>> GetChildrenAsync(int id) + { + var subCategories = await _productCategoryService.GetAllByParentIdAsync(id); + + return Ok(subCategories); + } + + [HttpPost] + public async Task> CreateAsync([FromBody] ProductCategoryForCreateDto categoryToCreate) + { + var createdCategory = await _productCategoryService.CreateAsync(categoryToCreate); + + return Ok(createdCategory); + } + + [HttpPut("{id}")] + public async Task> UpdateAsync(int id, [FromBody] ProductCategoryForUpdateDto categoryToUpdate) + { + if (id != categoryToUpdate.Id) + { + return BadRequest($"Route id: {id} does not match with category id: {categoryToUpdate.Id}."); + } + + var updatedCategory = await _productCategoryService.UpdateAsync(categoryToUpdate); + + return Ok(updatedCategory); + } + + [HttpPatch("{id}")] + public async Task PatchAsync(int id, JsonPatchDocument patchDocument) + { + var categoryToUpdate = await _productCategoryService.GetByIdAsync(id); + + if (categoryToUpdate is null) + { + return NotFound($"Category with id: {id} does not exist."); + } + + var categoryDto = new ProductCategoryForUpdateDto(id, categoryToUpdate.Name, categoryToUpdate.Description, categoryToUpdate.ParentId); + + patchDocument.ApplyTo(categoryDto); + + var result = _validator.Validate(categoryDto); + + if (!result.IsValid) + { + result.AddToModelState(ModelState); + + return BadRequest(ModelState); + } + + await _productCategoryService.UpdateAsync(categoryDto); + + return NoContent(); + } + + [HttpDelete("{id}")] + public async Task DeleteAsync(int id) + { + await _productCategoryService.DeleteAsync(id); + + return NoContent(); + } + + [HttpOptions] + public IActionResult GetOptions() + { + Response.Headers.Append("Allow", "GET,HEAD,POST,OPTIONS"); + return Ok(); + } +} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductsController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductsController.cs deleted file mode 100644 index c326706..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/ProductsController.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.Product; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - [Authorize] - [ApiController] - [Route("api/Products")] - public class ProductsController : ControllerBase - { - private readonly IProductService _service; - - private const int PageSize = 15; - public ProductsController(IProductService service) - { - _service = service; - } - - [HttpGet] - public async Task>> GetAllProductsAsync(string? searchString, int? categoryId, int pageSize = PageSize, int pageNumber = 1) - { - var products = await _service.GetProductsAsync(searchString, categoryId, pageSize, pageNumber); - - return Ok(products); - } - - [HttpGet("{id}")] - public async Task> GetProductByIdAsync(int id) - { - var product = await _service.GetProductByIdAsync(id); - - if (product is null) - return NotFound($"Product with id: {id} does not exist."); - - return Ok(product); - } - - [HttpPost] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateProductAsync([FromBody] ProductForCreateDto productToCreate) - { - var product = await _service.CreateProductAsync(productToCreate); - - if (product is null) - return StatusCode(500, - "Something went wrong while creating new Product. Please, try again later."); - - return Created("Product was sucessfully created.", product); - } - - [HttpPut("{id}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateProductAsync([FromBody] ProductForUpdateDto productToUpdate, int id) - { - if (productToUpdate.Id != id) - return BadRequest($"Product id: {productToUpdate.Id} does not match with route id: {id}."); - - await _service.UpdateProductAsync(productToUpdate); - - return NoContent(); - } - - [HttpDelete("{id}")] - public async Task DeleteProductAsync(int id) - { - await _service.DeleteProductAsync(id); - - return NoContent(); - } - } -} diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SalesController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SalesController.cs deleted file mode 100644 index 2874b75..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SalesController.cs +++ /dev/null @@ -1,144 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.Sale; -using ReverseAnalytics.Domain.DTOs.SaleDetail; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - [Authorize] - [ApiController] - [Route("api/sales")] - public class SalesController : ControllerBase - { - private readonly ISaleService _saleService; - private readonly ISaleDetailService _saleDetailService; - - private const int PageSize = 15; - - public SalesController(ISaleService service, ISaleDetailService saleDetailService) - { - _saleService = service; - _saleDetailService = saleDetailService; - } - - #region CRUD - - [HttpGet] - public async Task>> GetSalesAsync(int pageSize = PageSize, int pageNumber = 1) - { - var sales = await _saleService.GetAllSalesAsync(pageSize, pageNumber); - - return Ok(sales); - } - - [HttpGet("{id}")] - public async Task> GetSaleByIdAsync(int id) - { - var sale = await _saleService.GetSaleByIdAsync(id); - - if (sale is null) - return NotFound($"There is no Sale with id: {id}."); - - return Ok(sale); - } - - [HttpPost] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateSalesAsync([FromBody] SaleForCreateDto saleToCreate) - { - var createdSale = await _saleService.CreateSaleAsync(saleToCreate); - - if (createdSale is null) - return StatusCode(500, - "Something went wrong while creating new Sale. Please, try again."); - - return Created("Sale was successfully created.", createdSale); - } - - [HttpPut("{id}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateSaleAsync([FromBody] SaleForUpdateDto saleToUpdate, int id) - { - if (saleToUpdate.Id != id) - return BadRequest($"Route id: {saleToUpdate.Id} does not match with route id: {id}."); - - await _saleService.UpdateSaleAsync(saleToUpdate); - - return NoContent(); - } - - [HttpDelete("{id}")] - public async Task DeleteSaleAsync(int id) - { - await _saleService.DeleteSaleAsync(id); - - return NoContent(); - } - - #endregion - - #region Details - - [HttpGet("{id}/details")] - public async Task>> GetSaleDetailsAsync(int id) - { - var saleDetails = await _saleDetailService.GetAllSaleDetailsBySaleIdAsync(id); - - return Ok(saleDetails); - } - - [HttpGet("{saleId}/details/{saleDetailId}")] - public async Task> GetSaleDetailByIdAsync(int saleId, int saleDetailId) - { - var saleDetail = await _saleDetailService.GetSaleDetailBySaleAndDetailIdAsync(saleId, saleDetailId); - - if (saleDetail is null) - return NotFound($"Sale with id: {saleId} does not have Detail with id: {saleDetailId}."); - - return Ok(saleDetail); - } - - [HttpPost("{saleId}/details")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateSaleDetail([FromBody] SaleDetailForCreateDto saleDetailToCreate, int saleId) - { - if (saleDetailToCreate.SaleId != saleId) - return BadRequest($"Sale id: {saleDetailToCreate.SaleId} does not match with route id: {saleId}."); - - var createdSaleDetail = await _saleDetailService.CreateSaleDetailAsync(saleDetailToCreate); - - if (createdSaleDetail is null) - return StatusCode(500, - "Something went wrong while creating new Sale. Please, try again later."); - - return Created("Sale detail was successfully created.", createdSaleDetail); - } - - [HttpPut("{saleId}/details/{saleDetailId}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateSaleDetailAsync([FromBody] SaleDetailForUpdateDto saleDetailToUpdate, int saleId, int saleDetailId) - { - if (saleDetailToUpdate.Id != saleId) - return BadRequest($"Sale Detail id: {saleDetailToUpdate.Id} does not match with route id: {saleDetailId}."); - - if (saleDetailToUpdate.SaleId != saleId) - return BadRequest($"Sale id: {saleDetailToUpdate.SaleId} does not match with route id: {saleId}."); - - await _saleDetailService.UpdateSaleDetailAsync(saleDetailToUpdate); - - return NoContent(); - } - - [HttpDelete("{id}/details/{saleDetailId}")] - public async Task DeleteSaleDetailAsync(int saleDetailId) - { - await _saleDetailService.DeleteSaleDetailAsync(saleDetailId); - - return NoContent(); - } - - #endregion - } -} \ No newline at end of file diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SuppliersController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SuppliersController.cs deleted file mode 100644 index 931d368..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SuppliersController.cs +++ /dev/null @@ -1,141 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.Debt; -using ReverseAnalytics.Domain.DTOs.Supplier; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - [Authorize] - [ApiController] - [Route("api/suppliers")] - public class SuppliersController : ControllerBase - { - private readonly ISupplierService _supplierService; - private readonly IDebtService _debtService; - - public SuppliersController(ISupplierService supplierService, IDebtService debtService) - { - _supplierService = supplierService; - _debtService = debtService; - } - - #region CRUD - - [HttpGet] - public async Task>> GetSuppliersAsync(string? searchString) - { - var suppliers = await _supplierService.GetAllSuppliersAsync(searchString); - - return Ok(suppliers); - } - - [HttpGet("{id}")] - public async Task> GetSupplierByIdAsync(int id) - { - var supplier = await _supplierService.GetSupplierByIdAsync(id); - - if (supplier is null) - return NotFound($"Supplier with id: {id} does not exist."); - - return Ok(supplier); - } - - [HttpPost] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateSupplierAsync([FromBody] SupplierForCreateDto supplierToCreate) - { - var createdSupplier = await _supplierService.CreateSupplierAsync(supplierToCreate); - - if (createdSupplier is null) - return StatusCode(500, "Something went wrong while creating new Supplier. Please, try again later."); - - return Created("Supplier was successfully created.", createdSupplier); - } - - [HttpPut("{id}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateSupplierAsync([FromBody] SupplierForUpdateDto supplierToUpdate, int id) - { - if (supplierToUpdate.Id != id) - return BadRequest($"Route id: {supplierToUpdate.Id} does not match with Supplier id: {id}"); - - await _supplierService.UpdateSupplierAsync(supplierToUpdate); - - return NoContent(); - } - - [HttpDelete("{id}")] - public async Task DeleteSupplierAsync(int id) - { - await _supplierService.DeleteSupplierAsync(id); - - return NoContent(); - } - - #endregion - - #region Debts - - [HttpGet("{supplierId}/debts")] - public async Task>> GetSupplierDebtsAsync(int supplierId) - { - var debts = await _debtService.GetAllDebtsByPersonIdAsync(supplierId); - - return Ok(debts); - } - - [HttpGet("{supplierId}/debts/{debtId}")] - public async Task> GetDebtBySupplierAndDebtIdAsync(int supplierId, int debtId) - { - var debt = await _debtService.GetByPersonAndDebtId(supplierId, debtId); - - if (debt is null) - return NotFound($"Supplier with id: {supplierId} does not have Debt with id: {debtId}."); - - return Ok(debt); - } - - [HttpPost("{supplierId}/debts")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateSupplierDebtAsync([FromBody] DebtForCreateDto debtToCreate, int supplierId) - { - if (debtToCreate.PersonId != supplierId) - return BadRequest($"Supplier Id: {debtToCreate.PersonId} does not match with route id: {supplierId}"); - - var createdSupplierDebt = await _debtService.CreateDebtAsync(debtToCreate); - - if (createdSupplierDebt is null) - return StatusCode(500, - "Something went wrong while creating new Supplier Debt. Please, try again later."); - - return Created("Debt was successfully created.", createdSupplierDebt); - } - - [HttpPut("{supplierId}/debts/{debtId}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateSupplierDebtAsync([FromBody] DebtForUpdateDto debtToUpdate, int supplierId, int debtId) - { - if (debtToUpdate.Id != debtId) - return BadRequest($"Debt id: {debtToUpdate.Id} does not match with route id: {debtId}."); - - if (debtToUpdate.PersonId != supplierId) - return BadRequest($"Supplier id: {debtToUpdate.PersonId} does not match with route id: {supplierId}."); - - await _debtService.UpdateDebtAsync(debtToUpdate); - - return NoContent(); - } - - [HttpDelete("{supplierId}/debts/{debtId}")] - public async Task DeleteSupplierDebtAsync(int debtId) - { - await _debtService.DeleteDebtAsync(debtId); - - return NoContent(); - } - - #endregion - } -} \ No newline at end of file diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SuppliesController.cs b/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SuppliesController.cs deleted file mode 100644 index 2cd708e..0000000 --- a/Reverse-Analytics/Reverse-Analytics.Api/Controllers/SuppliesController.cs +++ /dev/null @@ -1,142 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Reverse_Analytics.Api.Filters; -using ReverseAnalytics.Domain.DTOs.Supply; -using ReverseAnalytics.Domain.DTOs.SupplyDetail; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace Reverse_Analytics.Api.Controllers -{ - [Authorize] - [ApiController] - [Route("api/supplies")] - public class SuppliesController : ControllerBase - { - private readonly ISupplyService _service; - private readonly ISupplyDetailService _detailService; - - public SuppliesController(ISupplyService supplyService, ISupplyDetailService supplyDetailService) - { - _service = supplyService; - _detailService = supplyDetailService; - } - - #region CRUD - - [HttpGet] - public async Task>> GetAllSuppliesAsync() - { - var supplies = await _service.GetAllSuppliesAsync(); - - return Ok(supplies); - } - - [HttpGet("{supplyId}")] - public async Task> GetSupplyByIdAsync(int supplyId) - { - var supply = await _service.GetSupplyByIdAsync(supplyId); - - if (supply is null) - return NotFound($"Supply with id: {supplyId} does not exist."); - - return Ok(supply); - } - - [HttpPost] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateSupplyAsync([FromBody] SupplyForCreateDto supplyToCreate) - { - var createdSupply = await _service.CreateSupplyAsync(supplyToCreate); - - if (createdSupply is null) - return StatusCode(500, - "Something went wrong while creating new Supply. Please, try again later."); - - return Created("Supply was successfully created.", createdSupply); - } - - [HttpPut("{supplyId}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateSupplyAsync([FromBody] SupplyForUpdateDto supplyToUpdate, int supplyId) - { - if (supplyToUpdate.Id != supplyId) - return BadRequest($"Supply id: {supplyToUpdate.Id} does not match with route id: {supplyId}."); - - await _service.UpdateSupplyAsync(supplyToUpdate); - - return NoContent(); - } - - [HttpDelete("{supplyId}")] - public async Task DeleteSupplyAsync(int supplyId) - { - await _service.DeleteSupplyAsync(supplyId); - - return NoContent(); - } - - #endregion - - #region Details - - [HttpGet("{supplyId}/details")] - public async Task>> GetSupplyDetailsAsync(int supplyId) - { - var supplyDetails = await _detailService.GetAllSupplyDetailsBySupplyIdAsync(supplyId); - - return Ok(supplyDetails); - } - - [HttpGet("{supplyId}/details/{detailId}")] - public async Task> GetBySupplyAndDetailIdAsync(int supplyId, int detailId) - { - var supplyDetail = await _detailService.GetBySupplyAndDetailIdAsync(supplyId, detailId); - - if (supplyDetail is null) - return NotFound($"Supply with id: {supplyId} does not have Detail with id: {detailId}."); - - return Ok(supplyDetail); - } - - [HttpPost("{supplyId}/details")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task> CreateSupplyDetailAsync([FromBody]SupplyDetailForCreateDto supplyDetailToCreate, int supplyId) - { - if (supplyDetailToCreate.SupplyId != supplyId) - return BadRequest($"Supply id: {supplyDetailToCreate.SupplyId} does not match with route id: {supplyId}."); - - var createdSupplyDetail = await _detailService.CreateSupplyDetailAsync(supplyDetailToCreate); - - if (createdSupplyDetail is null) - return StatusCode(500, - "Something went wrong while creating new Supply detail. Please, try again later."); - - return Created("Supply detail was successfully created.", createdSupplyDetail); - } - - [HttpPut("{supplyId}/details/{supplyDetailId}")] - [ServiceFilter(typeof(ValidationFilterAttribute))] - public async Task UpdateSupplyDetailAsyc([FromBody] SupplyDetailForUpdateDto supplyDetailToUpdate, int supplyId, int supplyDetailId) - { - if (supplyDetailToUpdate.Id != supplyDetailId) - return BadRequest($"Detail id: {supplyDetailToUpdate.Id} does not match with route {supplyDetailId}."); - - if (supplyDetailToUpdate.SupplyId != supplyId) - return BadRequest($"Supply id: {supplyDetailToUpdate.SupplyId} does not match with route id: {supplyId}."); - - await _detailService.UpdateSupplyDetailAsync(supplyDetailToUpdate); - - return NoContent(); - } - - [HttpDelete("{supplyId}/details/{supplyDetailId}")] - public async Task DeleteSupplyDetailAsync(int supplyId, int supplyDetailId) - { - await _detailService.DeleteSupplyDetailAsync(supplyDetailId); - - return NoContent(); - } - - #endregion - } -} \ No newline at end of file diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Extensions/ConfigureServices.cs b/Reverse-Analytics/Reverse-Analytics.Api/Extensions/ConfigureServices.cs index 22c1641..7c5b075 100644 --- a/Reverse-Analytics/Reverse-Analytics.Api/Extensions/ConfigureServices.cs +++ b/Reverse-Analytics/Reverse-Analytics.Api/Extensions/ConfigureServices.cs @@ -1,86 +1,113 @@ -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Mvc; +using FluentValidation; +using FluentValidation.AspNetCore; using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; -using Reverse_Analytics.Api.Filters; +using Reverse_Analytics.Api.Configurations; using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Configurations; +using ReverseAnalytics.Domain.Interfaces.Services; +using ReverseAnalytics.Domain.Validators.Product; using ReverseAnalytics.Infrastructure.Persistence; using ReverseAnalytics.Infrastructure.Persistence.Interceptors; -using ReverseAnalytics.Repositories; -using System.Text; +using ReverseAnalytics.Infrastructure.Repositories; +using ReverseAnalytics.Services; -namespace Reverse_Analytics.Api.Extensions +namespace Reverse_Analytics.Api.Extensions; + +public static class ConfigureServices { - public static class ConfigureServices + public static IServiceCollection AddLogger(this IServiceCollection services) + { + return services; + } + + public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration) { - public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + var provider = configuration.GetValue("Provider", "SqlServer"); + + services.AddDbContext( + options => _ = provider switch + { + "Sqlite" => options.UseSqlite( + configuration.GetConnectionString("DefaultConnection"), + x => x.MigrationsAssembly("ReverseAnalytics.Migrations.Sqlite")), + + "SqlServer" => options.UseSqlServer( + configuration.GetConnectionString("DefaultConnection"), + x => x.MigrationsAssembly("ReverseAnalytics.Migrations.SqlServer")), + + _ => throw new InvalidOperationException($"Unsupported provider: {provider}.") + }); #if DEBUG - services.AddDbContext(options => - options.UseSqlite(configuration.GetConnectionString("DefaultConnection"))); - services.AddDbContext(options => - options.UseSqlite(configuration.GetConnectionString("DefaultIdentityConnection"))); #else - services.AddDbContext(options => - options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"), builder => - builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName))); + - services.AddDbContext(options => - options.UseSqlServer(configuration.GetConnectionString("DefaultIdentityConnection"), builder => - builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName))); + services.AddDbContext(options => + options.UseSqlServer(configuration.GetConnectionString("DefaultIdentityConnection"), builder => + builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName))); #endif + //services.AddScoped(); + //services.AddScoped(); + //services.AddScoped(); + //services.AddScoped(); + //services.AddScoped(); + //services.AddScoped(); - return services; - } + return services; + } - public static IServiceCollection ConfigureAuthentication(this IServiceCollection services, IConfiguration configuration) - { - var tokenOptions = configuration.GetSection("TokenOptions").Get(); + public static IServiceCollection AddRepositories(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(options => - { - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateIssuer = true, - ValidIssuer = tokenOptions.Issuer, - ValidateAudience = true, - ValidAudience = tokenOptions.Audience, - RequireExpirationTime = false, - ValidateIssuerSigningKey = true, - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOptions.SecurityKey)) - }; - }); - - return services; - } - - public static IServiceCollection ConfigureValidationFilter(this IServiceCollection services) - { - services.Configure(options => - options.SuppressModelStateInvalidFilter = true); - services.AddScoped(); - - return services; - } + return services; + } + + public static IServiceCollection AddValidators(this IServiceCollection services) + { + services.AddFluentValidationAutoValidation(); + services.AddValidatorsFromAssemblyContaining(); + + return services; + } + + public static IServiceCollection AddMappers(this IServiceCollection services) + { + services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); + + return services; + } + + public static IServiceCollection AddServices(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + + return services; + } + + public static IServiceCollection AddSwagger(this IServiceCollection services) + { + services.AddSwaggerGen(); + + return services; + } + + public static IServiceCollection AddConfigurations(this IServiceCollection services, IConfiguration configuration) + { + services.Configure(configuration.GetSection(DataSeedConfiguration.SECTION)); + + return services; } } diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Extensions/DbInitializer.cs b/Reverse-Analytics/Reverse-Analytics.Api/Extensions/DbInitializer.cs index 7764b73..c540a07 100644 --- a/Reverse-Analytics/Reverse-Analytics.Api/Extensions/DbInitializer.cs +++ b/Reverse-Analytics/Reverse-Analytics.Api/Extensions/DbInitializer.cs @@ -1,468 +1,192 @@ -using Bogus; -using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Options; +using Reverse_Analytics.Api.Configurations; using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Enums; using ReverseAnalytics.Infrastructure.Persistence; -using System.Diagnostics; +using ReverseAnalytics.TestDataCreator; -namespace Reverse_Analytics.Api.Extensions -{ - internal static class DbInitializer - { - public static IApplicationBuilder SeedDatabase(this IApplicationBuilder app) - { - ArgumentNullException.ThrowIfNull(app, nameof(app)); - - using var scope = app.ApplicationServices.CreateScope(); - var services = scope.ServiceProvider; +namespace Reverse_Analytics.Api.Extensions; - try - { - var context = services.GetRequiredService(); - var identityContext = services.GetRequiredService(); - var userManager = services.GetRequiredService>(); - - DbSeeder.Initialize(context, identityContext, userManager); - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - } +public class DatabaseSeeder(ApplicationDbContext context, IOptions options) +{ + private readonly ApplicationDbContext _context = context; + private readonly DataSeedConfiguration _options = options.Value; + private readonly Fakers _faker = new(); - return app; - } + public void Seed() + { + GenerateProductCategories(); + GenerateProducts(); + GenerateCustomers(); + GenerateSales(); + GenerateSaleItems(); + GenerateSuppliers(); + GenerateSupplies(); + GenerateSupplyItems(); + GenerateTransactions(); } - internal class DbSeeder + private void GenerateProductCategories() { - private static readonly Faker _faker = new(); - private static readonly Random _random = new(); - - public static void Initialize(ApplicationDbContext context, ApplicationIdentityDbContext identityContext, UserManager userManager) - { - try - { - //CreateProductCategories(context); - //CreateProducts(context); - //CreateCustomers(context); - //CreateSales(context); - //CreateSaleDetails(context); - //CreateSaleDebts(context); - //CreateSuppliers(context); - //CreateSupplyDebts(context); - //CreateSupplies(context); - //CreateSupplyDetails(context); - //CreateInventories(context); - //CreateInventoryDetails(context); - //CreateRoles(identityContext); - //CreateUsers(identityContext, userManager); - } - catch (Exception ex) - { - Debug.WriteLine(ex.Message); - } - } - - - private static void CreateProductCategories(ApplicationDbContext context) - { - if (context.ProductCategories.Any()) return; - - List productCategories = new(); - var fakeCategories = _faker.Commerce.Categories(25); - - for (int i = 0; i < 25; i++) - { - productCategories.Add( - new ProductCategory() - { - CategoryName = fakeCategories[i] - }); - } + if (_context.ProductCategories.Any()) return; - context.ProductCategories.AddRange(productCategories); - context.SaveChanges(); - } + HashSet categoryNames = []; - private static void CreateProducts(ApplicationDbContext context) + for (int i = 0; i < _options.CategoriesCount; i++) { - if (context.Products.Any()) return; + int attempts = 0; + var category = _faker.ProductCategory().Generate(); - var categories = context.ProductCategories.ToList(); - List products = new(); - - foreach (var category in categories) + // try to generate only unique values + while (categoryNames.Contains(category.Name) && attempts < 100) { - int numberOfProducts = _random.Next(1, 25); - - for (int i = 0; i < numberOfProducts; i++) - { - products.Add( - new Product() - { - ProductCode = _faker.Commerce.ProductAdjective(), - ProductName = _faker.Commerce.ProductName(), - Volume = (double)(_random.NextDouble() * _random.Next(1, 500)), - Weight = (double)(_random.NextDouble() * _random.Next(1, 600)), - SupplyPrice = Math.Round((decimal)_random.NextDouble() * 500, 2), - SalePrice = Math.Round((decimal)_random.NextDouble() * 800, 2), - UnitOfMeasurement = _faker.Random.Enum(), - CategoryId = category.Id - }); - } + category = _faker.ProductCategory().Generate(); + attempts++; } - context.Products.AddRange(products); - context.SaveChanges(); - } - - private static void CreateCustomers(ApplicationDbContext context) - { - if (context.Customers.Any()) return; - - // Customers - List customers = new(50); - - for (int i = 0; i < 50; i++) + // if unable to generate unique value, don't add to context + if (categoryNames.Contains(category.Name)) { - customers.Add(new Customer() - { - FullName = _faker.Person.FullName, - CompanyName = _faker.Company.CompanyName(), - Address = _faker.Address.FullAddress(), - PhoneNumber = _faker.Phone.PhoneNumber("(###) ##-###-##-##"), - Balance = _faker.Finance.Amount(0, 10000000), - Discount = _faker.Random.Double(0, 100), - IsActive = _faker.Random.Bool() - }); + continue; } - context.Customers.AddRange(customers); - context.SaveChanges(); + _context.ProductCategories.Add(category); } - private static void CreateSales(ApplicationDbContext context) - { - if (context.Sales.Any()) return; - - var customers = context.Customers.ToList(); - List sales = new(); + _context.SaveChanges(); + } - foreach (var customer in customers) - { - int salesCount = _random.Next(5, 25); - - for (int i = 0; i < salesCount; i++) - { - var totalDue = decimal.Round(_faker.Random.Decimal(10, 5000), 2); - var totalPaid = decimal.Round(_faker.Random.Decimal(0, totalDue), 2); - var discountPercentage = _faker.Random.Double(0, 100); - var discountTotal = decimal.Round((totalDue * (decimal)discountPercentage) / 100, 2); - - sales.Add( - new Sale() - { - TotalDue = totalDue, - TotalPaid = totalPaid, - TransactionDate = _faker.Date.Between(DateTime.Now.AddYears(-1), DateTime.Now), - Comments = _faker.Lorem.Sentence(), - Status = _faker.Random.Enum(), - Receipt = _faker.Random.Guid().ToString(), - Discount = discountTotal, - SaleType = _faker.Random.Enum(), - CustomerId = customer.Id - }); - } - } + private void GenerateProducts() + { + if (_context.Products.Any()) return; - context.Sales.AddRange(sales); - context.SaveChanges(); - } + HashSet productNames = []; + var categories = _context.ProductCategories.Select(x => x.Id).ToArray(); - private static void CreateSaleDetails(ApplicationDbContext context) + for (int i = 0; i < _options.ProductsCount; i++) { - if (context.SaleDetails.Any()) return; - - var sales = context.Sales.ToList(); - var products = context.Products.ToList(); - List orderItems = new(); + int attempts = 0; + var product = _faker.Product(categories).Generate(); - foreach (var sale in sales) + // try to generate only unique values + while (productNames.Contains(product.Name) && attempts < 100) { - var orderItemsCount = _random.Next(1, 15); - - for (int i = 0; i < orderItemsCount; i++) - { - orderItems.Add( - new SaleDetail() - { - Quantity = _random.Next(1, 20), - UnitPrice = decimal.Round(_faker.Random.Decimal(5, 500), 2), - SaleId = sale.Id, - ProductId = products[_random.Next(0, products.Count)]?.Id ?? 1 - }); - } + product = _faker.Product(categories).Generate(); + attempts++; } - context.SaleDetails.AddRange(orderItems); - context.SaveChanges(); - } - - private static void CreateSaleDebts(ApplicationDbContext context) - { - if (context.Debts.Any()) return; - - List debts = new List(); - var sales = context.Sales.ToList(); - - foreach (var sale in sales) + // if unable to generate unique value, don't add to context + if (productNames.Contains(product.Name)) { - if (_faker.Random.Bool()) - { - var totalAmount = sale.TotalDue - sale.TotalPaid; - var remainedAmount = _faker.Random.Decimal(0, totalAmount); - - DateTime? paidDate = remainedAmount == 0 ? _faker.Date.Between(sale.TransactionDate, DateTime.Now.AddMonths(5)) : null; - DebtStatus status = remainedAmount == 0 ? DebtStatus.Closed : DebtStatus.PaymentRequired; - - debts.Add(new Debt() - { - TotalAmount = totalAmount, - Remained = remainedAmount, - PaidDate = paidDate, - DueDate = _faker.Date.Between(sale.TransactionDate, DateTime.Now.AddMonths(5)), - Status = status, - TransactionId = sale.Id - }); - } + continue; } - context.Debts.AddRange(debts); - context.SaveChanges(); + _context.Products.Add(product); } - private static void CreateSuppliers(ApplicationDbContext context) - { - if (context.Suppliers.Any()) return; - - List suppliers = new List(); - - for (int i = 0; i < 25; i++) - { - suppliers.Add( - new Supplier() - { - FullName = _faker.Person.FullName, - Address = _faker.Address.FullAddress(), - PhoneNumber = _faker.Phone.PhoneNumber("(###) ##-###-##-##"), - CompanyName = _faker.Company.CompanyName(), - Balance = _faker.Random.Decimal(0, 10000), - IsActive = _faker.Random.Bool() - }); - } - - context.Suppliers.AddRange(suppliers); - context.SaveChanges(); - } + _context.SaveChanges(); + } - private static void CreateSupplies(ApplicationDbContext context) - { - if (context.Supplies.Any()) return; + private void GenerateCustomers() + { + if (_context.Customers.Any()) return; - var suppliers = context.Suppliers.ToList(); - List supplies = new(); + var customers = _faker.Customer().Generate(_options.CustomersCount); - foreach (var supplier in suppliers) - { - int suppliesCount = _random.Next(5, 25); - - for (int i = 0; i < suppliesCount; i++) - { - var totalDue = decimal.Round(_faker.Random.Decimal(10, 5000), 2); - var totalPaid = decimal.Round(_faker.Random.Decimal(100, totalDue), 2); - - supplies.Add( - new Supply() - { - TotalDue = totalDue, - TotalPaid = totalPaid, - TransactionDate = _faker.Date.Between(DateTime.Now.AddYears(-1), DateTime.Now), - Comments = _faker.Lorem.Sentence(), - Status = _faker.Random.Enum(), - ReceivedBy = _faker.Name.FirstName(), - SupplierId = supplier.Id - }); - } - } + _context.Customers.AddRange(customers); + _context.SaveChanges(); + } - context.Supplies.AddRange(supplies); - context.SaveChanges(); - } + private void GenerateSales() + { + if (_context.Sales.Any()) return; - private static void CreateSupplyDetails(ApplicationDbContext context) - { - if (context.SupplyDetails.Any()) return; + var customers = _context.Customers.Select(x => x.Id).ToArray(); + var sales = _faker.Sale(customers).Generate(_options.SalesCount); - var supplies = context.Supplies.ToList(); - var products = context.Products.ToList(); - List supplyDetails = new List(); + _context.Sales.AddRange(sales); + _context.SaveChanges(); + } - foreach (var supply in supplies) - { - int suppliesCount = _random.Next(1, 15); - - for (int i = 0; i < suppliesCount; i++) - { - supplyDetails.Add(new SupplyDetail() - { - Quantity = _random.Next(1, 20), - UnitPrice = decimal.Round(_faker.Random.Decimal(5, 500), 2), - - SupplyId = supply.Id, - ProductId = products[_random.Next(0, products.Count)]?.Id ?? 1 - }); - } - } + private void GenerateSaleItems() + { + if (_context.SaleItems.Any()) return; - context.SupplyDetails.AddRange(supplyDetails); - context.SaveChanges(); - } + var sales = _context.Sales.Select(x => x.Id).ToArray(); + var products = _context.Products.Select(x => x.Id).ToArray(); + var saleItems = _faker.SaleItems(sales, products).Generate(_options.SaleItemsCount); - private static void CreateSupplyDebts(ApplicationDbContext context) - { - if (context.Debts.Any()) return; + _context.SaleItems.AddRange(saleItems); + _context.SaveChanges(); + } - List debts = new List(); - var supplies = context.Supplies.ToList(); + private void GenerateSuppliers() + { + if (_context.Suppliers.Any()) return; - foreach (var supply in supplies) - { - if (_faker.Random.Bool()) - { - var totalAmount = supply.TotalDue - supply.TotalPaid; - var remainedAmount = _faker.Random.Decimal(0, totalAmount); - - DateTime? paidDate = remainedAmount == 0 ? _faker.Date.Between(supply.TransactionDate, DateTime.Now.AddMonths(5)) : null; - DebtStatus status = remainedAmount == 0 ? DebtStatus.Closed : DebtStatus.PaymentRequired; - - debts.Add(new Debt() - { - TotalAmount = totalAmount, - Remained = remainedAmount, - PaidDate = paidDate, - DueDate = _faker.Date.Between(supply.TransactionDate, DateTime.Now.AddMonths(5)), - Status = status - }); - } - } + var suppliers = _faker.Supplier().Generate(_options.SuppliersCount); - context.Debts.AddRange(debts); - context.SaveChanges(); - } + _context.Suppliers.AddRange(suppliers); + _context.SaveChanges(); + } - private static void CreateInventories(ApplicationDbContext context) - { - if (context.Inventories.Any()) return; + private void GenerateSupplies() + { + if (_context.Supplies.Any()) return; - List inventories = new List(); + var suppliers = _context.Suppliers.Select(x => x.Id).ToArray(); + var suppplies = _faker.Supply(suppliers).Generate(_options.SuppliesCount); - for (int i = 0; i < 5; i++) - { - inventories.Add(new Inventory(_faker.Lorem.Word())); - } + _context.Supplies.AddRange(suppplies); + _context.SaveChanges(); + } - context.Inventories.AddRange(inventories); - } + private void GenerateSupplyItems() + { + if (_context.SupplyItems.Any()) return; - private static void CreateInventoryDetails(ApplicationDbContext context) - { - if (context.InventoryDetails.Any()) return; + var supplies = _context.Supplies.Select(x => x.Id).ToArray(); + var products = _context.Products.Select(x => x.Id).ToArray(); + var supplyItems = _faker.SupplyItems(supplies, products).Generate(_options.SupplyItemsCount); - var inventories = context.Inventories.ToList(); - var products = context.Products.ToList(); - List inventoryDetails = new List(); + _context.SupplyItems.AddRange(supplyItems); + _context.SaveChanges(); + } - foreach (var inventory in inventories) - { - var randomProducts = GetRandomProducts(products); - - foreach (var product in randomProducts) - { - inventoryDetails.Add(new InventoryDetail() - { - InventoryId = inventory.Id, - ProductId = product.Id, - ProductsRemained = _faker.Random.Double(0, 300) - }); - } - } + private void GenerateTransactions() + { + if (_context.Transactions.Any()) return; - context.InventoryDetails.AddRange(inventoryDetails); - context.SaveChanges(); - } + var sales = _context.Sales.ToArray(); + var supplies = _context.Supplies.ToArray(); - private static void CreateRoles(ApplicationIdentityDbContext context) + foreach (var sale in sales) { - if (context.Roles.Any()) return; - - List roles = new(); - - roles.Add(new IdentityRole - { - Name = "Visitor", - NormalizedName = "VISITOR" - }); - roles.Add(new IdentityRole - { - Name = "Regular", - NormalizedName = "REGULAR" - }); - roles.Add(new IdentityRole + var transaction = new Transaction { - Name = "Accountant", - NormalizedName = "ACCOUNTANT" - }); - roles.Add(new IdentityRole - { - Name = "Manager", - NormalizedName = "MANAGER" - }); - roles.Add(new IdentityRole - { - Name = "Administrator", - NormalizedName = "ADMINISTRATOR" - }); + Date = sale.Date, + Amount = sale.GetTransactionAmount(), + Source = sale.TransactionSource, + Type = sale.TransactionType, + SourceId = sale.GetTransactionSourceId() + }; - context.Roles.AddRange(roles); - context.SaveChanges(); + _context.Transactions.Add(transaction); } - private static void CreateUsers(ApplicationIdentityDbContext context, UserManager userManager) + foreach (var supply in supplies) { - if (context.Users.Any()) return; - - var roles = context.Roles.ToList(); - - for (int i = 0; i < 20; i++) + var transaction = new Transaction { - var role = roles.ElementAt(_random.Next(0, roles.Count)); - - var user = new IdentityUser - { - UserName = _faker.Internet.UserName(), - }; + Date = supply.Date, + Amount = supply.GetTransactionAmount(), + Source = supply.TransactionSource, + Type = supply.TransactionType, + SourceId = supply.GetTransactionSourceId() + }; - userManager.CreateAsync(user, $"qwerty{i}").Wait(); - userManager.AddToRoleAsync(user, role.Name).Wait(); - } + _context.Transactions.Add(transaction); } - private static List GetRandomProducts(List products) - { - var half = products.Count / 2; - var start = _faker.Random.Int(0, half); - - return new List(products.Skip(start).Take(half)); - } + _context.SaveChanges(); } -} +} \ No newline at end of file diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Extensions/RegisterDependencyInjections.cs b/Reverse-Analytics/Reverse-Analytics.Api/Extensions/RegisterDependencyInjections.cs index 9fb94ba..04eee50 100644 --- a/Reverse-Analytics/Reverse-Analytics.Api/Extensions/RegisterDependencyInjections.cs +++ b/Reverse-Analytics/Reverse-Analytics.Api/Extensions/RegisterDependencyInjections.cs @@ -1,26 +1,10 @@ -using ReverseAnalytics.Domain.Interfaces.Services; -using ReverseAnalytics.Services; - -namespace Reverse_Analytics.Api.Extensions +namespace Reverse_Analytics.Api.Extensions { public static class RegisterDependencyInjections { public static void RegisterDependencyInjection(this IServiceCollection services) { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); } } } diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Helpers/ResourceLink.cs b/Reverse-Analytics/Reverse-Analytics.Api/Helpers/ResourceLink.cs new file mode 100644 index 0000000..e2ecb1e --- /dev/null +++ b/Reverse-Analytics/Reverse-Analytics.Api/Helpers/ResourceLink.cs @@ -0,0 +1,6 @@ +namespace Reverse_Analytics.Api.Helpers; + +public record ResourceLink( + string? Href, + string? Rel, + string Method); diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Helpers/ResourceUriType.cs b/Reverse-Analytics/Reverse-Analytics.Api/Helpers/ResourceUriType.cs new file mode 100644 index 0000000..da833fb --- /dev/null +++ b/Reverse-Analytics/Reverse-Analytics.Api/Helpers/ResourceUriType.cs @@ -0,0 +1,8 @@ +namespace Reverse_Analytics.Api.Helpers; + +public enum ResourceUriType +{ + PreviousPage, + NextPage, + Current +} \ No newline at end of file diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Middlewares/ErrorHandlerMiddeware.cs b/Reverse-Analytics/Reverse-Analytics.Api/Middlewares/ErrorHandlerMiddeware.cs index 819ef43..c2bb316 100644 --- a/Reverse-Analytics/Reverse-Analytics.Api/Middlewares/ErrorHandlerMiddeware.cs +++ b/Reverse-Analytics/Reverse-Analytics.Api/Middlewares/ErrorHandlerMiddeware.cs @@ -1,70 +1,48 @@ -using ReverseAnalytics.Domain.Exceptions; -using System.Net; +using System.Net; -namespace Reverse_Analytics.Api.Middlewares +namespace Reverse_Analytics.Api.Middlewares; + +public class ErrorHandlerMiddeware { - public class ErrorHandlerMiddeware + private readonly RequestDelegate _next; + private readonly ILogger _logger; + + public ErrorHandlerMiddeware(RequestDelegate next, ILogger logger) { - private readonly RequestDelegate _next; - private readonly ILogger _logger; + _next = next; + _logger = logger; + } - public ErrorHandlerMiddeware(RequestDelegate next, ILogger logger) + public async Task Invoke(HttpContext context) + { + try { - _next = next; - _logger = logger; + await _next(context); } - - public async Task Invoke(HttpContext context) + catch (Exception ex) { - try - { - await _next(context); - } - catch(Exception ex) - { - await HandleAsync(context, ex); - } + await HandleAsync(context, ex); } + } - private async Task HandleAsync(HttpContext context, Exception error) - { - context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; - context.Response.ContentType = "application/json"; - string message = "Internal error. Something went wrong."; - - if (error is NotFoundException) - { - context.Response.StatusCode = (int)HttpStatusCode.NotFound; - } - else if(error is ForbiddenAccessException) - { - context.Response.StatusCode = (int)HttpStatusCode.Forbidden; - } - - var errorResponse = new ErrorResponse() - { - EventId = new EventId(500, "Internal error"), - StatusCode = context.Response.StatusCode, - Message = message, - Path = context.Request.Path.ToString(), - Method = context.Request.Method, - Errors = GetErrorsList(error, new List()), - }; + private async Task HandleAsync(HttpContext context, Exception error) + { + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + context.Response.ContentType = "application/json"; + string message = "Internal error. Something went wrong."; - await context.Response.WriteAsync(errorResponse.ToJson()); - _logger.LogError(errorResponse.EventId, error, context.Request.Path.ToString()); - } + await context.Response.WriteAsync(message); + } - private static List GetErrorsList(Exception? error, List errorsList) + private static List GetErrorsList(Exception? error, List errorsList) + { + if (error is not null) { - if(error is not null) - { - errorsList.Add($"{error.GetType()}: '{error.Message}'"); - - return GetErrorsList(error.InnerException, errorsList); - } + errorsList.Add($"{error.GetType()}: '{error.Message}'"); - return errorsList; + return GetErrorsList(error.InnerException, errorsList); } + + return errorsList; } } diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Program.cs b/Reverse-Analytics/Reverse-Analytics.Api/Program.cs index 8c4ca08..53d1501 100644 --- a/Reverse-Analytics/Reverse-Analytics.Api/Program.cs +++ b/Reverse-Analytics/Reverse-Analytics.Api/Program.cs @@ -1,11 +1,10 @@ -using Microsoft.AspNetCore.Identity; +using Serilog; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Reverse_Analytics.Api.Extensions; using Reverse_Analytics.Api.Middlewares; -using ReverseAnalytics.Infrastructure.Configurations; using ReverseAnalytics.Infrastructure.Persistence; -using Serilog; +using ReverseAnalytics.TestDataCreator; Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() @@ -19,23 +18,15 @@ builder.Host.UseSerilog(); -// Add services to the container. -builder.Services.AddInfrastructureServices(builder.Configuration); -builder.Services.RegisterDependencyInjection(); -builder.Services.ConfigureValidationFilter(); - -// Identity -builder.Services.Configure(builder.Configuration.GetSection("TokenOptions")); -builder.Services.AddIdentity(options => -{ - options.Password.RequireDigit = false; - options.Password.RequiredLength = 4; - options.Password.RequireNonAlphanumeric = false; - options.Password.RequireUppercase = false; - options.Password.RequireLowercase = false; -}) - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); +builder.Services + .AddLogger() + .AddInfrastructure(builder.Configuration) + .AddRepositories() + .AddValidators() + .AddMappers() + .AddServices() + .AddSwagger() + .AddConfigurations(builder.Configuration); builder.Services.AddControllers(options => { @@ -49,18 +40,19 @@ }) .AddXmlDataContractSerializerFormatters(); -builder.Services.ConfigureAuthentication(builder.Configuration); - -builder.Services.AddSwaggerGen(); - var app = builder.Build(); // Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) +if (app.Environment.IsDevelopment() || app.Environment.IsStaging()) { app.UseSwagger(); app.UseSwaggerUI(); app.SeedDatabase(); + + using var scope = app.Services.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + var seeder = new DatabaseSeeder(context); + seeder.Seed(); } app.UseMiddleware(); @@ -74,3 +66,5 @@ app.MapControllers(); app.Run(); + +public partial class Program { } \ No newline at end of file diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Properties/launchSettings.json b/Reverse-Analytics/Reverse-Analytics.Api/Properties/launchSettings.json index af0d60e..7b2cf09 100644 --- a/Reverse-Analytics/Reverse-Analytics.Api/Properties/launchSettings.json +++ b/Reverse-Analytics/Reverse-Analytics.Api/Properties/launchSettings.json @@ -1,33 +1,41 @@ -{ - "$schema": "https://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:50902", - "sslPort": 44376 - } - }, +{ "profiles": { "Reverse_Analytics.Api": { "commandName": "Project", - "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", - "applicationUrl": "https://localhost:7231;http://localhost:5231", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }, - "devTunnelEnabled": true, - "devTunnelAccess": "Public" + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7231;http://localhost:5231" + }, + "Reverse_Analytics.Api-Staging": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Staging" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7231;http://localhost:5231" }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "launchUrl": "swagger", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Staging" } } + }, + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:50902", + "sslPort": 0 + } } -} +} \ No newline at end of file diff --git a/Reverse-Analytics/Reverse-Analytics.Api/ReverseAnalytics.Api.csproj b/Reverse-Analytics/Reverse-Analytics.Api/ReverseAnalytics.Api.csproj index 9850d4e..1acbbf8 100644 --- a/Reverse-Analytics/Reverse-Analytics.Api/ReverseAnalytics.Api.csproj +++ b/Reverse-Analytics/Reverse-Analytics.Api/ReverseAnalytics.Api.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 enable enable false @@ -12,26 +12,26 @@ + + - - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + @@ -41,9 +41,12 @@ + + + - + diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics.db b/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics.db index 21bb552..e713bda 100644 Binary files a/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics.db and b/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics.db differ diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics_identity.db b/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics_identity.db deleted file mode 100644 index 88d9584..0000000 Binary files a/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics_identity.db and /dev/null differ diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics_identity.db-shm b/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics_identity.db-shm deleted file mode 100644 index fe9ac28..0000000 Binary files a/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics_identity.db-shm and /dev/null differ diff --git a/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics_identity.db-wal b/Reverse-Analytics/Reverse-Analytics.Api/Storage/reverse_analytics_identity.db-wal deleted file mode 100644 index e69de29..0000000 diff --git a/Reverse-Analytics/Reverse-Analytics.Api/appsettings.Development.json b/Reverse-Analytics/Reverse-Analytics.Api/appsettings.Development.json index 29d7d4b..5b8ed82 100644 --- a/Reverse-Analytics/Reverse-Analytics.Api/appsettings.Development.json +++ b/Reverse-Analytics/Reverse-Analytics.Api/appsettings.Development.json @@ -5,12 +5,19 @@ "Microsoft.AspNetCore": "Warning" } }, - //"ConnectionStrings": { - // "DefaultConnection": "Data Source=LAPTOP-8BHP2JOL;Initial Catalog=Reverse_Analytics;Integrated Security=True", - // "DefaultIdentityConnection": "Data Source=LAPTOP-8BHP2JOL;Initial Catalog=Reverse_Analytics_Identity;Integrated Security=True" - //}, "ConnectionStrings": { "DefaultConnection": "Data Source = Storage\\reverse_analytics.db", "DefaultIdentityConnection": "Data Source= Storage\\reverse_analytics_identity.db" - } + }, + "DataSeed": { + "CategoriesCount": 10, + "ProductsCount": 50, + "CustomersCount": 20, + "SalesCount": 50, + "SaleItemsCount": 150, + "SuppliersCount": 20, + "SuppliesCount": 100, + "SupplyItemsCount": 150 + }, + "Provider": "Sqlite" } diff --git a/Reverse-Analytics/Reverse-Analytics.Api/appsettings.Staging.json b/Reverse-Analytics/Reverse-Analytics.Api/appsettings.Staging.json new file mode 100644 index 0000000..0332db5 --- /dev/null +++ b/Reverse-Analytics/Reverse-Analytics.Api/appsettings.Staging.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "DefaultConnection": "Data Source=EPUZTASW0537\\SQLEXPRESS;Initial Catalog=ReverseAnalytics;Integrated Security=True;Trust Server Certificate=True", + "DefaultIdentityConnection": "Data Source=EPUZTASW0537\\SQLEXPRESS;Initial Catalog=ReverseAnalyticsIdentity;Integrated Security=True;Trust Server Certificate=True" + }, + "Provider": "SqlServer" +} diff --git a/Reverse-Analytics/Reverse-Analytics.sln b/Reverse-Analytics/Reverse-Analytics.sln index cb4b15e..309aa12 100644 --- a/Reverse-Analytics/Reverse-Analytics.sln +++ b/Reverse-Analytics/Reverse-Analytics.sln @@ -9,9 +9,21 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseAnalytics.Domain", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseAnalytics.Infrastructure", "ReverseAnalytics.Infrastructure\ReverseAnalytics.Infrastructure.csproj", "{1F92F8F0-A90D-490E-8DDF-642C6F179E04}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReverseAnalytics.Repositories", "ReverseAnalytics.Repositories\ReverseAnalytics.Repositories.csproj", "{8B43698A-72CC-448E-9D88-EA36B36757EF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseAnalytics.TestDataCreator", "ReverseAnalytics.TestDataCreator\ReverseAnalytics.TestDataCreator.csproj", "{BC2C2A53-2414-4CC4-B89A-1A0889516F10}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReverseAnalytics.Services", "ReverseAnalytics.Services\ReverseAnalytics.Services.csproj", "{C90C86A0-123C-4F88-B9B0-813D518A5E38}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseAnalytics.Migrations.Sqlite", "Migrations\ReverseAnalytics.Migrations.Sqlite\ReverseAnalytics.Migrations.Sqlite.csproj", "{6863C9D3-3718-468C-90E6-CFF14663E70B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseAnalytics.Migrations.SqlServer", "Migrations\ReverseAnalytics.Migrations.SqlServer\ReverseAnalytics.Migrations.SqlServer.csproj", "{BFDF8903-DF51-46A8-8436-D7054A61B47D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Migrations", "Migrations", "{E83F6F45-0BBA-48B6-9D31-A4749A435983}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseAnalytics.Services", "ReverseAnalytics.Services\ReverseAnalytics.Services.csproj", "{E8F4610B-0CDB-491C-A260-8DAE4025522E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8978CC52-2806-4816-A2A0-6B4E4CD55F57}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseAnalytics.Tests.Unit", "Tests\ReverseAnalytics.Tests.Unit\ReverseAnalytics.Tests.Unit.csproj", "{5CD082B1-1139-40F3-A445-B30C0CA9EB0D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReverseAnalytics.Tests.Api", "ReverseAnalytics.Tests.Api\ReverseAnalytics.Tests.Api.csproj", "{EEFE90AB-E2C8-44B3-9FC6-B7235176AB64}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -31,18 +43,40 @@ Global {1F92F8F0-A90D-490E-8DDF-642C6F179E04}.Debug|Any CPU.Build.0 = Debug|Any CPU {1F92F8F0-A90D-490E-8DDF-642C6F179E04}.Release|Any CPU.ActiveCfg = Release|Any CPU {1F92F8F0-A90D-490E-8DDF-642C6F179E04}.Release|Any CPU.Build.0 = Release|Any CPU - {8B43698A-72CC-448E-9D88-EA36B36757EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8B43698A-72CC-448E-9D88-EA36B36757EF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8B43698A-72CC-448E-9D88-EA36B36757EF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8B43698A-72CC-448E-9D88-EA36B36757EF}.Release|Any CPU.Build.0 = Release|Any CPU - {C90C86A0-123C-4F88-B9B0-813D518A5E38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C90C86A0-123C-4F88-B9B0-813D518A5E38}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C90C86A0-123C-4F88-B9B0-813D518A5E38}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C90C86A0-123C-4F88-B9B0-813D518A5E38}.Release|Any CPU.Build.0 = Release|Any CPU + {BC2C2A53-2414-4CC4-B89A-1A0889516F10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC2C2A53-2414-4CC4-B89A-1A0889516F10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC2C2A53-2414-4CC4-B89A-1A0889516F10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC2C2A53-2414-4CC4-B89A-1A0889516F10}.Release|Any CPU.Build.0 = Release|Any CPU + {6863C9D3-3718-468C-90E6-CFF14663E70B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6863C9D3-3718-468C-90E6-CFF14663E70B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6863C9D3-3718-468C-90E6-CFF14663E70B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6863C9D3-3718-468C-90E6-CFF14663E70B}.Release|Any CPU.Build.0 = Release|Any CPU + {BFDF8903-DF51-46A8-8436-D7054A61B47D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BFDF8903-DF51-46A8-8436-D7054A61B47D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BFDF8903-DF51-46A8-8436-D7054A61B47D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BFDF8903-DF51-46A8-8436-D7054A61B47D}.Release|Any CPU.Build.0 = Release|Any CPU + {E8F4610B-0CDB-491C-A260-8DAE4025522E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E8F4610B-0CDB-491C-A260-8DAE4025522E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E8F4610B-0CDB-491C-A260-8DAE4025522E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E8F4610B-0CDB-491C-A260-8DAE4025522E}.Release|Any CPU.Build.0 = Release|Any CPU + {5CD082B1-1139-40F3-A445-B30C0CA9EB0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5CD082B1-1139-40F3-A445-B30C0CA9EB0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5CD082B1-1139-40F3-A445-B30C0CA9EB0D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5CD082B1-1139-40F3-A445-B30C0CA9EB0D}.Release|Any CPU.Build.0 = Release|Any CPU + {EEFE90AB-E2C8-44B3-9FC6-B7235176AB64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEFE90AB-E2C8-44B3-9FC6-B7235176AB64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEFE90AB-E2C8-44B3-9FC6-B7235176AB64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEFE90AB-E2C8-44B3-9FC6-B7235176AB64}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6863C9D3-3718-468C-90E6-CFF14663E70B} = {E83F6F45-0BBA-48B6-9D31-A4749A435983} + {BFDF8903-DF51-46A8-8436-D7054A61B47D} = {E83F6F45-0BBA-48B6-9D31-A4749A435983} + {5CD082B1-1139-40F3-A445-B30C0CA9EB0D} = {8978CC52-2806-4816-A2A0-6B4E4CD55F57} + {EEFE90AB-E2C8-44B3-9FC6-B7235176AB64} = {8978CC52-2806-4816-A2A0-6B4E4CD55F57} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AB93A27F-394C-45FF-B005-7DDE4ED5800A} EndGlobalSection diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseAuditableEntity.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseAuditableEntity.cs index 28d25dd..ad7d390 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseAuditableEntity.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseAuditableEntity.cs @@ -1,15 +1,12 @@ -using System; - -namespace ReverseAnalytics.Domain.Common +namespace ReverseAnalytics.Domain.Common { public abstract class BaseAuditableEntity : BaseEntity { - public DateTime Created { get; set; } - + public DateTime CreatedAt { get; set; } + public DateTime? LastModifiedAt { get; set; } public string? CreatedBy { get; set; } - - public DateTime? LastModified { get; set; } - public string? LastModifiedBy { get; set; } + public int? CreatedById { get; set; } + public int? LastModifiedById { get; set; } } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseEntity.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseEntity.cs index e5bae62..93e52ff 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseEntity.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseEntity.cs @@ -1,41 +1,40 @@ using System.ComponentModel.DataAnnotations.Schema; -namespace ReverseAnalytics.Domain.Common +namespace ReverseAnalytics.Domain.Common; + +public abstract class BaseEntity { - public abstract class BaseEntity - { - public int Id { get; set; } + public int Id { get; set; } - private readonly List _domainEvents = new List(); + private readonly List _domainEvents = []; - [NotMapped] - public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); + [NotMapped] + public IReadOnlyCollection DomainEvents => _domainEvents.AsReadOnly(); - public void AddDomainEvent(BaseEvent domainEvent) - { - if (domainEvent == null) - return; + public void AddDomainEvent(BaseEvent domainEvent) + { + if (domainEvent == null) + return; - if (_domainEvents.Contains(domainEvent)) - return; + if (_domainEvents.Contains(domainEvent)) + return; - _domainEvents.Add(domainEvent); - } + _domainEvents.Add(domainEvent); + } - public void RemoveDomainEvent(BaseEvent domainEvent) - { - if (domainEvent == null) - return; + public void RemoveDomainEvent(BaseEvent domainEvent) + { + if (domainEvent == null) + return; - if (!_domainEvents.Contains(domainEvent)) - return; + if (!_domainEvents.Contains(domainEvent)) + return; - _domainEvents.Remove(domainEvent); - } + _domainEvents.Remove(domainEvent); + } - public void ClearDomainEvents() - { - _domainEvents.Clear(); - } + public void ClearDomainEvents() + { + _domainEvents.Clear(); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseEvent.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseEvent.cs index 2f87102..32e149a 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseEvent.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Common/BaseEvent.cs @@ -1,8 +1,7 @@ using MediatR; -namespace ReverseAnalytics.Domain.Common +namespace ReverseAnalytics.Domain.Common; + +public abstract class BaseEvent : INotification { - public abstract class BaseEvent : INotification - { - } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Common/ITransaction.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Common/ITransaction.cs new file mode 100644 index 0000000..26b5089 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Common/ITransaction.cs @@ -0,0 +1,13 @@ +using ReverseAnalytics.Domain.Enums; + +namespace ReverseAnalytics.Domain.Common; + +public interface ITransaction +{ + TransactionType TransactionType { get; } + TransactionSource TransactionSource { get; } + PaymentType PaymentType { get; } + CurrencyType Currency { get; } + int GetTransactionSourceId(); + decimal GetTransactionAmount(); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Common/PaginatedList.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Common/PaginatedList.cs new file mode 100644 index 0000000..3ea3d7c --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Common/PaginatedList.cs @@ -0,0 +1,85 @@ +namespace ReverseAnalytics.Domain.Common; + +/// +/// Represents a paginated list of items. +/// +/// The type of items in the list. +public class PaginatedList : List +{ + /// + /// Gets the current page number. + /// + public int CurrentPage { get; private set; } + + /// + /// Gets the size of each page. + /// + public int PageSize { get; private set; } + + /// + /// Gets the total number of pages. + /// + public int PagesCount { get; private set; } + + /// + /// Gets the total number of items across all pages. + /// + public int TotalCount { get; private set; } + + /// + /// Determines whether there is a next page. + /// + public bool HasNext => CurrentPage < PagesCount; + + /// + /// Determines whether there is a previous page. + /// + public bool HasPrevious => CurrentPage > 1; + + /// + /// Initializes a new instance of the class. + /// + /// The list of items. + /// The current page number. + /// The size of each page. + /// The total number of items across all pages. + /// Thrown when the items list is null. + /// Thrown when invalid arguments are provided (e.g., negative totalCount, currentPage less than 1). + public PaginatedList(List items, int currentPage, int pageSize, int totalCount) + { + ArgumentNullException.ThrowIfNull(items); + + if (totalCount < 0) + throw new ArgumentException("Total count cannot be negative.", nameof(totalCount)); + + if (currentPage < 1) + throw new ArgumentException("Current page must be greater than 0.", nameof(currentPage)); + + if (pageSize < 1) + throw new ArgumentException("Page size must be greater than 0.", nameof(pageSize)); + + if (totalCount < items.Count) + throw new ArgumentException($"Total count: {totalCount} cannot be less than items count: {items.Count}.", nameof(totalCount)); + + if (items.Count == 0 && totalCount > 0) + throw new ArgumentException($"Total count cannot be greater than 0 when items empty.", nameof(totalCount)); + + TotalCount = totalCount; + CurrentPage = currentPage; + PageSize = pageSize; + PagesCount = (int)Math.Ceiling((double)totalCount / pageSize); + AddRange(items); + } + + /// + /// Converts the pagination information to . + /// + /// The pagination metadata. + public PaginationMetaData MetaData + => new(TotalCount, + PageSize, + CurrentPage, + PagesCount, + HasNext, + HasPrevious); +} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Common/PaginationMetaData.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Common/PaginationMetaData.cs new file mode 100644 index 0000000..07a44f3 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Common/PaginationMetaData.cs @@ -0,0 +1,9 @@ +namespace ReverseAnalytics.Domain.Common; + +public record PaginationMetaData( + int TotalCount, + int PageSize, + int CurrentPage, + int PagesCount, + bool HasNext, + bool HasPrevious); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Authentication/AuthenticationRequest.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Authentication/AuthenticationRequest.cs deleted file mode 100644 index f619be6..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Authentication/AuthenticationRequest.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.Authentication -{ - public class AuthenticationRequest - { - public string UserName { get; set; } - public string Password { get; set; } - } -} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Authentication/AuthenticationResponse.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Authentication/AuthenticationResponse.cs deleted file mode 100644 index d7df692..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Authentication/AuthenticationResponse.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.Authentication -{ - public class AuthenticationResponse - { - public string Message { get; set; } - public bool IsSuccess { get; set; } - public IEnumerable Errors { get; set; } - public DateTime? ExpireDate { get; set; } - - public AuthenticationResponse(string message, bool isSuccess, DateTime? expireDate) - { - Message = message; - IsSuccess = isSuccess; - ExpireDate = expireDate; - Errors = new List(); - } - - public AuthenticationResponse(string message, bool isSuccess, IEnumerable errors, DateTime? expireDate) - { - Message = message; - IsSuccess = isSuccess; - Errors = errors; - ExpireDate = expireDate; - } - } -} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerDto.cs index c4368f0..df6277c 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerDto.cs @@ -1,24 +1,13 @@ -using ReverseAnalytics.Domain.DTOs.Debt; -using ReverseAnalytics.Domain.DTOs.Sale; +using ReverseAnalytics.Domain.DTOs.Supply; -namespace ReverseAnalytics.Domain.DTOs.Customer -{ - public class CustomerDto - { - public int Id { get; set; } - public string FullName { get; set; } - public string? CompanyName { get; set; } - public string? Address { get; set; } - public string? PhoneNumber { get; set; } - public decimal Balance { get; set; } - public bool IsActive { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Customer; - public virtual ICollection Debts { get; set; } - public virtual ICollection Sales { get; set; } - - public CustomerDto() - { - FullName = ""; - } - } -} +public record CustomerDto( + int Id, + string FullName, + string PhoneNumber, + string? Address, + string? Company, + decimal Balance, + double Discount, + ICollection Sales); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerForCreateDto.cs index e1a9801..cd91bda 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerForCreateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerForCreateDto.cs @@ -1,13 +1,9 @@ -namespace ReverseAnalytics.Domain.DTOs.Customer -{ - public class CustomerForCreateDto - { - public string FullName { get; set; } - public string? CompanyName { get; set; } - public string? Address { get; set; } - public string? PhoneNumber { get; set; } - public decimal Balance { get; set; } - public double Discount { get; set; } - public bool IsActive { get; set; } - } -} +namespace ReverseAnalytics.Domain.DTOs.Customer; + +public record CustomerForCreateDto( + string FirstName, + string LastName, + string PhoneNumber, + string? Address, + string? Company, + double Discount); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerForUpdateDto.cs index c7b6e50..bc3ce7b 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerForUpdateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Customer/CustomerForUpdateDto.cs @@ -1,14 +1,11 @@ -namespace ReverseAnalytics.Domain.DTOs.Customer -{ - public class CustomerForUpdateDto - { - public int Id { get; set; } - public string FullName { get; set; } - public string? CompanyName { get; set; } - public string? Address { get; set; } - public string? PhoneNumber { get; set; } - public decimal Balance { get; set; } - public double Discount { get; set; } - public bool IsActive { get; set; } - } -} +namespace ReverseAnalytics.Domain.DTOs.Customer; + +public record CustomerForUpdateDto( + int Id, + string FirstName, + string LastName, + string PhoneNumber, + string? Address, + string? Company, + decimal Balance, + double Discount); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtDto.cs deleted file mode 100644 index 7e1a872..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtDto.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.Debt -{ - public class DebtDto - { - public int Id { get; set; } - public decimal Amount { get; set; } - public DateTime DebtDate { get; set; } - public DateTime? PaidDate { get; set; } - public DateTime DueDate { get; set; } - - public int PersonId { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtForCreateDto.cs deleted file mode 100644 index 25b0bd6..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtForCreateDto.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.Debt -{ - public class DebtForCreateDto - { - public decimal Amount { get; set; } - public DateTime DebtDate { get; set; } - public DateTime? PaidDate { get; set; } - public DateTime DueDate { get; set; } - - public int PersonId { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtForUpdateDto.cs deleted file mode 100644 index e6e15da..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Debt/DebtForUpdateDto.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.Debt -{ - public class DebtForUpdateDto - { - public int Id { get; set; } - public decimal Amount { get; set; } - public DateTime DebtDate { get; set; } - public DateTime? PaidDate { get; set; } - public DateTime DueDate { get; set; } - - public int PersonId { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/PasswordReset/PasswordResetRequest.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/PasswordReset/PasswordResetRequest.cs deleted file mode 100644 index 84da6fe..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/PasswordReset/PasswordResetRequest.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.PasswordReset -{ - public class PasswordResetRequest - { - public string UserName { get; set; } - public string NewPassword { get; set; } - public string ConfirmPassword { get; set; } - public string Token { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/PasswordReset/PasswordResetResponse.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/PasswordReset/PasswordResetResponse.cs deleted file mode 100644 index 455c56b..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/PasswordReset/PasswordResetResponse.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.PasswordReset -{ - public class PasswordResetResponse - { - public bool IsSuccess { get; set; } - public string Message { get; set; } - public List Errors { get; set; } - } - - public class ResponseError - { - public string Description { get; set; } - public string Code { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductDto.cs index a783442..d19ba0b 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductDto.cs @@ -1,20 +1,16 @@ -using ReverseAnalytics.Domain.DTOs.ProductCategory; -using ReverseAnalytics.Domain.Enums; +using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Product -{ - public class ProductDto - { - public int Id { get; set; } - public string ProductName { get; set; } - public string ProductCode { get; set; } - public UnitOfMeasurement UnitOfMeasurement { get; set; } - public double? Volume { get; set; } - public double? Weight { get; set; } - public decimal SupplyPrice { get; set; } - public decimal SalePrice { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Product; - public int CategoryId { get; set; } - public virtual ProductCategoryDto Category { get; set; } - } -} +public record ProductDto( + int Id, + string Name, + string Code, + string? Description, + decimal SalePrice, + decimal SupplyPrice, + double? Volume, + double? Weight, + UnitOfMeasurement UnitOfMeasurement, + int CategoryId, + string CategoryName); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductForCreateDto.cs index 926b82f..6b8ef56 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductForCreateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductForCreateDto.cs @@ -1,17 +1,14 @@ using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Product -{ - public class ProductForCreateDto - { - public string ProductName { get; set; } - public string ProductCode { get; set; } - public UnitOfMeasurement UnitOfMeasurement { get; set; } - public double? Volume { get; set; } - public double? Weight { get; set; } - public decimal SupplyPrice { get; set; } - public decimal SalePrice { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Product; - public int CategoryId { get; set; } - } -} +public record ProductForCreateDto( + string Name, + string Code, + string? Description, + decimal SalePrice, + decimal SupplyPrice, + double? Volume, + double? Weight, + UnitOfMeasurement UnitOfMeasurement, + int CategoryId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductForUpdateDto.cs index 961dadc..4c31cf4 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductForUpdateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Product/ProductForUpdateDto.cs @@ -1,18 +1,15 @@ using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Product -{ - public class ProductForUpdateDto - { - public int Id { get; set; } - public string ProductName { get; set; } - public string ProductCode { get; set; } - public UnitOfMeasurement UnitOfMeasurement { get; set; } - public double? Volume { get; set; } - public double? Weight { get; set; } - public decimal SupplyPrice { get; set; } - public decimal SalePrice { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Product; - public int CategoryId { get; set; } - } -} +public record ProductForUpdateDto( + int Id, + string Name, + string Code, + string? Description, + decimal SalePrice, + decimal SupplyPrice, + double? Volume, + double? Weight, + UnitOfMeasurement UnitOfMeasurement, + int CategoryId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryDto.cs index 667af2e..2f6ee07 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryDto.cs @@ -1,8 +1,12 @@ -namespace ReverseAnalytics.Domain.DTOs.ProductCategory -{ - public class ProductCategoryDto - { - public int Id { get; set; } - public string CategoryName { get; set; } - } -} +using ReverseAnalytics.Domain.DTOs.Product; + +namespace ReverseAnalytics.Domain.DTOs.ProductCategory; + +public record ProductCategoryDto( + int Id, + string Name, + string? Description, + int? ParentId, + string? ParentName, + ICollection Products, + ICollection SubCategories); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryForCreateDto.cs index 38a8749..52672f8 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryForCreateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryForCreateDto.cs @@ -1,12 +1,7 @@ -namespace ReverseAnalytics.Domain.DTOs.ProductCategory -{ - public class ProductCategoryForCreateDto - { - public string CategoryName { get; set; } +namespace ReverseAnalytics.Domain.DTOs.ProductCategory; - public ProductCategoryForCreateDto(string categoryName) - { - CategoryName = categoryName; - } - } -} +public record ProductCategoryForCreateDto( + string Name, + string? Description, + int? ParentId, + ICollection? SubCategories); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryForUpdateDto.cs index add3039..29473c4 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryForUpdateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/ProductCategory/ProductCategoryForUpdateDto.cs @@ -1,14 +1,7 @@ -namespace ReverseAnalytics.Domain.DTOs.ProductCategory -{ - public class ProductCategoryForUpdateDto - { - public int Id { get; set; } - public string CategoryName { get; set; } +namespace ReverseAnalytics.Domain.DTOs.ProductCategory; - public ProductCategoryForUpdateDto(int id, string categoryName) - { - Id = id; - CategoryName = categoryName; - } - } -} +public record ProductCategoryForUpdateDto( + int Id, + string Name, + string? Description, + int? ParentId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleDto.cs index 97d41da..bb01f35 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleDto.cs @@ -1,25 +1,18 @@ using ReverseAnalytics.Domain.DTOs.Customer; -using ReverseAnalytics.Domain.DTOs.SaleDetail; +using ReverseAnalytics.Domain.DTOs.SaleItem; using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Sale -{ - public class SaleDto - { - public int Id { get; set; } - public string Receipt { get; set; } - public string? Comment { get; set; } - public decimal TotalDue { get; set; } - public decimal TotalPaid { get; set; } - public double? DiscountPercentage { get; set; } - public decimal? DiscountTotal { get; set; } - public DateTime SaleDate { get; set; } - public SaleType SaleType { get; set; } - public TransactionStatus Status { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Sale; - public int CustomerId { get; set; } - public virtual CustomerDto Customer { get; set; } - - public virtual ICollection Details { get; set; } - } -} +public record SaleDto( + int Id, + DateTime Date, + string? Comments, + decimal TotalPaid, + decimal TotalDiscount, + SaleType SaleType, + SaleStatus Status, + PaymentType PaymentType, + CurrencyType CurrencyType, + CustomerDto Customer, + ICollection SaleItems); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleForCreateDto.cs index 26a9cee..52c6e74 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleForCreateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleForCreateDto.cs @@ -1,27 +1,16 @@ -using ReverseAnalytics.Domain.DTOs.SaleDetail; +using ReverseAnalytics.Domain.DTOs.SaleItem; using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Sale -{ - public class SaleForCreateDto - { - public string Receipt { get; set; } - public string? Comment { get; set; } - public decimal TotalDue { get; set; } - public decimal TotalPaid { get; set; } - public double? DiscountPercentage { get; set; } - public decimal? DiscountTotal { get; set; } - public DateTime SaleDate { get; set; } - public SaleType SaleType { get; set; } - public TransactionStatus Status { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Sale; - public int CustomerId { get; set; } - - public ICollection SaleDetails { get; set; } - - public SaleForCreateDto() - { - SaleDetails = new List(); - } - } -} +public record SaleForCreateDto( + DateTime Date, + string? Comments, + decimal TotalPaid, + decimal TotalDiscount, + SaleType SaleType, + SaleStatus Status, + PaymentType PaymentType, + CurrencyType CurrencyType, + int CustomerId, + ICollection SaleItems); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleForUpdateDto.cs index 5486c69..b273d72 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleForUpdateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Sale/SaleForUpdateDto.cs @@ -1,20 +1,16 @@ using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Sale -{ - public class SaleForUpdateDto - { - public int Id { get; set; } - public string Receipt { get; set; } - public string? Comment { get; set; } - public decimal TotalDue { get; set; } - public decimal TotalPaid { get; set; } - public double? DiscountPercentage { get; set; } - public decimal? DiscountTotal { get; set; } - public DateTime SaleDate { get; set; } - public SaleType SaleType { get; set; } - public TransactionStatus Status { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Sale; - public int CustomerId { get; set; } - } -} +public record SaleForUpdateDto( + int Id, + DateTime Date, + string? Comments, + decimal TotalDue, + decimal TotalPaid, + decimal TotalDiscount, + SaleType SaleType, + SaleStatus Status, + PaymentType PaymentType, + CurrencyType CurrencyType, + int CustomerId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailDto.cs deleted file mode 100644 index f271da4..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailDto.cs +++ /dev/null @@ -1,19 +0,0 @@ -using ReverseAnalytics.Domain.DTOs.Product; -using ReverseAnalytics.Domain.DTOs.Sale; - -namespace ReverseAnalytics.Domain.DTOs.SaleDetail -{ - public class SaleDetailDto - { - public int Id { get; set; } - public int Quantity { get; set; } - public decimal UnitPrice { get; set; } - public double Discount { get; set; } - - public int SaleId { get; set; } - public virtual SaleDto Sale { get; set; } - - public int ProductId { get; set; } - public virtual ProductDto Product { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailForCreateDto.cs deleted file mode 100644 index daa63d2..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailForCreateDto.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.SaleDetail -{ - public class SaleDetailForCreateDto - { - public int Quantity { get; set; } - public decimal UnitPrice { get; set; } - public double Discount { get; set; } - - public int SaleId { get; set; } - public int ProductId { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailForUpdateDto.cs deleted file mode 100644 index 1857898..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleDetail/SaleDetailForUpdateDto.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.SaleDetail -{ - public class SaleDetailForUpdateDto - { - public int Id { get; set; } - public int Quantity { get; set; } - public decimal UnitPrice { get; set; } - public double Discount { get; set; } - - public int SaleId { get; set; } - public int ProductId { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemDto.cs new file mode 100644 index 0000000..88630a1 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemDto.cs @@ -0,0 +1,12 @@ +using ReverseAnalytics.Domain.DTOs.Product; +using ReverseAnalytics.Domain.DTOs.Sale; + +namespace ReverseAnalytics.Domain.DTOs.SaleItem; + +public record SaleItemDto( + int Id, + int Quantity, + decimal UnitPrice, + decimal Discount, + SaleDto Sale, + ProductDto Product); \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemForCreateDto.cs new file mode 100644 index 0000000..fc8a536 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemForCreateDto.cs @@ -0,0 +1,8 @@ +namespace ReverseAnalytics.Domain.DTOs.SaleItem; + +public record SaleItemForCreateDto( + int Quantity, + decimal UnitPrice, + decimal Discount, + int SaleId, + int ProductId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemForUpdateDto.cs new file mode 100644 index 0000000..44c485e --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SaleItem/SaleItemForUpdateDto.cs @@ -0,0 +1,9 @@ +namespace ReverseAnalytics.Domain.DTOs.SaleItem; + +public record SaleItemForUpdateDto( + int Id, + int Quantity, + decimal UnitPrice, + decimal Discount, + int SaleId, + int ProductId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierDto.cs index 6140979..bad35ec 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierDto.cs @@ -1,17 +1,11 @@ -using ReverseAnalytics.Domain.DTOs.Debt; +using ReverseAnalytics.Domain.DTOs.Supply; -namespace ReverseAnalytics.Domain.DTOs.Supplier -{ - public class SupplierDto - { - public int Id { get; set; } - public string FullName { get; set; } - public string? CompanyName { get; set; } - public string? Address { get; set; } - public string? PhoneNumber { get; set; } - public decimal Balance { get; set; } - public bool IsActive { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Supplier; - public ICollection Debts { get; set; } - } -} +public record SupplierDto( + int Id, + string FullName, + string PhoneNumber, + string Company, + decimal Balance, + ICollection Supplies); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierForCreateDto.cs index 470a48f..298e6a2 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierForCreateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierForCreateDto.cs @@ -1,10 +1,8 @@ -namespace ReverseAnalytics.Domain.DTOs.Supplier -{ - public class SupplierForCreateDto - { - public string FullName { get; set; } - public string? CompanyName { get; set; } - public decimal Balance { get; set; } - public bool IsActive { get; set; } - } -} +namespace ReverseAnalytics.Domain.DTOs.Supplier; + +public record SupplierForCreateDto( + string FirstName, + string LastName, + string PhoneNumber, + string Company, + decimal Balance); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierForUpdateDto.cs index 4c734ca..0324174 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierForUpdateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supplier/SupplierForUpdateDto.cs @@ -1,11 +1,9 @@ -namespace ReverseAnalytics.Domain.DTOs.Supplier -{ - public class SupplierForUpdateDto - { - public int Id { get; set; } - public string FullName { get; set; } - public string? CompanyName { get; set; } - public decimal Balance { get; set; } - public bool IsActive { get; set; } - } -} +namespace ReverseAnalytics.Domain.DTOs.Supplier; + +public record SupplierForUpdateDto( + int Id, + string FirstName, + string LastName, + string PhoneNumber, + string Company, + decimal Balance); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyDto.cs index d318c8c..fdcb38a 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyDto.cs @@ -1,19 +1,15 @@ using ReverseAnalytics.Domain.DTOs.Supplier; -using System.Transactions; +using ReverseAnalytics.Domain.DTOs.SupplyItem; +using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Supply -{ - public class SupplyDto - { - public int Id { get; set; } - public string? ReceivedBy { get; set; } - public string? Comment { get; set; } - public DateTime? SupplyDate { get; set; } - public decimal TotalDue { get; set; } - public decimal TotalPaid { get; set; } - public TransactionStatus Status { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Supply; - public int SupplierId { get; set; } - public SupplierDto Supplier { get; set; } - } -} +public record SupplyDto( + int Id, + DateTime Date, + string? Comments, + decimal TotalPaid, + PaymentType PaymentType, + CurrencyType CurrencyType, + SupplierDto Customer, + ICollection SupplyItems); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyForCreateDto.cs index 4394908..1ba6906 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyForCreateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyForCreateDto.cs @@ -1,16 +1,13 @@ -using System.Transactions; +using ReverseAnalytics.Domain.DTOs.SupplyItem; +using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Supply -{ - public class SupplyForCreateDto - { - public string? ReceivedBy { get; set; } - public string? Comment { get; set; } - public DateTime? SupplyDate { get; set; } - public decimal TotalDue { get; set; } - public decimal TotalPaid { get; set; } - public TransactionStatus Status { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Sale; - public int SupplierId { get; set; } - } -} +public record SupplyForCreateDto( + DateTime Date, + string? Comments, + decimal TotalPaid, + PaymentType PaymentType, + CurrencyType CurrencyType, + int SupplierId, + ICollection SupplyItems); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyForUpdateDto.cs index c9e228c..0f42ba2 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyForUpdateDto.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Supply/SupplyForUpdateDto.cs @@ -1,17 +1,12 @@ -using System.Transactions; +using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.DTOs.Supply -{ - public class SupplyForUpdateDto - { - public int Id { get; set; } - public string? ReceivedBy { get; set; } - public string? Comment { get; set; } - public DateTime? SupplyDate { get; set; } - public decimal TotalDue { get; set; } - public decimal TotalPaid { get; set; } - public TransactionStatus Status { get; set; } +namespace ReverseAnalytics.Domain.DTOs.Sale; - public int SupplierId { get; set; } - } -} +public record SupplyForUpdateDto( + int Id, + DateTime Date, + string? Comments, + decimal TotalPaid, + PaymentType PaymentType, + CurrencyType CurrencyType, + int SupplierId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailDto.cs deleted file mode 100644 index 6a95634..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailDto.cs +++ /dev/null @@ -1,18 +0,0 @@ -using ReverseAnalytics.Domain.DTOs.Product; -using ReverseAnalytics.Domain.DTOs.Supply; - -namespace ReverseAnalytics.Domain.DTOs.SupplyDetail -{ - public class SupplyDetailDto - { - public int Id { get; set; } - public int Quantity { get; set; } - public decimal UnitPrice { get; set; } - - public int SupplyId { get; set; } - public SupplyDto Supply { get; set; } - - public int ProductId { get; set; } - public ProductDto Product { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailForCreateDto.cs deleted file mode 100644 index 3c5ebf6..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailForCreateDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.SupplyDetail -{ - public class SupplyDetailForCreateDto - { - public int Quantity { get; set; } - public decimal UnitPrice { get; set; } - - public int SupplyId { get; set; } - public int ProductId { get; set; } - } -} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailForUpdateDto.cs deleted file mode 100644 index 06e68ed..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyDetail/SupplyDetailForUpdateDto.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.SupplyDetail -{ - public class SupplyDetailForUpdateDto - { - public int Id { get; set; } - public int Quantity { get; set; } - public decimal UnitPrice { get; set; } - - public int SupplyId { get; set; } - public int ProductId { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemDto.cs new file mode 100644 index 0000000..98c0278 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemDto.cs @@ -0,0 +1,12 @@ +using ReverseAnalytics.Domain.DTOs.Product; +using ReverseAnalytics.Domain.DTOs.Supply; + +namespace ReverseAnalytics.Domain.DTOs.SupplyItem; + +public record SupplyItemDto( + int Id, + int Quantity, + decimal UnitPrice, + decimal Discount, + SupplyDto Sale, + ProductDto Product); \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemForCreateDto.cs new file mode 100644 index 0000000..24f2e17 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemForCreateDto.cs @@ -0,0 +1,8 @@ +namespace ReverseAnalytics.Domain.DTOs.SupplyItem; + +public record SupplyItemForCreateDto( + int Quantity, + decimal UnitPrice, + decimal Discount, + int SupplyId, + int ProductId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemForUpdateDto.cs new file mode 100644 index 0000000..18c409e --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/SupplyItem/SupplyItemForUpdateDto.cs @@ -0,0 +1,9 @@ +namespace ReverseAnalytics.Domain.DTOs.SupplyItem; + +public record SupplyItemForUpdateDto( + int Id, + int Quantity, + decimal UnitPrice, + decimal Discount, + int SupplyId, + int ProductId); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionDto.cs new file mode 100644 index 0000000..e931a38 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionDto.cs @@ -0,0 +1,11 @@ +using ReverseAnalytics.Domain.Enums; + +namespace ReverseAnalytics.Domain.DTOs.Transaction; + +public record TransactionDto( + int Id, + DateTime Date, + int? SourceId, + decimal Amount, + TransactionType Type, + TransactionSource? Source); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionForCreateDto.cs new file mode 100644 index 0000000..9aea4d7 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionForCreateDto.cs @@ -0,0 +1,10 @@ +using ReverseAnalytics.Domain.Enums; + +namespace ReverseAnalytics.Domain.DTOs.Transaction; + +public record TransactionForCreateDto( + DateTime Date, + int? SourceId, + decimal Amount, + TransactionType Type, + TransactionSource? Source); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionForUpdateDto.cs new file mode 100644 index 0000000..4e57cdb --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/Transaction/TransactionForUpdateDto.cs @@ -0,0 +1,11 @@ +using ReverseAnalytics.Domain.Enums; + +namespace ReverseAnalytics.Domain.DTOs.Transaction; + +public record TransactionForUpdateDto( + int Id, + DateTime Date, + int? SourceId, + decimal Amount, + TransactionType Type, + TransactionSource? Source); diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountDto.cs deleted file mode 100644 index eb176a0..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountDto.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.UserAccount -{ - public class UserAccountDto - { - public string Id { get; set; } - public string UserName { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountForCreateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountForCreateDto.cs deleted file mode 100644 index 675eda3..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountForCreateDto.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace ReverseAnalytics.Domain.DTOs.UserAccount -{ - public class UserAccountForCreateDto - { - [Required(ErrorMessage = "User name is required.")] - public string UserName { get; set; } - - [Required(ErrorMessage = "Login is required.")] - [DataType(DataType.Password)] - public string Password { get; set; } - - [DataType(DataType.Password)] - [Compare(nameof(Password), ErrorMessage = "The password and confirmation password do not match.")] - public string ConfirmPassword { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountForUpdateDto.cs b/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountForUpdateDto.cs deleted file mode 100644 index ff34297..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/DTOs/UserAccount/UserAccountForUpdateDto.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace ReverseAnalytics.Domain.DTOs.UserAccount -{ - public class UserAccountForUpdateDto - { - public string Id { get; set; } - public string UserName { get; set; } - } -} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Customer.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Customer.cs index 9fd43df..09caaf1 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Customer.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Customer.cs @@ -1,9 +1,21 @@ -namespace ReverseAnalytics.Domain.Entities +using ReverseAnalytics.Domain.Common; + +namespace ReverseAnalytics.Domain.Entities; + +public class Customer : BaseAuditableEntity { - public class Customer : Person - { - public double Discount { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string PhoneNumber { get; set; } + public string? Address { get; set; } + public string? Company { get; set; } + public decimal Balance { get; set; } + public double Discount { get; set; } - public virtual ICollection Sales { get; set; } + public virtual ICollection Sales { get; set; } + + public Customer() + { + Sales = []; } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Debt.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Debt.cs deleted file mode 100644 index 1f3bc76..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Debt.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ReverseAnalytics.Domain.Common; -using ReverseAnalytics.Domain.Enums; - -namespace ReverseAnalytics.Domain.Entities -{ - public class Debt : BaseAuditableEntity - { - public decimal TotalAmount { get; set; } - public decimal Remained { get; set; } - public DateTime? PaidDate { get; set; } - public DateTime? DueDate { get; set; } - public DebtStatus Status { get; set; } - - public int TransactionId { get; set; } - public virtual Transaction Transaction { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Inventory.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Inventory.cs deleted file mode 100644 index 1263ae5..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Inventory.cs +++ /dev/null @@ -1,18 +0,0 @@ -using ReverseAnalytics.Domain.Common; - -namespace ReverseAnalytics.Domain.Entities -{ - public class Inventory : BaseAuditableEntity - { - public string Name { get; set; } - - public virtual ICollection Details { get; set; } - - public Inventory(string name) - { - Name = name; - - Details = new List(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/InventoryDetail.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/InventoryDetail.cs deleted file mode 100644 index 0886754..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/InventoryDetail.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ReverseAnalytics.Domain.Common; - -namespace ReverseAnalytics.Domain.Entities -{ - public class InventoryDetail : BaseAuditableEntity - { - public double ProductsRemained { get; set; } - - public int InventoryId { get; set; } - public Inventory Inventory { get; set; } - public int ProductId { get; set; } - public Product Product { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Person.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Person.cs deleted file mode 100644 index 04e184c..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Person.cs +++ /dev/null @@ -1,23 +0,0 @@ -using ReverseAnalytics.Domain.Common; - -namespace ReverseAnalytics.Domain.Entities -{ - public abstract class Person : BaseAuditableEntity - { - public string FullName { get; set; } - public string? CompanyName { get; set; } - public string? PhoneNumber { get; set; } - public string? Address { get; set; } - public decimal Balance { get; set; } - public bool IsActive { get; set; } - - public Person() - { - } - - public Person(string fullName) - { - FullName = fullName; - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Product.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Product.cs index f49ad69..97643d1 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Product.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Product.cs @@ -1,29 +1,31 @@ using ReverseAnalytics.Domain.Common; using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.Entities +namespace ReverseAnalytics.Domain.Entities; + +public class Product : BaseAuditableEntity { - public class Product : BaseAuditableEntity - { - public string ProductName { get; set; } - public string ProductCode { get; set; } - public UnitOfMeasurement UnitOfMeasurement { get; set; } - public double? Volume { get; set; } - public double? Weight { get; set; } - public decimal SupplyPrice { get; set; } - public decimal SalePrice { get; set; } + public string Name { get; set; } + public string Code { get; set; } + public string? Description { get; set; } + public decimal SalePrice { get; set; } + public decimal SupplyPrice { get; set; } + public double? Volume { get; set; } + public double? Weight { get; set; } + public UnitOfMeasurement UnitOfMeasurement { get; set; } - public int CategoryId { get; set; } - public virtual ProductCategory Category { get; set; } + public int CategoryId { get; set; } + public virtual ProductCategory Category { get; set; } - public virtual ICollection SaleDetails { get; set; } - public virtual ICollection PurchaseDetails { get; set; } - public virtual ICollection InventoryProducts { get; set; } + public virtual ICollection SaleItems { get; set; } + public virtual ICollection SupplyItems { get; set; } + + public Product() + { + Name = string.Empty; + Code = string.Empty; - public Product() - { - SaleDetails = new List(); - PurchaseDetails = new List(); - } + SaleItems = []; + SupplyItems = []; } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/ProductCategory.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/ProductCategory.cs index fbe27d2..5d35bb0 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/ProductCategory.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/ProductCategory.cs @@ -1,23 +1,20 @@ using ReverseAnalytics.Domain.Common; -namespace ReverseAnalytics.Domain.Entities +namespace ReverseAnalytics.Domain.Entities; + +public class ProductCategory : BaseAuditableEntity { - public class ProductCategory : BaseAuditableEntity - { - public string CategoryName { get; set; } + public string Name { get; set; } + public string? Description { get; set; } - public virtual ICollection Products { get; set; } + public int? ParentId { get; set; } + public virtual ProductCategory? Parent { get; set; } - public ProductCategory() - { - CategoryName = String.Empty; - Products = new List(); - } + public virtual ICollection Products { get; set; } + public virtual ICollection SubCategories { get; set; } - public ProductCategory(string categoryName) - { - CategoryName = categoryName; - Products = new List(); - } + public ProductCategory() + { + Products = []; } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Sale.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Sale.cs index 8b7aa69..28f036f 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Sale.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Sale.cs @@ -1,21 +1,32 @@ -using ReverseAnalytics.Domain.Enums; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.Entities +namespace ReverseAnalytics.Domain.Entities; + +public class Sale : BaseAuditableEntity, ITransaction { - public class Sale : Transaction - { - public string Receipt { get; set; } - public decimal Discount { get; set; } - public SaleType SaleType { get; set; } + public DateTime Date { get; set; } + public string? Comments { get; set; } + public decimal TotalDue { get; set; } + public decimal TotalPaid { get; set; } + public decimal TotalDiscount { get; set; } + public SaleType SaleType { get; set; } + public SaleStatus Status { get; set; } + public PaymentType PaymentType { get; set; } + public CurrencyType Currency { get; set; } - public int CustomerId { get; set; } - public virtual Customer Customer { get; set; } + public int CustomerId { get; set; } + public virtual Customer Customer { get; set; } - public virtual ICollection OrderDetails { get; set; } + public virtual ICollection SaleItems { get; set; } - public Sale() - { - OrderDetails = new List(); - } + public TransactionType TransactionType => TransactionType.Income; + public TransactionSource TransactionSource => TransactionSource.Sale; + public decimal GetTransactionAmount() => TotalDue; + public int GetTransactionSourceId() => Id; + + public Sale() + { + SaleItems = []; } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SaleDetail.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SaleDetail.cs deleted file mode 100644 index 46fe25d..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SaleDetail.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ReverseAnalytics.Domain.Common; - -namespace ReverseAnalytics.Domain.Entities -{ - public class SaleDetail : BaseAuditableEntity - { - public int Quantity { get; set; } - public decimal UnitPrice { get; set; } - - public int SaleId { get; set; } - public virtual Sale Sale { get; set; } - - public int ProductId { get; set; } - public virtual Product Product { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SaleItem.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SaleItem.cs new file mode 100644 index 0000000..07fc58d --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SaleItem.cs @@ -0,0 +1,16 @@ +using ReverseAnalytics.Domain.Common; + +namespace ReverseAnalytics.Domain.Entities; + +public class SaleItem : BaseAuditableEntity +{ + public int Quantity { get; set; } + public decimal UnitPrice { get; set; } + public decimal Discount { get; set; } + + public int SaleId { get; set; } + public virtual Sale Sale { get; set; } + + public int ProductId { get; set; } + public virtual Product Product { get; set; } +} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Supplier.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Supplier.cs index eef434d..6b6ed21 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Supplier.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Supplier.cs @@ -1,19 +1,19 @@ -namespace ReverseAnalytics.Domain.Entities -{ - public class Supplier : Person - { - public virtual ICollection Supplies { get; set; } +using ReverseAnalytics.Domain.Common; - public Supplier() - { - } +namespace ReverseAnalytics.Domain.Entities; - public Supplier(string fullName, string? companyName) - { - FullName = fullName; - CompanyName = companyName; +public class Supplier : BaseAuditableEntity +{ + public string FirstName { get; set; } + public string LastName { get; set; } + public string PhoneNumber { get; set; } + public string Company { get; set; } + public decimal Balance { get; set; } - Supplies = new List(); - } + public virtual ICollection Supplies { get; set; } + + public Supplier() + { + Supplies = []; } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Supply.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Supply.cs index 283855c..1cd4f93 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Supply.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Supply.cs @@ -1,17 +1,29 @@ -namespace ReverseAnalytics.Domain.Entities +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Enums; + +namespace ReverseAnalytics.Domain.Entities; + +public class Supply : BaseAuditableEntity, ITransaction { - public class Supply : Transaction - { - public string? ReceivedBy { get; set; } + public DateTime Date { get; set; } + public string? Comments { get; set; } + public decimal TotalDue { get; set; } + public decimal TotalPaid { get; set; } + public PaymentType PaymentType { get; set; } + public CurrencyType Currency { get; set; } - public int SupplierId { get; set; } - public virtual Supplier Supplier { get; set; } + public int SupplierId { get; set; } + public virtual Supplier Supplier { get; set; } - public virtual ICollection SupplyDetails { get; set; } + public virtual ICollection SupplyItems { get; set; } - public Supply() - { - SupplyDetails = new List(); - } + public TransactionType TransactionType => TransactionType.Expense; + public TransactionSource TransactionSource => TransactionSource.Supply; + public decimal GetTransactionAmount() => TotalDue; + public int GetTransactionSourceId() => Id; + + public Supply() + { + SupplyItems = []; } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SupplyDetail.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SupplyDetail.cs deleted file mode 100644 index a6597c7..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SupplyDetail.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ReverseAnalytics.Domain.Common; - -namespace ReverseAnalytics.Domain.Entities -{ - public class SupplyDetail : BaseAuditableEntity - { - public int Quantity { get; set; } - public decimal UnitPrice { get; set; } - - public int SupplyId { get; set; } - public virtual Supply Supply { get; set; } - - public int ProductId { get; set; } - public virtual Product Product { get; set; } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SupplyItem.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SupplyItem.cs new file mode 100644 index 0000000..db5afb4 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/SupplyItem.cs @@ -0,0 +1,15 @@ +using ReverseAnalytics.Domain.Common; + +namespace ReverseAnalytics.Domain.Entities; + +public class SupplyItem : BaseAuditableEntity +{ + public int Quantity { get; set; } + public decimal UnitPrice { get; set; } + + public int SupplyId { get; set; } + public virtual Supply Supply { get; set; } + + public int ProductId { get; set; } + public virtual Product Product { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Transaction.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Transaction.cs index 4ca694b..3dc3b3d 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Transaction.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Entities/Transaction.cs @@ -1,16 +1,13 @@ using ReverseAnalytics.Domain.Common; using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Domain.Entities -{ - public class Transaction : BaseAuditableEntity - { - public decimal TotalDue { get; set; } - public decimal TotalPaid { get; set; } - public DateTime TransactionDate { get; set; } - public string? Comments { get; set; } - public TransactionStatusType Status { get; set; } +namespace ReverseAnalytics.Domain.Entities; - public virtual Debt Debt { get; set; } - } +public class Transaction : BaseAuditableEntity +{ + public DateTime Date { get; set; } + public int? SourceId { get; set; } + public decimal Amount { get; set; } + public TransactionType Type { get; set; } + public TransactionSource? Source { get; set; } } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/Currency.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/Currency.cs new file mode 100644 index 0000000..8a83c88 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/Currency.cs @@ -0,0 +1,8 @@ +namespace ReverseAnalytics.Domain.Enums +{ + public enum CurrencyType + { + USD, + UZD + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtOrigin.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtOrigin.cs new file mode 100644 index 0000000..d9351ec --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtOrigin.cs @@ -0,0 +1,11 @@ +namespace ReverseAnalytics.Domain.Enums +{ + public enum DebtOrigin + { + Sale = 1, + SaleRefund = 2, + Supply = 3, + SupplyRefund = 4, + Debt = 5, + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtSource.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtSource.cs new file mode 100644 index 0000000..3676b0f --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtSource.cs @@ -0,0 +1,10 @@ +namespace ReverseAnalytics.Domain.Enums; + +public enum DebtSource +{ + Sale, + SaleRefund, + Supply, + SupplyRefund, + Debt +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtStatus.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtStatus.cs deleted file mode 100644 index 96041f4..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtStatus.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ReverseAnalytics.Domain.Enums -{ - public enum DebtStatus - { - PaymentRequired = 0, - Closed = 1, - Overdue = 2, - Unknown = 3, - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/Debtor.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/Debtor.cs new file mode 100644 index 0000000..2951b1b --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/Debtor.cs @@ -0,0 +1,11 @@ +namespace ReverseAnalytics.Domain.Enums +{ + public enum Debtor + { + Customer = 0, + Supplier = 1, + Employee = 2, + Company = 3, + Other = 4, + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtorType.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtorType.cs new file mode 100644 index 0000000..ff26c86 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/DebtorType.cs @@ -0,0 +1,8 @@ +namespace ReverseAnalytics.Domain.Enums; + +public enum DebtorType +{ + Customer, + Supplier, + Company +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/OrderStatus.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/OrderStatus.cs deleted file mode 100644 index 5b432e5..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/OrderStatus.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ReverseAnalytics.Domain.Enums -{ - public enum OrderStatus - { - Ordered = 1, - Shipped = 2, - PickedUp = 3, - Cancelled = 4, - Completed = 5, - Unkown = 6 - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/PaymentType.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/PaymentType.cs new file mode 100644 index 0000000..48f8c95 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/PaymentType.cs @@ -0,0 +1,8 @@ +namespace ReverseAnalytics.Domain.Enums +{ + public enum PaymentType + { + Cash, + Card + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/RefundSource.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/RefundSource.cs new file mode 100644 index 0000000..8b9d3ed --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/RefundSource.cs @@ -0,0 +1,7 @@ +namespace ReverseAnalytics.Domain.Enums; + +public enum RefundSource +{ + Sale, + Supply +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/SaleStatus.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/SaleStatus.cs new file mode 100644 index 0000000..892c533 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/SaleStatus.cs @@ -0,0 +1,11 @@ +namespace ReverseAnalytics.Domain.Enums +{ + public enum SaleStatus + { + Completed, + Pending, + PartiallyPaid, + Refunded, + Cancelled, + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionSource.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionSource.cs new file mode 100644 index 0000000..2663757 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionSource.cs @@ -0,0 +1,12 @@ +namespace ReverseAnalytics.Domain.Enums +{ + public enum TransactionSource + { + Sale, + Supply, + Refund, + DebtPayment, + Payroll, + None + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionStatusType.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionStatusType.cs deleted file mode 100644 index 4b69067..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionStatusType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ReverseAnalytics.Domain.Enums -{ - public enum TransactionStatusType - { - Completed = 0, - InDebt = 1, - Cancelled = 2 - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionType.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionType.cs new file mode 100644 index 0000000..eb7219d --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Enums/TransactionType.cs @@ -0,0 +1,7 @@ +namespace ReverseAnalytics.Domain.Enums; + +public enum TransactionType +{ + Income, + Expense +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/EntityNotFoundException.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/EntityNotFoundException.cs new file mode 100644 index 0000000..7f0f53a --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/EntityNotFoundException.cs @@ -0,0 +1,9 @@ +namespace ReverseAnalytics.Domain.Exceptions +{ + public class EntityNotFoundException : Exception + { + public EntityNotFoundException() { } + public EntityNotFoundException(string message) : base(message) { } + public EntityNotFoundException(string message, Exception innerException) : base(message, innerException) { } + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/ErrorResponse.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/ErrorResponse.cs deleted file mode 100644 index e689847..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/ErrorResponse.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Microsoft.Extensions.Logging; -using Newtonsoft.Json; - -namespace ReverseAnalytics.Domain.Exceptions -{ - public class ErrorResponse - { - public EventId EventId { get; set; } - public int? StatusCode { get; set; } - public string Message { get; set; } - public string Path { get; set; } - public string Method { get; set; } - public List Errors { get; set; } - - public string ToJson() - { - return JsonConvert.SerializeObject(new - { - StatusCode, - Path, - Method, - Message, - Errors - }); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/ForbiddenAccessException.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/ForbiddenAccessException.cs deleted file mode 100644 index e808dfb..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/ForbiddenAccessException.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ReverseAnalytics.Domain.Exceptions -{ - public class ForbiddenAccessException : Exception - { - public ForbiddenAccessException(string? message) : base(message) { } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/NotFoundException.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/NotFoundException.cs deleted file mode 100644 index 057842b..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Exceptions/NotFoundException.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace ReverseAnalytics.Domain.Exceptions -{ - public class NotFoundException : Exception - { - public NotFoundException() - : base() - { - } - - public NotFoundException(string message) - : base(message) - { - } - - public NotFoundException(string message, Exception innerException) - : base(message, innerException) - { - } - - public NotFoundException(string name, object key) - : base($"Entity \"{name}\" ({key}) was not found.") - { - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IAccountRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IAccountRepository.cs deleted file mode 100644 index 1ccdf8b..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IAccountRepository.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Microsoft.AspNetCore.Identity; - -namespace ReverseAnalytics.Domain.Interfaces.Repositories -{ - public interface IAccountRepository : IRepositoryBase - { - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ICommonRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ICommonRepository.cs index 325d3bc..94c33bc 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ICommonRepository.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ICommonRepository.cs @@ -1,17 +1,16 @@ -namespace ReverseAnalytics.Domain.Interfaces.Repositories +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface ICommonRepository { - public interface ICommonRepository - { - public IDebtRepository Debt { get; } - public IProductCategoryRepository ProductCategory { get; } - public IProductRepository Product { get; } - public ICustomerRepository Customer { get; } - public ISaleRepository Sale { get; } - public ISaleDetailRepository SaleDetail { get; } - public ISupplierRepository Supplier { get; } - public ISupplyRepository Supply { get; } - public ISupplyDetailRepository SupplyDetail { get; } + public ICustomerRepository Customer { get; } + public IProductCategoryRepository ProductCategory { get; } + public IProductRepository Product { get; } + public ISaleItemRepository SaleItem { get; } + public ISaleRepository Sale { get; } + public ISupplierRepository Supplier { get; } + public ISupplyItemRepository SupplyItem { get; } + public ISupplyRepository Supply { get; } + public ITransactionRepository Transaction { get; } - public Task SaveChangesAsync(); - } + public Task SaveChangesAsync(); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ICustomerRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ICustomerRepository.cs index 6108c7d..c1c99f6 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ICustomerRepository.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ICustomerRepository.cs @@ -1,9 +1,10 @@ -using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Repositories +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface ICustomerRepository : IRepositoryBase { - public interface ICustomerRepository : IRepositoryBase - { - public Task> FindAllCustomers(string? searchString, int pageNumber, int pageSize); - } + Task> FindAllAsync(CustomerQueryParameters queryParameters); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IDebtRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IDebtRepository.cs deleted file mode 100644 index 072957f..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IDebtRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Interfaces.Repositories -{ - public interface IDebtRepository : IRepositoryBase - { - public Task> FindAllByPersonIdAsync(int personId); - public Task FindByPersonAndDebtIdAsync(int personId, int phoneId); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IProductCategoryRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IProductCategoryRepository.cs index 4f3e042..c3ce880 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IProductCategoryRepository.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IProductCategoryRepository.cs @@ -1,9 +1,11 @@ -using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Repositories +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface IProductCategoryRepository : IRepositoryBase { - public interface IProductCategoryRepository : IRepositoryBase - { - Task> FindAllProductCategoriesAsync(string? searchString); - } + Task> FindAllAsync(ProductCategoryQueryParameters queryParameters); + Task> FindByParentIdAsync(int parentId); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IProductRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IProductRepository.cs index a172355..e79c03a 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IProductRepository.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IProductRepository.cs @@ -1,9 +1,11 @@ -using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Repositories +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface IProductRepository : IRepositoryBase { - public interface IProductRepository : IRepositoryBase - { - Task> FindAllProductsAsync(string? searchString, int? categoryId, int pageSize, int pageNumber); - } + Task> FindAllAsync(ProductQueryParameters queryParameters); + Task> FindByCategoryIdAsync(int categoryId); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IRepositoryBase.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IRepositoryBase.cs index 36f156d..dd9c769 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IRepositoryBase.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/IRepositoryBase.cs @@ -1,18 +1,29 @@ -namespace ReverseAnalytics.Domain.Interfaces.Repositories +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.QueryParameters; + +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface IRepositoryBase where TEntity : BaseEntity { - public interface IRepositoryBase where T : class - { - Task> FindAllAsync(int pageSize = 0, int pageNumber = 0); - Task FindByIdAsync(int id); - T Create(T entity); - void CreateRange(IEnumerable entities); - void Update(T entity); - void UpdateRange(IEnumerable entities); - void Delete(T entity); - void DeleteRange(IEnumerable entities); - void Delete(int id); - void DeleteRange(IEnumerable ids); - Task SaveChangesAsync(); - Task EntityExistsAsync(int id); - } + Task> FindAllAsync(); + + Task> FindAllAsync(PaginatedQueryParameters queryParameters); + + Task FindByIdAsync(int id); + + Task CreateAsync(TEntity entity); + + Task> CreateRangeAsync(IEnumerable entities); + + Task UpdateAsync(TEntity entity); + + Task UpdateRangeAsync(IEnumerable entities); + + Task DeleteAsync(int id); + + Task DeleteRangeAsync(IEnumerable ids); + + Task SaveChangesAsync(); + + Task EntityExistsAsync(int id); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleDetailRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleDetailRepository.cs deleted file mode 100644 index 4a858a6..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleDetailRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Interfaces.Repositories -{ - public interface ISaleDetailRepository : IRepositoryBase - { - public Task> FindAllBySaleIdAsync(int saleId); - public Task FindBySaleAndDetailIdAsync(int saleId, int detailId); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleItemRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleItemRepository.cs new file mode 100644 index 0000000..6fcd54d --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleItemRepository.cs @@ -0,0 +1,8 @@ +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface ISaleItemRepository : IRepositoryBase +{ + Task> FindBySale(int saleId); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleRepository.cs index 204f454..71fd108 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleRepository.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISaleRepository.cs @@ -1,8 +1,10 @@ -using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Repositories +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface ISaleRepository : IRepositoryBase { - public interface ISaleRepository : IRepositoryBase - { - } + Task> FindAllAsync(SaleQueryParameters queryParameters); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplierRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplierRepository.cs index b390cda..3c7a15e 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplierRepository.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplierRepository.cs @@ -1,8 +1,10 @@ -using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Repositories +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface ISupplierRepository : IRepositoryBase { - public interface ISupplierRepository : IRepositoryBase - { - } + Task> FindAllAsync(SupplierQueryParameters queryParameters); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyDetailRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyDetailRepository.cs deleted file mode 100644 index e43f54c..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyDetailRepository.cs +++ /dev/null @@ -1,11 +0,0 @@ -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Interfaces.Repositories -{ - public interface ISupplyDetailRepository : IRepositoryBase - { - public Task> FindAllBySupplyIdAsync(int supplyId); - public Task> FindAllByProductIdAsync(int supplyId); - public Task FindBySupplyAndDetailIdAsync(int supplyId, int detailId); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyItemRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyItemRepository.cs new file mode 100644 index 0000000..611e7ac --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyItemRepository.cs @@ -0,0 +1,8 @@ +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface ISupplyItemRepository : IRepositoryBase +{ + Task> FindBySupplyAsync(int supplyId); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyRepository.cs index 1aeb49b..4a6ed87 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyRepository.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ISupplyRepository.cs @@ -1,9 +1,10 @@ -using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Repositories +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface ISupplyRepository : IRepositoryBase { - public interface ISupplyRepository : IRepositoryBase - { - public Task> FindAllBySupplierIdAsync(int supplierId); - } + Task> FindAllAsync(SupplyQueryParameters queryParameters); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ITransactionRepository.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ITransactionRepository.cs new file mode 100644 index 0000000..447429d --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Repositories/ITransactionRepository.cs @@ -0,0 +1,10 @@ +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.QueryParameters; + +namespace ReverseAnalytics.Domain.Interfaces.Repositories; + +public interface ITransactionRepository : IRepositoryBase +{ + Task> FindAllAsync(TransactionQueryParameters queryParameters); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IAccountService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IAccountService.cs deleted file mode 100644 index 23c9036..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IAccountService.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ReverseAnalytics.Domain.DTOs.PasswordReset; -using ReverseAnalytics.Domain.DTOs.UserAccount; - -namespace ReverseAnalytics.Domain.Interfaces.Services -{ - public interface IAccountService - { - public Task> GetAllAccountsAsync(); - public Task GetAccountByIdAsync(string id); - public Task GetAccountByLoginAsync(string name); - public Task CreateAccountAsync(UserAccountForCreateDto userAccountToCreate); - public Task UpdateAccountAsync(UserAccountForUpdateDto userAccountToUpdate); - public Task ResetPasswordAsync(PasswordResetRequest request); - public Task DeleteAccountAsync(string id); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IAuthenticationService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IAuthenticationService.cs deleted file mode 100644 index e747536..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IAuthenticationService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ReverseAnalytics.Domain.DTOs.Authentication; - -namespace ReverseAnalytics.Domain.Interfaces.Services -{ - public interface IAuthenticationService - { - Task LoginAsync(AuthenticationRequest request); - - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ICustomerService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ICustomerService.cs index 0c4555b..e5362c9 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ICustomerService.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ICustomerService.cs @@ -1,13 +1,17 @@ using ReverseAnalytics.Domain.DTOs.Customer; +using ReverseAnalytics.Domain.DTOs.Product; +using ReverseAnalytics.Domain.DTOs.Sale; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Services +namespace ReverseAnalytics.Domain.Interfaces.Services; + +public interface ICustomerService { - public interface ICustomerService - { - Task?> GetAllCustomerAsync(string? searchString, int pageNumber, int pageSize); - Task GetCustomerByIdAsync(int id); - Task CreateCustomerAsync(CustomerForCreateDto customerToCreate); - Task UpdateCustomerAsync(CustomerForUpdateDto customerToUpdate); - Task DeleteCustomerAsync(int id); - } -} \ No newline at end of file + Task> GetAllAsync(); + Task> GetAllAsync(ProductQueryParameters queryParameters); + Task> GetSalesAsync(int customerId); + Task GetByIdAsync(int id); + Task CreateAsync(ProductForCreateDto productToCreate); + Task UpdateAsync(ProductForUpdateDto productToUpdate); + Task DeleteAsync(int id); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IDebtService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IDebtService.cs deleted file mode 100644 index 52c1dcd..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IDebtService.cs +++ /dev/null @@ -1,15 +0,0 @@ -using ReverseAnalytics.Domain.DTOs.Debt; - -namespace ReverseAnalytics.Domain.Interfaces.Services -{ - public interface IDebtService - { - public Task> GetAllDebtsAsync(); - public Task> GetAllDebtsByPersonIdAsync(int personId); - public Task GetByPersonAndDebtId(int personId, int debtId); - public Task GetDebtByIdAsync(int id); - public Task CreateDebtAsync(DebtForCreateDto debtToCreate); - public Task UpdateDebtAsync(DebtForUpdateDto debtToUpdate); - public Task DeleteDebtAsync(int id); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IOrderItemService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IOrderItemService.cs deleted file mode 100644 index d4892dc..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IOrderItemService.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ReverseAnalytics.Domain.Interfaces.Services -{ - internal interface IOrderItemService - { - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IProductCategoryService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IProductCategoryService.cs index acd23e7..c304fc5 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IProductCategoryService.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IProductCategoryService.cs @@ -1,14 +1,16 @@ -using ReverseAnalytics.Domain.DTOs.ProductCategory; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.DTOs.ProductCategory; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Services +namespace ReverseAnalytics.Domain.Interfaces.Services; + +public interface IProductCategoryService { - public interface IProductCategoryService - { - Task?> GetProductCategoriesAsync(); - Task?> GetProductCategoriesAsync(string? searchString); - Task GetProductCategoryByIdAsync(int id); - Task CreateProductCategoryAsync(ProductCategoryForCreateDto productCategoryToCreate); - Task UpdateProductCategoryAsync(ProductCategoryForUpdateDto productCategoryToUpdate); - Task DeleteProductCategoryAsync(int productCategoryId); - } + Task> GetAllAsync(); + Task<(IEnumerable Data, PaginationMetaData PaginationMetaData)> GetAllAsync(ProductCategoryQueryParameters queryParameters); + Task> GetAllByParentIdAsync(int parentId); + Task GetByIdAsync(int id); + Task CreateAsync(ProductCategoryForCreateDto categoryToCreate); + Task UpdateAsync(ProductCategoryForUpdateDto categoryToUpdate); + Task DeleteAsync(int id); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IProductService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IProductService.cs index 056a5bf..92272cc 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IProductService.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/IProductService.cs @@ -1,14 +1,15 @@ using ReverseAnalytics.Domain.DTOs.Product; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Services +namespace ReverseAnalytics.Domain.Interfaces.Services; + +public interface IProductService { - public interface IProductService - { - Task?> GetProductsAsync(); - Task?> GetProductsAsync(string? searchString, int? categoryId, int pageSize, int pageNumber); - Task GetProductByIdAsync(int id); - Task CreateProductAsync(ProductForCreateDto productToCreate); - Task UpdateProductAsync(ProductForUpdateDto productToUpdate); - Task DeleteProductAsync(int id); - } + Task> GetAllAsync(); + Task> GetAllAsync(ProductQueryParameters queryParameters); + Task> GetByCategoryAsync(int categoryId); + Task GetByIdAsync(int id); + Task CreateAsync(ProductForCreateDto productToCreate); + Task UpdateAsync(ProductForUpdateDto productToUpdate); + Task DeleteAsync(int id); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISaleDetailService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISaleDetailService.cs deleted file mode 100644 index db61aa1..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISaleDetailService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ReverseAnalytics.Domain.DTOs.SaleDetail; - -namespace ReverseAnalytics.Domain.Interfaces.Services -{ - public interface ISaleDetailService - { - public Task?> GetAllSaleDetailsBySaleIdAsync(int saleId); - public Task GetSaleDetailBySaleAndDetailIdAsync(int saleId, int saleDetailId); - public Task GetSaleDetailByIdAsync(int saleDetailId); - public Task CreateSaleDetailAsync(SaleDetailForCreateDto saleDetailToCreate); - public Task UpdateSaleDetailAsync(SaleDetailForUpdateDto saleDetailToUpdate); - public Task DeleteSaleDetailAsync(int id); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISaleService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISaleService.cs index 209d9b4..6b6f13f 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISaleService.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISaleService.cs @@ -1,13 +1,16 @@ using ReverseAnalytics.Domain.DTOs.Sale; +using ReverseAnalytics.Domain.DTOs.SaleItem; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Services +namespace ReverseAnalytics.Domain.Interfaces.Services; + +public interface ISaleService { - public interface ISaleService - { - public Task> GetAllSalesAsync(int pageSize, int pageNumber); - public Task GetSaleByIdAsync(int id); - public Task CreateSaleAsync(SaleForCreateDto SaleToCreate); - public Task UpdateSaleAsync(SaleForUpdateDto SaleToUpdate); - public Task DeleteSaleAsync(int id); - } + Task> GetAllAsync(); + Task> GetAllAsync(SaleQueryParameters queryParameters); + Task> GetItemsAsync(int saleId); + Task GetByIdAsync(int id); + Task CreateAsync(SaleForCreateDto saleToCreate); + Task UpdateAsync(SaleForUpdateDto saleToUpdate); + Task DeleteAsync(int id); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplierService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplierService.cs index f6d0406..8daf408 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplierService.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplierService.cs @@ -1,13 +1,16 @@ using ReverseAnalytics.Domain.DTOs.Supplier; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Services +namespace ReverseAnalytics.Domain.Interfaces.Services; + +public interface ISupplierService { - public interface ISupplierService - { - public Task> GetAllSuppliersAsync(string? searchString); - public Task GetSupplierByIdAsync(int id); - public Task CreateSupplierAsync(SupplierForCreateDto supplierToCreate); - public Task UpdateSupplierAsync(SupplierForUpdateDto supplierToUpdate); - public Task DeleteSupplierAsync(int id); - } + Task> GetAllAsync(); + Task> GetAllAsync(SupplierQueryParameters queryParameters); + Task> GetSuppliesAsync(int supplierId); + Task GetByIdAsync(int id); + Task CreateAsync(SupplierForCreateDto supplierToCreate); + Task UpdateAsync(SupplierForUpdateDto supplierToUpdate); + Task DeleteAsync(int id); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplyDetailService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplyDetailService.cs deleted file mode 100644 index 87e28fe..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplyDetailService.cs +++ /dev/null @@ -1,16 +0,0 @@ -using ReverseAnalytics.Domain.DTOs.SupplyDetail; - -namespace ReverseAnalytics.Domain.Interfaces.Services -{ - public interface ISupplyDetailService - { - public Task> GetAllSupplyDetailsAsync(); - public Task> GetAllSupplyDetailsBySupplyIdAsync(int supplyId); - public Task> GetAllSupplyDetailsByProductIdAsync(int productId); - public Task GetBySupplyAndDetailIdAsync(int supplyId, int detailId); - public Task GetSupplyDetailByIdAsync(int supplyDetailid); - public Task CreateSupplyDetailAsync(SupplyDetailForCreateDto supplyDetailToCreate); - public Task UpdateSupplyDetailAsync(SupplyDetailForUpdateDto supplyDetailToUpdate); - public Task DeleteSupplyDetailAsync(int supplyDetailid); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplyService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplyService.cs index 0fb1427..86d256b 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplyService.cs +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ISupplyService.cs @@ -1,14 +1,17 @@ -using ReverseAnalytics.Domain.DTOs.Supply; +using ReverseAnalytics.Domain.DTOs.Sale; +using ReverseAnalytics.Domain.DTOs.Supply; +using ReverseAnalytics.Domain.DTOs.SupplyItem; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Domain.Interfaces.Services +namespace ReverseAnalytics.Domain.Interfaces.Services; + +public interface ISupplyService { - public interface ISupplyService - { - public Task> GetAllSuppliesAsync(); - public Task> GetAllSuppliesBySupplierIdAsync(int supplierId); - public Task GetSupplyByIdAsync(int supplyId); - public Task CreateSupplyAsync(SupplyForCreateDto supplyToCreate); - public Task UpdateSupplyAsync(SupplyForUpdateDto supplyToUpdate); - public Task DeleteSupplyAsync(int supplyId); - } + Task> GetAllAsync(); + Task> GetAllAsync(SupplyQueryParameters queryParameters); + Task> GetItemsAsync(int supplyId); + Task GetByIdAsync(int id); + Task CreateAsync(SupplyForCreateDto supplyToCreate); + Task UpdateAsync(SupplyForUpdateDto supplyToUpdate); + Task DeleteAsync(int id); } diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ITokenService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ITokenService.cs deleted file mode 100644 index ac94006..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ITokenService.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ReverseAnalytics.Domain.DTOs.Authentication; -using System.IdentityModel.Tokens.Jwt; - -namespace ReverseAnalytics.Domain.Interfaces.Services -{ - public interface ITokenService - { - public JwtSecurityToken CreateToken(AuthenticationRequest request); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ITransactionService.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ITransactionService.cs new file mode 100644 index 0000000..b6cb38f --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Interfaces/Services/ITransactionService.cs @@ -0,0 +1,14 @@ +using ReverseAnalytics.Domain.DTOs.Transaction; +using ReverseAnalytics.Domain.QueryParameters; + +namespace ReverseAnalytics.Domain.Interfaces.Services; + +public interface ITransactionService +{ + Task> GetAllAsync(); + Task> GetAllAsync(TransactionQueryParameters queryParameters); + Task GetByIdAsync(int id); + Task CreateAsync(TransactionForCreateDto transactionToCreate); + Task UpdateAsync(TransactionForUpdateDto transactionToUpdate); + Task DeleteAsync(int id); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/CustomerMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/CustomerMappings.cs new file mode 100644 index 0000000..5691ef5 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/CustomerMappings.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using ReverseAnalytics.Domain.DTOs.Customer; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Mappings; + +public class CustomerMappings : Profile +{ + public CustomerMappings() + { + CreateMap() + .ForMember(x => x.FullName, e => e.MapFrom(s => s.FirstName + " " + s.LastName)); + CreateMap(); + CreateMap(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/ProductCategoryMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/ProductCategoryMappings.cs new file mode 100644 index 0000000..ffa74ad --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/ProductCategoryMappings.cs @@ -0,0 +1,20 @@ +using AutoMapper; +using ReverseAnalytics.Domain.DTOs.ProductCategory; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Mappings; + +public class ProductCategoryMappings : Profile +{ + public ProductCategoryMappings() + { + CreateMap() + .ForMember(d => d.ParentName, opt => + { + opt.PreCondition(s => s.Parent is not null); + opt.MapFrom(s => s.Parent!.Name); + }); + CreateMap(); + CreateMap(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/ProductMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/ProductMappings.cs new file mode 100644 index 0000000..f6b0876 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/ProductMappings.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using ReverseAnalytics.Domain.DTOs.Product; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Mappings; + +public class ProductMappings : Profile +{ + public ProductMappings() + { + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SaleItemMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SaleItemMappings.cs new file mode 100644 index 0000000..9f68071 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SaleItemMappings.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using ReverseAnalytics.Domain.DTOs.SaleItem; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Mappings; + +public class SaleItemMappings : Profile +{ + public SaleItemMappings() + { + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SaleMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SaleMappings.cs new file mode 100644 index 0000000..62a2349 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SaleMappings.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using ReverseAnalytics.Domain.DTOs.Sale; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Mappings; + +public class SaleMappings : Profile +{ + public SaleMappings() + { + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplierMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplierMappings.cs new file mode 100644 index 0000000..7f87119 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplierMappings.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using ReverseAnalytics.Domain.DTOs.Supplier; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Mappings; + +public class SupplierMappings : Profile +{ + public SupplierMappings() + { + CreateMap() + .ForMember(x => x.FullName, e => e.MapFrom(s => s.FirstName + " " + s.LastName)); + CreateMap(); + CreateMap(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplyItemMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplyItemMappings.cs new file mode 100644 index 0000000..06e614b --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplyItemMappings.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using ReverseAnalytics.Domain.DTOs.SupplyItem; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Mappings; + +public class SupplyItemMappings : Profile +{ + public SupplyItemMappings() + { + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplyMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplyMappings.cs new file mode 100644 index 0000000..409b015 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/SupplyMappings.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using ReverseAnalytics.Domain.DTOs.Sale; +using ReverseAnalytics.Domain.DTOs.Supply; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Domain.Mappings; + +public class SupplyMappings : Profile +{ + public SupplyMappings() + { + CreateMap(); + CreateMap(); + CreateMap(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/TransactionMappings.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/TransactionMappings.cs new file mode 100644 index 0000000..5dd0050 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Mappings/TransactionMappings.cs @@ -0,0 +1,10 @@ +using AutoMapper; + +namespace ReverseAnalytics.Domain.Mappings; + +public class TransactionMappings : Profile +{ + public TransactionMappings() + { + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/CustomerProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/CustomerProfile.cs deleted file mode 100644 index 6523e44..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/CustomerProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Customer; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - public class CustomerProfile : Profile - { - public CustomerProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/DebtProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/DebtProfile.cs deleted file mode 100644 index 0f1a8fe..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/DebtProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Debt; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - public class DebtProfile : Profile - { - public DebtProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/ProductCategoryProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/ProductCategoryProfile.cs deleted file mode 100644 index bdc62ed..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/ProductCategoryProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.ProductCategory; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - public class ProductCategoryProfile : Profile - { - public ProductCategoryProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/ProductProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/ProductProfile.cs deleted file mode 100644 index 0b76782..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/ProductProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Product; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - public class ProductProfile : Profile - { - public ProductProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SaleDetailProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SaleDetailProfile.cs deleted file mode 100644 index 3739cb2..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SaleDetailProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.SaleDetail; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - internal class SaleDetailProfile : Profile - { - public SaleDetailProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SaleProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SaleProfile.cs deleted file mode 100644 index 1896ddf..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SaleProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Sale; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - public class SaleProfile : Profile - { - public SaleProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplierProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplierProfile.cs deleted file mode 100644 index b0da972..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplierProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Supplier; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - public class SupplierProfile : Profile - { - public SupplierProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplyDetailProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplyDetailProfile.cs deleted file mode 100644 index c583921..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplyDetailProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.SupplyDetail; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - public class SupplyDetailProfile : Profile - { - public SupplyDetailProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplyProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplyProfile.cs deleted file mode 100644 index 12be146..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/SupplyProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Supply; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Domain.Profiles -{ - public class SupplyProfile : Profile - { - public SupplyProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/UserAccountProfile.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/UserAccountProfile.cs deleted file mode 100644 index b506b38..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Domain/Profiles/UserAccountProfile.cs +++ /dev/null @@ -1,17 +0,0 @@ -using AutoMapper; -using Microsoft.AspNetCore.Identity; -using ReverseAnalytics.Domain.DTOs.UserAccount; - -namespace ReverseAnalytics.Domain.Profiles -{ - internal class UserAccountProfile : Profile - { - public UserAccountProfile() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/CustomerQueryParameters.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/CustomerQueryParameters.cs new file mode 100644 index 0000000..1462fe7 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/CustomerQueryParameters.cs @@ -0,0 +1,6 @@ +namespace ReverseAnalytics.Domain.QueryParameters; + +public class CustomerQueryParameters : PaginatedQueryParameters +{ + public decimal? Balance { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/PaginatedQueryParameters.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/PaginatedQueryParameters.cs new file mode 100644 index 0000000..7907233 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/PaginatedQueryParameters.cs @@ -0,0 +1,26 @@ +namespace ReverseAnalytics.Domain.QueryParameters; + +public class PaginatedQueryParameters : QueryParametersBase +{ + protected const int MAX_PAGE_SIZE = 50; + protected const int DEFAULT_PAGE_SIZE = 15; + + public int PageNumber { get; init; } = 1; + + private int _pageSize = DEFAULT_PAGE_SIZE; + public int PageSize + { + get => _pageSize; + init + { + if (value > MAX_PAGE_SIZE) + { + _pageSize = MAX_PAGE_SIZE; + + return; + } + + _pageSize = value; + } + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/ProductCategoryQueryParameters.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/ProductCategoryQueryParameters.cs new file mode 100644 index 0000000..c7a53b3 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/ProductCategoryQueryParameters.cs @@ -0,0 +1,6 @@ +namespace ReverseAnalytics.Domain.QueryParameters; + +public class ProductCategoryQueryParameters : PaginatedQueryParameters +{ + public int? ParentId { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/ProductQueryParameters.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/ProductQueryParameters.cs new file mode 100644 index 0000000..2b9a0aa --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/ProductQueryParameters.cs @@ -0,0 +1,7 @@ +namespace ReverseAnalytics.Domain.QueryParameters; + +public class ProductQueryParameters : PaginatedQueryParameters +{ + public decimal? Price { get; set; } + public int? CategoryId { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/QueryParametersBase.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/QueryParametersBase.cs new file mode 100644 index 0000000..097fe21 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/QueryParametersBase.cs @@ -0,0 +1,6 @@ +namespace ReverseAnalytics.Domain.QueryParameters; + +public abstract class QueryParametersBase +{ + public string? SearchQuery { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SaleQueryParameters.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SaleQueryParameters.cs new file mode 100644 index 0000000..369da45 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SaleQueryParameters.cs @@ -0,0 +1,11 @@ +using ReverseAnalytics.Domain.Enums; + +namespace ReverseAnalytics.Domain.QueryParameters; + +public class SaleQueryParameters : PaginatedQueryParameters +{ + public DateTime? SaleDate { get; set; } + public decimal? TotalDue { get; set; } + public SaleStatus? Status { get; set; } + public int? CustomerId { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SupplierQueryParameters.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SupplierQueryParameters.cs new file mode 100644 index 0000000..747848e --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SupplierQueryParameters.cs @@ -0,0 +1,6 @@ +namespace ReverseAnalytics.Domain.QueryParameters; + +public class SupplierQueryParameters : PaginatedQueryParameters +{ + public decimal? Balance { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SupplyQueryParameters.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SupplyQueryParameters.cs new file mode 100644 index 0000000..e127d89 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/SupplyQueryParameters.cs @@ -0,0 +1,8 @@ +namespace ReverseAnalytics.Domain.QueryParameters; + +public class SupplyQueryParameters : PaginatedQueryParameters +{ + public DateTime? SupplyDate { get; set; } + public decimal? TotalDue { get; set; } + public int? SupplierId { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/TransactionQueryParameters.cs b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/TransactionQueryParameters.cs new file mode 100644 index 0000000..98f81d0 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/QueryParameters/TransactionQueryParameters.cs @@ -0,0 +1,11 @@ +using ReverseAnalytics.Domain.Enums; + +namespace ReverseAnalytics.Domain.QueryParameters; + +public class TransactionQueryParameters : PaginatedQueryParameters +{ + public DateTime? Date { get; set; } + public decimal? Amount { get; set; } + public TransactionType? Type { get; set; } + public TransactionSource? Source { get; set; } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/ReverseAnalytics.Domain.csproj b/Reverse-Analytics/ReverseAnalytics.Domain/ReverseAnalytics.Domain.csproj index 7598fbc..d11720a 100644 --- a/Reverse-Analytics/ReverseAnalytics.Domain/ReverseAnalytics.Domain.csproj +++ b/Reverse-Analytics/ReverseAnalytics.Domain/ReverseAnalytics.Domain.csproj @@ -1,19 +1,18 @@  - net6.0 + net8.0 enable enable preview - - - - - - + + + + + diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Validators/Product/ProductForCreateValidator.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/Product/ProductForCreateValidator.cs new file mode 100644 index 0000000..0501c5a --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/Product/ProductForCreateValidator.cs @@ -0,0 +1,34 @@ +using FluentValidation; +using ReverseAnalytics.Domain.DTOs.Product; + +namespace ReverseAnalytics.Domain.Validators.Product; + +public class ProductForCreateValidator : AbstractValidator +{ + public ProductForCreateValidator() + { + RuleFor(x => x.Name) + .NotEmpty() + .MinimumLength(5) + .WithMessage("Product name must contain at least 5 characters.") + .MaximumLength(255) + .WithMessage("Product name must contain maximum 255 characters."); + RuleFor(x => x.Description) + .MaximumLength(4000) + .WithMessage("Description can contain 4000 max characters."); + RuleFor(x => x.SalePrice) + .GreaterThan(0) + .WithMessage($"Sale price must be great than 0."); + RuleFor(x => x.SupplyPrice) + .GreaterThan(0) + .WithMessage($"Supply price must be greater than 0.") + .LessThan(x => x.SalePrice) + .WithMessage(x => $"Supply price: {x.SupplyPrice} cannot be less than Sale price: {x.SalePrice}."); + RuleFor(x => x.UnitOfMeasurement) + .IsInEnum() + .WithMessage(x => $"Invalid Unit of measurement: {x.UnitOfMeasurement}."); + RuleFor(x => x.CategoryId) + .GreaterThan(0) + .WithMessage(x => $"Invalid category id: {x.CategoryId}."); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Validators/Product/ProductForUpdateValidator.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/Product/ProductForUpdateValidator.cs new file mode 100644 index 0000000..a3725bd --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/Product/ProductForUpdateValidator.cs @@ -0,0 +1,36 @@ +using FluentValidation; +using ReverseAnalytics.Domain.DTOs.Product; + +namespace ReverseAnalytics.Domain.Validators.Product; +public class ProductForUpdateValidator : AbstractValidator +{ + public ProductForUpdateValidator() + { + RuleFor(x => x.Id) + .GreaterThan(0) + .WithMessage(x => $"Invalid product id: {x.Id}."); + RuleFor(x => x.Name) + .NotEmpty() + .MinimumLength(5) + .WithMessage("Product name must contain at least 5 characters.") + .MaximumLength(255) + .WithMessage("Product name must contain maximum 255 characters."); + RuleFor(x => x.Description) + .MaximumLength(4000) + .WithMessage("Description can contain 4000 max characters."); + RuleFor(x => x.SalePrice) + .GreaterThan(0) + .WithMessage($"Sale price must be great than 0."); + RuleFor(x => x.SupplyPrice) + .GreaterThan(0) + .WithMessage($"Supply price must be greater than 0.") + .LessThan(x => x.SalePrice) + .WithMessage(x => $"Supply price: {x.SupplyPrice} cannot be less than Sale price: {x.SalePrice}."); + RuleFor(x => x.UnitOfMeasurement) + .IsInEnum() + .WithMessage(x => $"Invalid Unit of measurement: {x.UnitOfMeasurement}."); + RuleFor(x => x.CategoryId) + .GreaterThan(0) + .WithMessage(x => $"Invalid category id: {x.CategoryId}."); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ProductCategory/ProductCategoryForCreateValidator.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ProductCategory/ProductCategoryForCreateValidator.cs new file mode 100644 index 0000000..24f68a8 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ProductCategory/ProductCategoryForCreateValidator.cs @@ -0,0 +1,26 @@ +using FluentValidation; +using ReverseAnalytics.Domain.DTOs.ProductCategory; + +namespace ReverseAnalytics.Domain.Validators.ProductCategory; + +public class ProductCategoryForCreateValidator : AbstractValidator +{ + public ProductCategoryForCreateValidator() + { + RuleFor(x => x.Name) + .NotNull() + .NotEmpty() + .WithMessage("Category name cannot be empty.") + .MinimumLength(ValidationConstants.DEFAULT_MIN_STRING_LENGTH) + .WithMessage($"Category name must contain at least {ValidationConstants.DEFAULT_MIN_STRING_LENGTH} characters.") + .MaximumLength(ValidationConstants.DEFAULT_MAX_STRING_LENGTH) + .WithMessage($"Category name must contain max {ValidationConstants.DEFAULT_MAX_STRING_LENGTH} characters."); + RuleFor(x => x.Description) + .MaximumLength(ValidationConstants.DEFAULT_LARGE_STRING_LENGTH) + .WithMessage($"Description can contain {ValidationConstants.DEFAULT_LARGE_STRING_LENGTH} max characters"); + RuleFor(x => x.ParentId) + .GreaterThan(0) + .When(x => x.ParentId != null) + .WithMessage(x => $"Parent id: {x.ParentId} is invalid"); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ProductCategory/ProductCategoryForUpdateValidator.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ProductCategory/ProductCategoryForUpdateValidator.cs new file mode 100644 index 0000000..2355576 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ProductCategory/ProductCategoryForUpdateValidator.cs @@ -0,0 +1,27 @@ +using FluentValidation; +using ReverseAnalytics.Domain.DTOs.ProductCategory; + +namespace ReverseAnalytics.Domain.Validators.ProductCategory; + +public class ProductCategoryForUpdateValidator : AbstractValidator +{ + public ProductCategoryForUpdateValidator() + { + RuleFor(x => x.Id) + .GreaterThan(0); + RuleFor(x => x.Name) + .NotEmpty() + .WithMessage("Category name cannot be empty.") + .MinimumLength(ValidationConstants.DEFAULT_MIN_STRING_LENGTH) + .WithMessage("Category name must contain at least 3 characters.") + .MaximumLength(ValidationConstants.DEFAULT_MAX_STRING_LENGTH) + .WithMessage("Category name must contain max 255 characters."); + RuleFor(x => x.Description) + .MaximumLength(ValidationConstants.DEFAULT_LARGE_STRING_LENGTH) + .WithMessage("Description can contain 4000 max characters"); + RuleFor(x => x.ParentId) + .GreaterThan(0) + .When(x => x.ParentId != null) + .WithMessage(x => $"Parent id: {x.ParentId} is invalid"); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ValidationConstants.cs b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ValidationConstants.cs new file mode 100644 index 0000000..74061a2 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Domain/Validators/ValidationConstants.cs @@ -0,0 +1,8 @@ +namespace ReverseAnalytics.Domain.Validators; + +internal static class ValidationConstants +{ + public const int DEFAULT_MIN_STRING_LENGTH = 3; + public const int DEFAULT_MAX_STRING_LENGTH = 255; + public const int DEFAULT_LARGE_STRING_LENGTH = 4000; +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Extensions/QueryableExtensions.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Extensions/QueryableExtensions.cs new file mode 100644 index 0000000..4b7e2ce --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Extensions/QueryableExtensions.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; + +namespace ReverseAnalytics.Infrastructure.Extensions; + +internal static class QueryableExtensions +{ + public static async Task> ToPaginatedListAsync(this IQueryable source, int pageNumber, int pageSize) + { + ArgumentNullException.ThrowIfNull(source); + + var count = await source.CountAsync(); + var items = await source.Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + + return new PaginatedList(items, pageNumber, pageSize, count); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/ApplicationDbContext.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/ApplicationDbContext.cs index e370f93..dc478ef 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/ApplicationDbContext.cs +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/ApplicationDbContext.cs @@ -3,42 +3,64 @@ using ReverseAnalytics.Infrastructure.Persistence.Interceptors; using System.Reflection; -namespace ReverseAnalytics.Infrastructure.Persistence +namespace ReverseAnalytics.Infrastructure.Persistence; + +public class ApplicationDbContext : DbContext { - public class ApplicationDbContext : DbContext + private readonly AuditInterceptor _auditInterceptor; + private readonly TransactionsInterceptor _transactionsInterceptor; + + public virtual DbSet Customers { get; set; } + public virtual DbSet Products { get; set; } + public virtual DbSet ProductCategories { get; set; } + public virtual DbSet SaleItems { get; set; } + public virtual DbSet Sales { get; set; } + public virtual DbSet Suppliers { get; set; } + public virtual DbSet SupplyItems { get; set; } + public virtual DbSet Supplies { get; set; } + public virtual DbSet Transactions { get; set; } + + public ApplicationDbContext(DbContextOptions options, + AuditInterceptor auditableInterceptor, + TransactionsInterceptor transactionsInterceptor) + : base(options) { - private readonly AuditableEntitySaveChangesInterceptor _auditableEntitySaveChangesInterceptor; - - public virtual DbSet Debts { get; set; } - public virtual DbSet Products { get; set; } - public virtual DbSet ProductCategories { get; set; } - public virtual DbSet Customers { get; set; } - public virtual DbSet Sales { get; set; } - public virtual DbSet SaleDetails { get; set; } - public virtual DbSet Suppliers { get; set; } - public virtual DbSet Supplies { get; set; } - public virtual DbSet SupplyDetails { get; set; } - public virtual DbSet Inventories { get; set; } - public virtual DbSet InventoryDetails { get; set; } - - public ApplicationDbContext(DbContextOptions options, - AuditableEntitySaveChangesInterceptor auditableEntitySaveChangesInterceptor) - : base(options) - { - _auditableEntitySaveChangesInterceptor = auditableEntitySaveChangesInterceptor; - Database.Migrate(); - } + _auditInterceptor = auditableInterceptor; + _transactionsInterceptor = transactionsInterceptor; - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - optionsBuilder.AddInterceptors(_auditableEntitySaveChangesInterceptor); - } + // Database.EnsureCreated(); + // Database.Migrate(); + } - protected override void OnModelCreating(ModelBuilder modelBuilder) + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.AddInterceptors(_auditInterceptor, _transactionsInterceptor); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); + + ConfigureDecimalAndDouble(modelBuilder); + + base.OnModelCreating(modelBuilder); + } + + private static void ConfigureDecimalAndDouble(ModelBuilder modelBuilder) + { + foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { - modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); + var properties = entityType + .ClrType + .GetProperties() + .Where(p => p.PropertyType == typeof(decimal) || p.PropertyType == typeof(double)); - base.OnModelCreating(modelBuilder); + foreach (var property in properties) + { + modelBuilder.Entity(entityType.Name) + .Property(property.Name) + .HasPrecision(18, 2); + } } } } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/ApplicationIdentityDbContext.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/ApplicationIdentityDbContext.cs deleted file mode 100644 index 00cb7fb..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/ApplicationIdentityDbContext.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; - -namespace ReverseAnalytics.Infrastructure.Persistence -{ - public class ApplicationIdentityDbContext : IdentityDbContext - { - public ApplicationIdentityDbContext(DbContextOptions options) - : base(options) - { - Database.Migrate(); - } - - protected override void OnModelCreating(ModelBuilder builder) - { - base.OnModelCreating(builder); - - builder.Entity(entity => entity.ToTable("User")); - builder.Entity(entity => entity.ToTable("Role")); - builder.Entity>(entity => entity.ToTable("User_Role")); - builder.Entity>(entity => entity.ToTable("User_Claim")); - builder.Entity>(entity => entity.ToTable("Role_Claim")); - builder.Entity>(entity => entity.ToTable("User_Login")); - builder.Entity>(entity => entity.ToTable("User_Token")); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ConfigurationConstants.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ConfigurationConstants.cs new file mode 100644 index 0000000..8d6ee3a --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ConfigurationConstants.cs @@ -0,0 +1,7 @@ +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal static class ConfigurationConstants +{ + public const int DefaultStringMaxLength = 255; + public const int LargeStringMaxLength = 4000; +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/CustomerConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/CustomerConfiguration.cs index b00cd74..20bd5e4 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/CustomerConfiguration.cs +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/CustomerConfiguration.cs @@ -2,20 +2,41 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; using ReverseAnalytics.Domain.Entities; -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal class CustomerConfiguration : IEntityTypeConfiguration { - internal class CustomerConfiguration : IEntityTypeConfiguration + public void Configure(EntityTypeBuilder builder) { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Customer"); + builder.ToTable(nameof(Customer)); + + builder.HasKey(c => c.Id); - builder.HasMany(c => c.Sales) - .WithOne(s => s.Customer) - .HasForeignKey(s => s.CustomerId); + builder.HasMany(c => c.Sales) + .WithOne(s => s.Customer) + .HasForeignKey(s => s.CustomerId); - builder.Property(c => c.Discount) - .HasPrecision(2); - } + builder.Property(c => c.FirstName) + .HasMaxLength(ConfigurationConstants.DefaultStringMaxLength) + .IsRequired(); + builder.Property(c => c.LastName) + .HasMaxLength(ConfigurationConstants.DefaultStringMaxLength) + .IsRequired(false); + builder.Property(c => c.PhoneNumber) + .HasMaxLength(50) + .IsRequired(); + builder.Property(c => c.Address) + .HasMaxLength(ConfigurationConstants.LargeStringMaxLength) + .IsRequired(false); + builder.Property(c => c.Company) + .HasMaxLength(ConfigurationConstants.LargeStringMaxLength) + .IsRequired(false); + builder.Property(c => c.Balance) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(c => c.Discount) + .HasPrecision(18) + .HasDefaultValue(0) + .IsRequired(); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/DebtConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/DebtConfiguration.cs deleted file mode 100644 index 96c07b2..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/DebtConfiguration.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Enums; - -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations -{ - internal class DebtConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Debt"); - - builder.HasKey(d => d.Id); - - builder.HasOne(x => x.Transaction) - .WithOne(d => d.Debt) - .HasForeignKey(d => d.TransactionId); - - builder.Property(d => d.TotalAmount) - .HasColumnType("money") - .HasPrecision(2) - .IsRequired(); - builder.Property(d => d.Remained) - .HasColumnType("money") - .HasPrecision(2) - .IsRequired(); - builder.Property(d => d.DueDate) - .HasColumnType("date") - .IsRequired(false); - builder.Property(d => d.PaidDate) - .HasColumnType("date") - .IsRequired(false); - builder.Property(e => e.Status) - .HasDefaultValue(DebtStatus.PaymentRequired); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/InventoryConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/InventoryConfiguration.cs deleted file mode 100644 index 53b9bdf..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/InventoryConfiguration.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations -{ - internal class InventoryConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Inventory"); - - builder.HasKey(i => i.Id); - - builder.HasMany(i => i.Details) - .WithOne(ip => ip.Inventory) - .HasForeignKey(ip => ip.InventoryId); - - builder.Property(i => i.Name) - .HasMaxLength(150) - .IsRequired(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/InventoryDetailsConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/InventoryDetailsConfiguration.cs deleted file mode 100644 index 16d86ba..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/InventoryDetailsConfiguration.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations -{ - internal class InventoryDetailsConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Inventory_Detail"); - - builder.HasKey(ip => ip.Id); - - builder.HasOne(ip => ip.Inventory) - .WithMany(i => i.Details) - .HasForeignKey(ip => ip.InventoryId); - builder.HasOne(ip => ip.Product) - .WithMany(p => p.InventoryProducts) - .HasForeignKey(ip => ip.ProductId); - - builder.Property(ip => ip.ProductsRemained) - .HasDefaultValue(0) - .IsRequired(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/PersonConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/PersonConfiguration.cs deleted file mode 100644 index 510c056..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/PersonConfiguration.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations -{ - internal class PersonConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Person"); - - builder.HasKey(p => p.Id); - - builder.Property(p => p.FullName) - .HasMaxLength(250) - .IsRequired(); - builder.Property(p => p.CompanyName) - .HasMaxLength(50) - .IsRequired(false); - builder.Property(p => p.Address) - .HasMaxLength(250) - .IsRequired(false); - builder.Property(p => p.PhoneNumber) - .HasMaxLength(50) - .IsRequired(false); - builder.Property(p => p.Balance) - .HasColumnType("money") - .HasPrecision(2) - .HasDefaultValue(0m); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ProductCategoryConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ProductCategoryConfiguration.cs index bc9b597..ad540bc 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ProductCategoryConfiguration.cs +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ProductCategoryConfiguration.cs @@ -2,23 +2,28 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; using ReverseAnalytics.Domain.Entities; -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal class ProductCategoryConfiguration : IEntityTypeConfiguration { - internal class ProductCategoryConfiguration : IEntityTypeConfiguration + public void Configure(EntityTypeBuilder builder) { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Product_Category"); + builder.ToTable(nameof(ProductCategory)); - builder.HasKey(pc => pc.Id); + builder.HasKey(pc => pc.Id); - builder.HasMany(pc => pc.Products) - .WithOne(p => p.Category) - .HasForeignKey(p => p.CategoryId); + builder.HasOne(c => c.Parent) + .WithMany(p => p.SubCategories) + .HasForeignKey(c => c.ParentId); + builder.HasMany(c => c.Products) + .WithOne(p => p.Category) + .HasForeignKey(p => p.CategoryId); - builder.Property(pc => pc.CategoryName) - .HasMaxLength(150) - .IsRequired(); - } + builder.Property(pc => pc.Name) + .HasMaxLength(ConfigurationConstants.DefaultStringMaxLength) + .IsRequired(); + builder.Property(pc => pc.Description) + .HasMaxLength(ConfigurationConstants.LargeStringMaxLength) + .IsRequired(false); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ProductConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ProductConfiguration.cs index 3c094b2..cda2e71 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ProductConfiguration.cs +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/ProductConfiguration.cs @@ -2,41 +2,43 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; using ReverseAnalytics.Domain.Entities; -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal class ProductConfiguration : IEntityTypeConfiguration { - internal class ProductConfiguration : IEntityTypeConfiguration + public void Configure(EntityTypeBuilder builder) { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Product"); - - builder.HasKey(p => p.Id); + builder.ToTable(nameof(Product)); - builder.HasOne(p => p.Category) - .WithMany(pc => pc.Products) - .HasForeignKey(p => p.CategoryId); + builder.HasKey(p => p.Id); - builder.HasMany(p => p.SaleDetails) - .WithOne(od => od.Product) - .HasForeignKey(od => od.ProductId); - builder.HasMany(p => p.PurchaseDetails) - .WithOne(pd => pd.Product) - .HasForeignKey(pd => pd.ProductId); + builder.HasOne(p => p.Category) + .WithMany(pc => pc.Products) + .HasForeignKey(p => p.CategoryId); + builder.HasMany(p => p.SaleItems) + .WithOne(si => si.Product) + .HasForeignKey(si => si.ProductId); - builder.Property(p => p.ProductCode) - .HasMaxLength(50) - .IsRequired(); - builder.Property(p => p.ProductName) - .HasMaxLength(250) - .IsRequired(); - builder.Property(p => p.Volume) - .HasPrecision(2); - builder.Property(p => p.Weight) - .HasPrecision(2); - builder.Property(p => p.SupplyPrice) - .HasColumnType("money"); - builder.Property(p => p.SalePrice) - .HasColumnType("money"); - } + builder.Property(p => p.Name) + .HasMaxLength(ConfigurationConstants.DefaultStringMaxLength) + .IsRequired(); + builder.Property(p => p.Code) + .HasMaxLength(ConfigurationConstants.DefaultStringMaxLength) + .IsRequired(); + builder.Property(p => p.Description) + .HasMaxLength(ConfigurationConstants.LargeStringMaxLength) + .IsRequired(false); + builder.Property(p => p.SalePrice) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(p => p.SupplyPrice) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(p => p.Volume) + .HasPrecision(18, 2) + .IsRequired(false); + builder.Property(p => p.Weight) + .HasPrecision(18, 2) + .IsRequired(false); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleConfiguration.cs index d4f5d8c..a7efc50 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleConfiguration.cs +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleConfiguration.cs @@ -1,33 +1,46 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal class SaleConfiguration : IEntityTypeConfiguration { - internal class SaleConfiguration : IEntityTypeConfiguration + public void Configure(EntityTypeBuilder builder) { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Sale"); + builder.ToTable(nameof(Sale)); - builder.HasOne(s => s.Customer) - .WithMany(c => c.Sales) - .HasForeignKey(s => s.CustomerId); + builder.HasOne(s => s.Customer) + .WithMany(c => c.Sales) + .HasForeignKey(s => s.CustomerId); + builder.HasMany(s => s.SaleItems) + .WithOne(si => si.Sale) + .HasForeignKey(si => si.SaleId); - builder.HasMany(s => s.OrderDetails) - .WithOne(od => od.Sale) - .HasForeignKey(od => od.SaleId); + builder.Property(s => s.Date) + .IsRequired(); + builder.Property(s => s.Comments) + .HasMaxLength(ConfigurationConstants.LargeStringMaxLength) + .IsRequired(false); + builder.Property(s => s.TotalDue) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(s => s.TotalPaid) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(s => s.TotalDiscount) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(s => s.SaleType) + .IsRequired(); + builder.Property(s => s.Status) + .IsRequired(); + builder.Property(s => s.PaymentType) + .IsRequired(); + builder.Property(s => s.Currency) + .IsRequired(); - builder.Property(s => s.Receipt) - .IsRequired() - .HasMaxLength(250); - builder.Property(s => s.Discount) - .HasColumnType("money") - .HasDefaultValue(0); - builder.Property(s => s.SaleType) - .HasDefaultValue(SaleType.Other) - .IsRequired(); - } + builder.Ignore(s => s.TransactionSource); + builder.Ignore(s => s.TransactionType); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleDetailsConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleDetailsConfiguration.cs deleted file mode 100644 index 7175159..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleDetailsConfiguration.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations -{ - internal class SaleDetailsConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Sale_Detail"); - - builder.HasKey(sd => sd.Id); - - builder.HasOne(sd => sd.Sale) - .WithMany(o => o.OrderDetails) - .HasForeignKey(sd => sd.SaleId); - builder.HasOne(sd => sd.Product) - .WithMany(p => p.SaleDetails) - .HasForeignKey(sd => sd.ProductId); - - builder.Property(sd => sd.Quantity) - .IsRequired(); - builder.Property(sd => sd.UnitPrice) - .HasColumnType("money") - .HasPrecision(2) - .IsRequired(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleItemConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleItemConfiguration.cs new file mode 100644 index 0000000..31272fc --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SaleItemConfiguration.cs @@ -0,0 +1,31 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal class SaleItemsConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable(nameof(SaleItem)); + + builder.HasKey(si => si.Id); + + builder.HasOne(si => si.Sale) + .WithMany(s => s.SaleItems) + .HasForeignKey(si => si.SaleId); + builder.HasOne(si => si.Product) + .WithMany(p => p.SaleItems) + .HasForeignKey(sd => sd.ProductId); + + builder.Property(si => si.Quantity) + .IsRequired(); + builder.Property(si => si.UnitPrice) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(si => si.Discount) + .HasDefaultValue(0) + .IsRequired(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplierConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplierConfiguration.cs index 826ac7b..c7cc0bd 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplierConfiguration.cs +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplierConfiguration.cs @@ -8,11 +8,28 @@ internal class SupplierConfiguration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { - builder.ToTable("Supplier"); + builder.ToTable(nameof(Supplier)); + builder.HasKey(s => s.Id); builder.HasMany(s => s.Supplies) - .WithOne(sp => sp.Supplier) - .HasForeignKey(sp => sp.SupplierId); + .WithOne(x => x.Supplier) + .HasForeignKey(x => x.SupplierId); + + builder.Property(s => s.FirstName) + .HasMaxLength(ConfigurationConstants.DefaultStringMaxLength) + .IsRequired(); + builder.Property(s => s.LastName) + .HasMaxLength(ConfigurationConstants.DefaultStringMaxLength) + .IsRequired(false); + builder.Property(s => s.PhoneNumber) + .HasMaxLength(50) + .IsRequired(); + builder.Property(s => s.Company) + .HasMaxLength(ConfigurationConstants.LargeStringMaxLength) + .IsRequired(false); + builder.Property(s => s.Balance) + .HasPrecision(18, 2) + .IsRequired(); } } } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyConfiguration.cs index 760e206..80909c6 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyConfiguration.cs +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyConfiguration.cs @@ -2,25 +2,35 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; using ReverseAnalytics.Domain.Entities; -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal class SupplyConfiguration : IEntityTypeConfiguration { - internal class SupplyConfiguration : IEntityTypeConfiguration + public void Configure(EntityTypeBuilder builder) { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Supply"); + builder.ToTable(nameof(Supply)); + builder.HasKey(s => s.Id); - builder.HasOne(p => p.Supplier) - .WithMany(s => s.Supplies) - .HasForeignKey(p => p.SupplierId); + builder.HasOne(s => s.Supplier) + .WithMany(x => x.Supplies) + .HasForeignKey(x => x.SupplierId); + builder.HasMany(s => s.SupplyItems) + .WithOne(si => si.Supply) + .HasForeignKey(si => si.SupplyId); - builder.HasMany(p => p.SupplyDetails) - .WithOne(pd => pd.Supply) - .HasForeignKey(pd => pd.SupplyId); + builder.Property(s => s.Date) + .IsRequired(); + builder.Property(s => s.Comments) + .HasMaxLength(ConfigurationConstants.LargeStringMaxLength) + .IsRequired(false); + builder.Property(s => s.TotalDue) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(s => s.TotalPaid) + .HasPrecision(18, 2) + .IsRequired(); - builder.Property(p => p.ReceivedBy) - .HasMaxLength(500) - .IsRequired(false); - } + builder.Ignore(s => s.TransactionSource); + builder.Ignore(s => s.TransactionType); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyDetailConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyDetailConfiguration.cs deleted file mode 100644 index 10c280a..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyDetailConfiguration.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using ReverseAnalytics.Domain.Entities; - -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations -{ - internal class SupplyDetailConfiguration : IEntityTypeConfiguration - { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Supply_Detail"); - - builder.HasKey(sd => sd.Id); - - builder.HasOne(sd => sd.Supply) - .WithMany(p => p.SupplyDetails) - .HasForeignKey(sd => sd.SupplyId); - builder.HasOne(sd => sd.Product) - .WithMany(p => p.PurchaseDetails) - .HasForeignKey(sd => sd.ProductId); - - builder.Property(p => p.Quantity) - .IsRequired(); - builder.Property(p => p.UnitPrice) - .HasColumnType("money") - .IsRequired(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyItemConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyItemConfiguration.cs new file mode 100644 index 0000000..5d48d03 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/SupplyItemConfiguration.cs @@ -0,0 +1,27 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal class SupplyItemConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable(nameof(SupplyItem)); + builder.HasKey(si => si.Id); + + builder.HasOne(si => si.Supply) + .WithMany(s => s.SupplyItems) + .HasForeignKey(si => si.SupplyId); + builder.HasOne(si => si.Product) + .WithMany(p => p.SupplyItems) + .HasForeignKey(si => si.ProductId); + + builder.Property(si => si.Quantity) + .IsRequired(); + builder.Property(si => si.UnitPrice) + .HasPrecision(18, 2) + .IsRequired(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/TransactionConfiguration.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/TransactionConfiguration.cs index 29de4bc..1eba804 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/TransactionConfiguration.cs +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Configurations/TransactionConfiguration.cs @@ -1,34 +1,26 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Enums; -namespace ReverseAnalytics.Infrastructure.Persistence.Configurations +namespace ReverseAnalytics.Infrastructure.Persistence.Configurations; + +internal class TransactionConfiguration : IEntityTypeConfiguration { - public class TransactionConfiguration : IEntityTypeConfiguration + public void Configure(EntityTypeBuilder builder) { - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("Transaction"); - - builder.HasKey(x => x.Id); + builder.ToTable(nameof(Transaction)); + builder.HasKey(x => x.Id); - builder.Property(x => x.TotalDue) - .HasColumnType("money") - .HasPrecision(2) - .IsRequired(); - builder.Property(x => x.TotalPaid) - .HasColumnType("money") - .HasPrecision(2) - .IsRequired(); - builder.Property(x => x.TransactionDate) - .HasColumnType("date") - .IsRequired(); - builder.Property(x => x.Comments) - .HasMaxLength(500) - .IsRequired(false); - builder.Property(x => x.Status) - .HasDefaultValue(TransactionStatusType.Completed); - } + builder.Property(x => x.Date) + .IsRequired(); + builder.Property(x => x.SourceId) + .IsRequired(); + builder.Property(x => x.Amount) + .HasPrecision(18, 2) + .IsRequired(); + builder.Property(t => t.Type) + .IsRequired(); + builder.Property(t => t.Source) + .IsRequired(); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/20221123225617_Initial_Create.Designer.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/20221123225617_Initial_Create.Designer.cs deleted file mode 100644 index 4f2e3e1..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/20221123225617_Initial_Create.Designer.cs +++ /dev/null @@ -1,267 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ReverseAnalytics.Infrastructure.Persistence; - -#nullable disable - -namespace ReverseAnalytics.Infrastructure.Persistence.Identity_Migrations -{ - [DbContext(typeof(ApplicationIdentityDbContext))] - [Migration("20221123225617_Initial_Create")] - partial class Initial_Create - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "6.0.5"); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("TEXT"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("Role", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ClaimType") - .HasColumnType("TEXT"); - - b.Property("ClaimValue") - .HasColumnType("TEXT"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("Role_Claim", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("AccessFailedCount") - .HasColumnType("INTEGER"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("TEXT"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("EmailConfirmed") - .HasColumnType("INTEGER"); - - b.Property("LockoutEnabled") - .HasColumnType("INTEGER"); - - b.Property("LockoutEnd") - .HasColumnType("TEXT"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("PasswordHash") - .HasColumnType("TEXT"); - - b.Property("PhoneNumber") - .HasColumnType("TEXT"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("INTEGER"); - - b.Property("SecurityStamp") - .HasColumnType("TEXT"); - - b.Property("TwoFactorEnabled") - .HasColumnType("INTEGER"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("User", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ClaimType") - .HasColumnType("TEXT"); - - b.Property("ClaimValue") - .HasColumnType("TEXT"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("User_Claim", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("TEXT"); - - b.Property("ProviderKey") - .HasColumnType("TEXT"); - - b.Property("ProviderDisplayName") - .HasColumnType("TEXT"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("User_Login", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("RoleId") - .HasColumnType("TEXT"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("User_Role", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("LoginProvider") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("User_Token", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/20221123225617_Initial_Create.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/20221123225617_Initial_Create.cs deleted file mode 100644 index 5eddb7e..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/20221123225617_Initial_Create.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ReverseAnalytics.Infrastructure.Persistence.Identity_Migrations -{ - public partial class Initial_Create : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "Role", - columns: table => new - { - Id = table.Column(type: "TEXT", nullable: false), - Name = table.Column(type: "TEXT", maxLength: 256, nullable: true), - NormalizedName = table.Column(type: "TEXT", maxLength: 256, nullable: true), - ConcurrencyStamp = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Role", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "User", - columns: table => new - { - Id = table.Column(type: "TEXT", nullable: false), - UserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), - NormalizedUserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), - Email = table.Column(type: "TEXT", maxLength: 256, nullable: true), - NormalizedEmail = table.Column(type: "TEXT", maxLength: 256, nullable: true), - EmailConfirmed = table.Column(type: "INTEGER", nullable: false), - PasswordHash = table.Column(type: "TEXT", nullable: true), - SecurityStamp = table.Column(type: "TEXT", nullable: true), - ConcurrencyStamp = table.Column(type: "TEXT", nullable: true), - PhoneNumber = table.Column(type: "TEXT", nullable: true), - PhoneNumberConfirmed = table.Column(type: "INTEGER", nullable: false), - TwoFactorEnabled = table.Column(type: "INTEGER", nullable: false), - LockoutEnd = table.Column(type: "TEXT", nullable: true), - LockoutEnabled = table.Column(type: "INTEGER", nullable: false), - AccessFailedCount = table.Column(type: "INTEGER", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_User", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Role_Claim", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - RoleId = table.Column(type: "TEXT", nullable: false), - ClaimType = table.Column(type: "TEXT", nullable: true), - ClaimValue = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Role_Claim", x => x.Id); - table.ForeignKey( - name: "FK_Role_Claim_Role_RoleId", - column: x => x.RoleId, - principalTable: "Role", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "User_Claim", - columns: table => new - { - Id = table.Column(type: "INTEGER", nullable: false) - .Annotation("Sqlite:Autoincrement", true), - UserId = table.Column(type: "TEXT", nullable: false), - ClaimType = table.Column(type: "TEXT", nullable: true), - ClaimValue = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_User_Claim", x => x.Id); - table.ForeignKey( - name: "FK_User_Claim_User_UserId", - column: x => x.UserId, - principalTable: "User", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "User_Login", - columns: table => new - { - LoginProvider = table.Column(type: "TEXT", nullable: false), - ProviderKey = table.Column(type: "TEXT", nullable: false), - ProviderDisplayName = table.Column(type: "TEXT", nullable: true), - UserId = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_User_Login", x => new { x.LoginProvider, x.ProviderKey }); - table.ForeignKey( - name: "FK_User_Login_User_UserId", - column: x => x.UserId, - principalTable: "User", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "User_Role", - columns: table => new - { - UserId = table.Column(type: "TEXT", nullable: false), - RoleId = table.Column(type: "TEXT", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_User_Role", x => new { x.UserId, x.RoleId }); - table.ForeignKey( - name: "FK_User_Role_Role_RoleId", - column: x => x.RoleId, - principalTable: "Role", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_User_Role_User_UserId", - column: x => x.UserId, - principalTable: "User", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "User_Token", - columns: table => new - { - UserId = table.Column(type: "TEXT", nullable: false), - LoginProvider = table.Column(type: "TEXT", nullable: false), - Name = table.Column(type: "TEXT", nullable: false), - Value = table.Column(type: "TEXT", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_User_Token", x => new { x.UserId, x.LoginProvider, x.Name }); - table.ForeignKey( - name: "FK_User_Token_User_UserId", - column: x => x.UserId, - principalTable: "User", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "RoleNameIndex", - table: "Role", - column: "NormalizedName", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Role_Claim_RoleId", - table: "Role_Claim", - column: "RoleId"); - - migrationBuilder.CreateIndex( - name: "EmailIndex", - table: "User", - column: "NormalizedEmail"); - - migrationBuilder.CreateIndex( - name: "UserNameIndex", - table: "User", - column: "NormalizedUserName", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_User_Claim_UserId", - table: "User_Claim", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_User_Login_UserId", - table: "User_Login", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_User_Role_RoleId", - table: "User_Role", - column: "RoleId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Role_Claim"); - - migrationBuilder.DropTable( - name: "User_Claim"); - - migrationBuilder.DropTable( - name: "User_Login"); - - migrationBuilder.DropTable( - name: "User_Role"); - - migrationBuilder.DropTable( - name: "User_Token"); - - migrationBuilder.DropTable( - name: "Role"); - - migrationBuilder.DropTable( - name: "User"); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/ApplicationIdentityDbContextModelSnapshot.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/ApplicationIdentityDbContextModelSnapshot.cs deleted file mode 100644 index d8b3cd5..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Identity_Migrations/ApplicationIdentityDbContextModelSnapshot.cs +++ /dev/null @@ -1,265 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ReverseAnalytics.Infrastructure.Persistence; - -#nullable disable - -namespace ReverseAnalytics.Infrastructure.Persistence.Identity_Migrations -{ - [DbContext(typeof(ApplicationIdentityDbContext))] - partial class ApplicationIdentityDbContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder.HasAnnotation("ProductVersion", "6.0.5"); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("TEXT"); - - b.Property("Name") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("NormalizedName") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("Role", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ClaimType") - .HasColumnType("TEXT"); - - b.Property("ClaimValue") - .HasColumnType("TEXT"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("Role_Claim", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("AccessFailedCount") - .HasColumnType("INTEGER"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("TEXT"); - - b.Property("Email") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("EmailConfirmed") - .HasColumnType("INTEGER"); - - b.Property("LockoutEnabled") - .HasColumnType("INTEGER"); - - b.Property("LockoutEnd") - .HasColumnType("TEXT"); - - b.Property("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.Property("PasswordHash") - .HasColumnType("TEXT"); - - b.Property("PhoneNumber") - .HasColumnType("TEXT"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("INTEGER"); - - b.Property("SecurityStamp") - .HasColumnType("TEXT"); - - b.Property("TwoFactorEnabled") - .HasColumnType("INTEGER"); - - b.Property("UserName") - .HasMaxLength(256) - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.ToTable("User", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ClaimType") - .HasColumnType("TEXT"); - - b.Property("ClaimValue") - .HasColumnType("TEXT"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("User_Claim", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("TEXT"); - - b.Property("ProviderKey") - .HasColumnType("TEXT"); - - b.Property("ProviderDisplayName") - .HasColumnType("TEXT"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("User_Login", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("RoleId") - .HasColumnType("TEXT"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("User_Role", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("LoginProvider") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("User_Token", (string)null); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/AuditInterceptor.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/AuditInterceptor.cs new file mode 100644 index 0000000..a41989f --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/AuditInterceptor.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using Microsoft.EntityFrameworkCore.Diagnostics; +using ReverseAnalytics.Domain.Common; + +namespace ReverseAnalytics.Infrastructure.Persistence.Interceptors; + +public class AuditInterceptor : SaveChangesInterceptor +{ + public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result) + { + UpdateEntities(eventData.Context); + + return base.SavingChanges(eventData, result); + } + + public override ValueTask> SavingChangesAsync(DbContextEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) + { + UpdateEntities(eventData.Context); + + return base.SavingChangesAsync(eventData, result, cancellationToken); + } + + public void UpdateEntities(DbContext? context) + { + if (context is not ApplicationDbContext dbContext) return; + + foreach (var entry in context.ChangeTracker.Entries()) + { + if (entry.State == EntityState.Added) + { + // TODO implement createdBy && createdDate in a separate service + // entry.Entity.CreatedBy + entry.Entity.CreatedAt = DateTime.Now; + } + + if (entry.State == EntityState.Modified || entry.HasChangedOwnedEntities()) + { + // TODO implement createdBy && createdDate in a separate service + // entry.Entity.CreatedBy + entry.Entity.LastModifiedAt = DateTime.Now; + } + } + } +} + +public static class EntityExtensions +{ + public static bool HasChangedOwnedEntities(this EntityEntry entry) => + entry.References.Any(r => + r.TargetEntry != null && + r.TargetEntry.Metadata.IsOwned() && + (r.TargetEntry.State == EntityState.Added || r.TargetEntry.State == EntityState.Modified)); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/AuditableEntitySaveChangesInterceptor.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/AuditableEntitySaveChangesInterceptor.cs deleted file mode 100644 index f3b2d21..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/AuditableEntitySaveChangesInterceptor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; -using Microsoft.EntityFrameworkCore.Diagnostics; -using ReverseAnalytics.Domain.Common; - -namespace ReverseAnalytics.Infrastructure.Persistence.Interceptors -{ - public class AuditableEntitySaveChangesInterceptor : SaveChangesInterceptor - { - public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result) - { - UpdateEntities(eventData.Context); - - return base.SavingChanges(eventData, result); - } - - public override ValueTask> SavingChangesAsync(DbContextEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) - { - UpdateEntities(eventData.Context); - - return base.SavingChangesAsync(eventData, result, cancellationToken); - } - - public void UpdateEntities(DbContext? context) - { - if (context == null) return; - - foreach (var entry in context.ChangeTracker.Entries()) - { - if (entry.State == EntityState.Added) - { - // TODO implement createdBy && createdDate in a separate service - // entry.Entity.CreatedBy - entry.Entity.Created = DateTime.Now; - } - - if (entry.State == EntityState.Added || entry.State == EntityState.Modified || entry.HasChangedOwnedEntities()) - { - // TODO implement createdBy && createdDate in a separate service - // entry.Entity.CreatedBy - entry.Entity.LastModified = DateTime.Now; - } - } - } - } - - public static class Extensions - { - public static bool HasChangedOwnedEntities(this EntityEntry entry) => - entry.References.Any(r => - r.TargetEntry != null && - r.TargetEntry.Metadata.IsOwned() && - (r.TargetEntry.State == EntityState.Added || r.TargetEntry.State == EntityState.Modified)); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/TransactionsInterceptor.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/TransactionsInterceptor.cs new file mode 100644 index 0000000..3a1c93e --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Persistence/Interceptors/TransactionsInterceptor.cs @@ -0,0 +1,60 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Infrastructure.Persistence.Interceptors; + +public class TransactionsInterceptor : SaveChangesInterceptor +{ + public override InterceptionResult SavingChanges(DbContextEventData eventData, InterceptionResult result) + { + // UpdateTransactions(eventData.Context as ApplicationDbContext); + return base.SavingChanges(eventData, result); + } + + public override ValueTask> SavingChangesAsync(DbContextEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) + { + // UpdateTransactions(eventData.Context as ApplicationDbContext); + return base.SavingChangesAsync(eventData, result, cancellationToken); + } + + private static void UpdateTransactions(ApplicationDbContext? context) + { + if (context is null) return; + + foreach (var entry in context.ChangeTracker.Entries().ToList()) + { + if (entry.Entity is not ITransaction entity) + { + continue; + } + + if (entry.State == EntityState.Added) + { + var transaction = CreateTransaction(entity); + context.Transactions.Add(transaction); + } + + if (entry.State == EntityState.Modified || entry.HasChangedOwnedEntities()) + { + var transaction = context.Transactions + .FirstOrDefault(x => x.SourceId == entity.GetTransactionSourceId() && x.Source == entity.TransactionSource) ?? throw new Exception(); + + transaction.Amount = entity.GetTransactionAmount(); + } + } + } + + private static Transaction CreateTransaction(ITransaction transaction) + { + return new Transaction + { + Amount = transaction.GetTransactionAmount(), + Date = DateTime.Now, + Source = transaction.TransactionSource, + SourceId = transaction.GetTransactionSourceId(), + Type = transaction.TransactionType, + }; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/CommonRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/CommonRepository.cs new file mode 100644 index 0000000..79d0de4 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/CommonRepository.cs @@ -0,0 +1,37 @@ +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class CommonRepository(ApplicationDbContext context) : ICommonRepository +{ + private ICustomerRepository _customer = new CustomerRepository(context); + public ICustomerRepository Customer => _customer ??= new CustomerRepository(context); + + private IProductCategoryRepository _productCategory = new ProductCategoryRepository(context); + public IProductCategoryRepository ProductCategory => _productCategory ??= new ProductCategoryRepository(context); + + private IProductRepository _product = new ProductRepository(context); + public IProductRepository Product => _product ??= new ProductRepository(context); + + private ISaleItemRepository _saleItem = new SaleItemRepository(context); + public ISaleItemRepository SaleItem => _saleItem ??= new SaleItemRepository(context); + + private ISaleRepository _sale = new SaleRepository(context); + public ISaleRepository Sale => _sale ??= new SaleRepository(context); + + private ISupplierRepository _supplier = new SupplierRepository(context); + public ISupplierRepository Supplier => _supplier ??= new SupplierRepository(context); + + private ISupplyItemRepository _supplyItem = new SupplyItemRepository(context); + public ISupplyItemRepository SupplyItem => _supplyItem ??= new SupplyItemRepository(context); + + private ISupplyRepository _supply = new SupplyRepository(context); + public ISupplyRepository Supply => _supply ??= new SupplyRepository(context); + + private ITransactionRepository _transaction = new TransactionRepository(context); + public ITransactionRepository Transaction => _transaction ??= new TransactionRepository(context); + + public async Task SaveChangesAsync() + => await context.SaveChangesAsync(); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/CustomerRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/CustomerRepository.cs new file mode 100644 index 0000000..e07ae3e --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/CustomerRepository.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Domain.QueryParameters; +using ReverseAnalytics.Infrastructure.Extensions; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class CustomerRepository(ApplicationDbContext context) : RepositoryBase(context), ICustomerRepository +{ + public async Task> FindAllAsync(CustomerQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.Customers.AsQueryable(); + + if (queryParameters.Balance.HasValue) + { + query = query.Where(x => x.Balance == queryParameters.Balance); + } + + if (!string.IsNullOrWhiteSpace(queryParameters.SearchQuery)) + { + query = query.Where(x => x.FirstName.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase) || + x.LastName.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase) || + (x.Company != null && x.Company.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase)) || + (x.Address != null && x.Address.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase))); + } + + var customers = await query.AsNoTracking() + .ToPaginatedListAsync(queryParameters.PageNumber, queryParameters.PageSize); + + return customers; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/ProductCategoryRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/ProductCategoryRepository.cs new file mode 100644 index 0000000..f9258eb --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/ProductCategoryRepository.cs @@ -0,0 +1,48 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Domain.QueryParameters; +using ReverseAnalytics.Infrastructure.Extensions; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class ProductCategoryRepository(ApplicationDbContext context) : RepositoryBase(context), IProductCategoryRepository +{ + public async Task> FindAllAsync(ProductCategoryQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.ProductCategories.AsQueryable(); + + if (!string.IsNullOrWhiteSpace(queryParameters.SearchQuery)) + { + query = query.Where(x => x.Name.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase)); + } + + if (queryParameters.ParentId is not null) + { + query = query.Where(x => x.ParentId == queryParameters.ParentId); + } + + var entities = await query + .Include(x => x.Products) + .Include(x => x.Parent) + .Include(x => x.SubCategories) + .AsNoTrackingWithIdentityResolution() + .ToPaginatedListAsync(queryParameters.PageNumber, queryParameters.PageSize); + + return entities; + } + + public async Task> FindByParentIdAsync(int parentId) + { + var categories = await _context.ProductCategories + .Where(x => x.ParentId == parentId) + .AsNoTracking() + .ToListAsync(); + + return categories; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/ProductRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/ProductRepository.cs new file mode 100644 index 0000000..3834343 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/ProductRepository.cs @@ -0,0 +1,50 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Domain.QueryParameters; +using ReverseAnalytics.Infrastructure.Extensions; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class ProductRepository(ApplicationDbContext context) : RepositoryBase(context), IProductRepository +{ + public async Task> FindAllAsync(ProductQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.Products.AsQueryable(); + + if (queryParameters.Price.HasValue) + { + query = query.Where(x => x.SalePrice == queryParameters.Price || x.SupplyPrice == queryParameters.Price); + } + + if (queryParameters.CategoryId.HasValue) + { + query = query.Where(x => x.CategoryId == queryParameters.CategoryId); + } + + if (!string.IsNullOrWhiteSpace(queryParameters.SearchQuery)) + { + query = query.Where(x => x.Name.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase) || + x.Code.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase) || + (x.Description != null && x.Description.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase))); + } + + var products = await query.AsNoTracking().ToPaginatedListAsync(queryParameters.PageNumber, queryParameters.PageSize); + + return products; + } + + public async Task> FindByCategoryIdAsync(int categoryId) + { + var products = await _context.Products + .Where(x => x.CategoryId == categoryId) + .AsNoTracking() + .ToListAsync(); + + return products; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/RepositoryBase.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/RepositoryBase.cs new file mode 100644 index 0000000..7fb0d3e --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/RepositoryBase.cs @@ -0,0 +1,134 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Exceptions; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Domain.QueryParameters; +using ReverseAnalytics.Infrastructure.Extensions; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public abstract class RepositoryBase(ApplicationDbContext context) : IRepositoryBase where TEntity : BaseAuditableEntity +{ + protected readonly ApplicationDbContext _context = context ?? throw new ArgumentNullException(nameof(context)); + + public async Task> FindAllAsync() + { + var entities = await _context.Set() + .AsNoTracking() + .ToListAsync(); + + return entities; + } + + public virtual async Task> FindAllAsync(PaginatedQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var entities = await _context.Set() + .AsNoTracking() + .ToPaginatedListAsync(queryParameters.PageNumber, queryParameters.PageSize); + + return entities; + } + + public async Task FindByIdAsync(int id) + { + var entity = await _context.Set() + .AsNoTracking() + .FirstOrDefaultAsync(x => x.Id == id); + + return entity; + } + + public async Task CreateAsync(TEntity entity) + { + ArgumentNullException.ThrowIfNull(entity); + + var createdEntity = await _context.Set().AddAsync(entity); + await _context.SaveChangesAsync(); + + return createdEntity.Entity; + } + + public async Task> CreateRangeAsync(IEnumerable entities) + { + ArgumentNullException.ThrowIfNull(entities); + + if (!entities.Any()) + { + return []; + } + + foreach (var entity in entities) + { + var attachedEntity = _context.Set().Attach(entity); + attachedEntity.State = Microsoft.EntityFrameworkCore.EntityState.Added; + } + + await _context.SaveChangesAsync(); + + return entities; + } + + public async Task UpdateAsync(TEntity entity) + { + ArgumentNullException.ThrowIfNull(entity); + + if (!await EntityExistsAsync(entity.Id)) + { + throw new EntityNotFoundException($"{nameof(TEntity)} with id: {entity.Id} does not exist."); + } + + var updatedEntity = _context.Set().Update(entity); + await _context.SaveChangesAsync(); + + return updatedEntity.Entity; + } + + public async Task UpdateRangeAsync(IEnumerable entities) + { + ArgumentNullException.ThrowIfNull(entities); + + if (!entities.Any()) + { + return; + } + + _context.Set().UpdateRange(entities); + await _context.SaveChangesAsync(); + } + + public async Task DeleteAsync(int id) + { + var entityToDelete = await FindByIdAsync(id); + + if (entityToDelete is null) + { + throw new EntityNotFoundException($"Entity {typeof(TEntity)} with id: {id} does not exist."); + } + + _context.Set().Remove(entityToDelete); + await _context.SaveChangesAsync(); + } + + public async Task DeleteRangeAsync(IEnumerable ids) + { + ArgumentNullException.ThrowIfNull(ids); + + if (!ids.Any()) + { + return; + } + + foreach (var id in ids) + { + await DeleteAsync(id); + } + } + + public async Task EntityExistsAsync(int id) + => await _context.Set().AnyAsync(x => x.Id == id); + + public Task SaveChangesAsync() => _context.SaveChangesAsync(); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SaleItemRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SaleItemRepository.cs new file mode 100644 index 0000000..89bc70a --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SaleItemRepository.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class SaleItemRepository(ApplicationDbContext context) : RepositoryBase(context), ISaleItemRepository +{ + public async Task> FindBySale(int saleId) + { + var saleItems = await _context.SaleItems + .Where(x => x.SaleId == saleId) + .AsNoTracking() + .ToListAsync(); + + return saleItems; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SaleRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SaleRepository.cs new file mode 100644 index 0000000..2d89525 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SaleRepository.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Domain.QueryParameters; +using ReverseAnalytics.Infrastructure.Extensions; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class SaleRepository(ApplicationDbContext context) : RepositoryBase(context), ISaleRepository +{ + public async Task> FindAllAsync(SaleQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.Sales.AsQueryable(); + + if (queryParameters.TotalDue.HasValue) + { + query = query.Where(x => x.TotalDue == queryParameters.TotalDue); + } + + if (queryParameters.SaleDate.HasValue) + { + query = query.Where(x => x.Date == queryParameters.SaleDate); + } + + if (queryParameters.Status.HasValue) + { + query = query.Where(x => x.Status == queryParameters.Status); + } + + if (queryParameters.CustomerId.HasValue) + { + query = query.Where(x => x.CustomerId == queryParameters.CustomerId); + } + + var sales = await query.AsNoTracking() + .ToPaginatedListAsync(queryParameters.PageNumber, queryParameters.PageSize); + + return sales; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplierRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplierRepository.cs new file mode 100644 index 0000000..e62353a --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplierRepository.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Domain.QueryParameters; +using ReverseAnalytics.Infrastructure.Extensions; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class SupplierRepository(ApplicationDbContext context) : RepositoryBase(context), ISupplierRepository +{ + public async Task> FindAllAsync(SupplierQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.Suppliers.AsQueryable(); + + if (queryParameters.Balance.HasValue) + { + query = query.Where(x => x.Balance == queryParameters.Balance); + } + + if (!string.IsNullOrWhiteSpace(queryParameters.SearchQuery)) + { + query = query.Where(x => x.FirstName.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase) || + x.LastName.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase) || + x.PhoneNumber.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase) || + x.Company.Contains(queryParameters.SearchQuery, StringComparison.OrdinalIgnoreCase)); + } + + var suppliers = await query.AsNoTracking() + .ToPaginatedListAsync(queryParameters.PageNumber, queryParameters.PageSize); + + return suppliers; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplyItemRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplyItemRepository.cs new file mode 100644 index 0000000..20b3eb3 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplyItemRepository.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class SupplyItemRepository(ApplicationDbContext context) : RepositoryBase(context), ISupplyItemRepository +{ + public async Task> FindBySupplyAsync(int supplyId) + { + var supplies = await _context.SupplyItems + .Where(x => x.SupplyId == supplyId) + .AsNoTracking() + .ToListAsync(); + + return supplies; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplyRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplyRepository.cs new file mode 100644 index 0000000..514b7c8 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/SupplyRepository.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Domain.QueryParameters; +using ReverseAnalytics.Infrastructure.Extensions; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class SupplyRepository(ApplicationDbContext context) : RepositoryBase(context), ISupplyRepository +{ + public async Task> FindAllAsync(SupplyQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.Supplies.AsQueryable(); + + if (queryParameters.TotalDue.HasValue) + { + query = query.Where(x => x.TotalDue == queryParameters.TotalDue); + } + + if (queryParameters.SupplyDate.HasValue) + { + query = query.Where(x => x.Date == queryParameters.SupplyDate); + } + + if (queryParameters.SupplierId.HasValue) + { + query = query.Where(x => x.SupplierId == queryParameters.SupplierId); + } + + var supplies = await query.AsNoTracking() + .ToPaginatedListAsync(queryParameters.PageNumber, queryParameters.PageSize); + + return supplies; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/TransactionRepository.cs b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/TransactionRepository.cs new file mode 100644 index 0000000..679613d --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/Repositories/TransactionRepository.cs @@ -0,0 +1,44 @@ +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.Common; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Interfaces.Repositories; +using ReverseAnalytics.Domain.QueryParameters; +using ReverseAnalytics.Infrastructure.Extensions; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Infrastructure.Repositories; + +public class TransactionRepository(ApplicationDbContext context) : RepositoryBase(context), ITransactionRepository +{ + public async Task> FindAllAsync(TransactionQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.Transactions.AsQueryable(); + + if (queryParameters.Source.HasValue) + { + query = query.Where(x => x.Source == queryParameters.Source); + } + + if (queryParameters.Amount.HasValue) + { + query = query.Where(x => x.Amount == queryParameters.Amount); + } + + if (queryParameters.Date.HasValue) + { + query = query.Where(x => x.Date == queryParameters.Date); + } + + if (queryParameters.Type.HasValue) + { + query = query.Where(x => x.Type == queryParameters.Type); + } + + var transactions = await query.AsNoTracking() + .ToPaginatedListAsync(queryParameters.PageNumber, queryParameters.PageSize); + + return transactions; + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Infrastructure/ReverseAnalytics.Infrastructure.csproj b/Reverse-Analytics/ReverseAnalytics.Infrastructure/ReverseAnalytics.Infrastructure.csproj index 38a445d..542621e 100644 --- a/Reverse-Analytics/ReverseAnalytics.Infrastructure/ReverseAnalytics.Infrastructure.csproj +++ b/Reverse-Analytics/ReverseAnalytics.Infrastructure/ReverseAnalytics.Infrastructure.csproj @@ -1,40 +1,23 @@ - net6.0 + net8.0 enable enable preview - - - - - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/CommonRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/CommonRepository.cs deleted file mode 100644 index eccbe75..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/CommonRepository.cs +++ /dev/null @@ -1,68 +0,0 @@ -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class CommonRepository : ICommonRepository - { - private readonly ApplicationDbContext _context; - - private readonly IDebtRepository _debt; - public IDebtRepository Debt => _debt ?? - new DebtRepository(_context); - - private readonly IProductCategoryRepository _productCategory; - public IProductCategoryRepository ProductCategory => _productCategory ?? - new ProductCategoryRepository(_context); - - private readonly IProductRepository _product; - public IProductRepository Product => _product ?? - new ProductRepository(_context); - - private readonly ICustomerRepository _customer; - public ICustomerRepository Customer => _customer ?? - new CustomerRepository(_context); - - private readonly ISaleRepository _sale; - public ISaleRepository Sale => _sale ?? - new SaleRepository(_context); - - private readonly ISaleDetailRepository _saleDetail; - public ISaleDetailRepository SaleDetail => _saleDetail ?? - new SaleDetailRepository(_context); - - private readonly ISupplierRepository _supplier; - public ISupplierRepository Supplier => _supplier ?? - new SupplierRepository(_context); - - private readonly ISupplyRepository _supply; - public ISupplyRepository Supply => _supply ?? - new SupplyRepository(_context); - - private readonly ISupplyDetailRepository _supplyDetail; - public ISupplyDetailRepository SupplyDetail => _supplyDetail ?? - new SupplyDetailRepository(_context); - - public CommonRepository(ApplicationDbContext context) - { - _context = context ?? throw new ArgumentNullException(nameof(context)); - - _debt = new DebtRepository(context); - _productCategory = new ProductCategoryRepository(context); - _product = new ProductRepository(context); - _customer = new CustomerRepository(context); - _sale = new SaleRepository(context); - _saleDetail = new SaleDetailRepository(context); - _supplier = new SupplierRepository(context); - _supply = new SupplyRepository(context); - _supplyDetail = new SupplyDetailRepository(context); - } - - public async Task SaveChangesAsync() - { - int savedChanges = await _context.SaveChangesAsync(); - - return savedChanges; - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/CustomerRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/CustomerRepository.cs deleted file mode 100644 index 1eba28d..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/CustomerRepository.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class CustomerRepository : RepositoryBase, ICustomerRepository - { - public CustomerRepository(ApplicationDbContext dbContext) - : base(dbContext) - { - } - - public async Task> FindAllCustomers(string? searchString, int pageNumber, int pageSize) - { - var customers = _context.Customers - .Include(x => x.Debts) - .Include(x => x.Sales) - .AsNoTracking() - .AsQueryable(); - - if (!string.IsNullOrEmpty(searchString)) - { - customers = customers.Where(c => c.FullName.Contains(searchString)); - } - - customers = customers.OrderBy(c => c.FullName) - .ThenBy(c => c.IsActive); - - customers = customers.Skip(pageSize * (pageNumber - 1)) - .Take(pageSize); - - return await customers.ToListAsync(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/DebtRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/DebtRepository.cs deleted file mode 100644 index 43a4a08..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/DebtRepository.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class DebtRepository : RepositoryBase, IDebtRepository - { - public DebtRepository(ApplicationDbContext context) - : base(context) - { - } - - public async Task> FindAllByPersonIdAsync(int personId) - { - var debts = await _context.Debts - .Where(d => d.PersonId == personId) - .ToListAsync(); - - return debts; - } - - public async Task FindByPersonAndDebtIdAsync(int personId, int phoneId) - { - var debt = await _context.Debts.FirstOrDefaultAsync(p => p.Id == phoneId && p.PersonId == personId); - - return debt; - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/ProductCategoryRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/ProductCategoryRepository.cs deleted file mode 100644 index fdb16e5..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/ProductCategoryRepository.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class ProductCategoryRepository : RepositoryBase, IProductCategoryRepository - { - public ProductCategoryRepository(ApplicationDbContext context) - : base(context) - { - } - - public async Task> FindAllProductCategoriesAsync(string? searchString) - { - var productCategories = _context.ProductCategories.AsQueryable(); - - if (!string.IsNullOrEmpty(searchString)) - { - productCategories = productCategories.Where(pc => pc.CategoryName == searchString); - } - - return await productCategories.ToListAsync(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/ProductRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/ProductRepository.cs deleted file mode 100644 index 8dd42dd..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/ProductRepository.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class ProductRepository : RepositoryBase, IProductRepository - { - public ProductRepository(ApplicationDbContext dbContext) - : base(dbContext) - { - } - - public async Task> FindAllProductsAsync(string? searchString, int? categoryId, int pageSize, int pageNumber) - { - var products = _context.Products - .Include(p => p.Category) - .AsNoTracking() - .AsQueryable(); - - // Search - if (!string.IsNullOrEmpty(searchString)) - { - products = products.Where(p => p.ProductName.Contains(searchString)); - } - - // Filter - if (categoryId != null) - { - products = products.Where(p => p.CategoryId == categoryId); - } - - // Sort - products = products.OrderBy(p => p.ProductName); - - // Pagination - //products = products.Skip(pageSize * (pageNumber - 1)) - // .Take(pageSize); - - return await products.ToListAsync(); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/RepositoryBase.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/RepositoryBase.cs deleted file mode 100644 index d9120be..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/RepositoryBase.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.Common; -using ReverseAnalytics.Domain.Exceptions; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public abstract class RepositoryBase : IRepositoryBase where T : BaseEntity - { - protected readonly ApplicationDbContext _context; - - protected RepositoryBase(ApplicationDbContext context) - { - _context = context; - } - - public async Task> FindAllAsync(int pageSize = 0, int pageNumber = 0) - { - if(pageSize > 0 && pageNumber > 0) - { - return await _context.Set() - .AsNoTracking() - .Skip(pageSize * (pageNumber - 1)) - .Take(pageSize) - .OrderBy(x => x.Id) - .ToListAsync(); - } - - return await _context.Set() - .AsNoTracking() - .ToListAsync(); - } - - public async Task FindByIdAsync(int id) - { - return await _context.Set().FindAsync(id); - } - - public T Create(T entity) - { - return _context.Set().Add(entity).Entity; - } - - public void CreateRange(IEnumerable entities) - { - _context.Set().AddRange(entities); - } - - public void Update(T entity) - { - var entityExists = _context.Set().Contains(entity); - - if (!entityExists) - { - throw new NotFoundException($"There is no Entity {typeof(T)} with id: {entity.Id}."); - } - - _context.Set().Update(entity); - } - - public void UpdateRange(IEnumerable entities) - { - _context.Set().UpdateRange(entities); - } - - public void Delete(T entity) - { - _context.Set().Remove(entity); - } - - public void DeleteRange(IEnumerable entities) - { - _context.Set().RemoveRange(entities); - } - - public void Delete(int id) - { - var entity = _context.Set().Find(id); - - if(entity == null) - { - throw new NotFoundException($"There is no Entity {typeof(T)} with id: {id}."); - } - - Delete(entity); - } - - public async void DeleteRange(IEnumerable ids) - { - foreach(var id in ids) - { - bool entityExists = await EntityExistsAsync(id); - - if (!entityExists) - { - throw new Exception($"There is no Entity Type {typeof(T)} with id: {id}."); - } - - Delete(id); - } - } - - public async Task SaveChangesAsync() - { - return (await _context.SaveChangesAsync() >= 0); - } - - public async Task EntityExistsAsync(int id) - { - return await _context.Set() - .AsNoTracking() - .FirstOrDefaultAsync(s => s.Id == id) != null; - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/SaleDetailRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/SaleDetailRepository.cs deleted file mode 100644 index 43a5a0e..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/SaleDetailRepository.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class SaleDetailRepository : RepositoryBase, ISaleDetailRepository - { - public SaleDetailRepository(ApplicationDbContext context) - : base(context) - { - } - - public async Task> FindAllBySaleIdAsync(int saleId) - { - var saleDetails = await _context.SaleDetails - .Where(s => s.SaleId == saleId) - .ToListAsync(); - - return saleDetails; - } - - public async Task FindBySaleAndDetailIdAsync(int saleId, int detailId) - { - var saleDetail = await _context.SaleDetails - .FirstOrDefaultAsync(s => s.SaleId == saleId && s.Id == detailId); - - return saleDetail; - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/SaleRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/SaleRepository.cs deleted file mode 100644 index 5fe745c..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/SaleRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class SaleRepository : RepositoryBase, ISaleRepository - { - public SaleRepository(ApplicationDbContext context) - : base(context) - { - } - } -} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/SupplierRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/SupplierRepository.cs deleted file mode 100644 index b5d0df0..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/SupplierRepository.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class SupplierRepository : RepositoryBase, ISupplierRepository - { - public SupplierRepository(ApplicationDbContext context) - : base(context) - { - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/SupplyDetailRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/SupplyDetailRepository.cs deleted file mode 100644 index 1c392fa..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/SupplyDetailRepository.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class SupplyDetailRepository : RepositoryBase, ISupplyDetailRepository - { - public SupplyDetailRepository(ApplicationDbContext context) - : base(context) - { - } - - public async Task> FindAllBySupplyIdAsync(int supplyId) - { - var supplyDetails = await _context.SupplyDetails - .Where(sd => sd.SupplyId == supplyId) - .ToListAsync(); - - return supplyDetails; - } - - public async Task> FindAllByProductIdAsync(int productId) - { - var supplyDetails = await _context.SupplyDetails - .Where(sd => sd.ProductId == productId) - .ToListAsync(); - - return supplyDetails; - } - - public async Task FindBySupplyAndDetailIdAsync(int supplyId, int detailId) - { - var supplyDetail = await _context.SupplyDetails - .FirstOrDefaultAsync(s => s.SupplyId == supplyId && s.Id == detailId); - - return supplyDetail; - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/SupplyRepository.cs b/Reverse-Analytics/ReverseAnalytics.Repositories/SupplyRepository.cs deleted file mode 100644 index 74cfe7d..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/SupplyRepository.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Infrastructure.Persistence; - -namespace ReverseAnalytics.Repositories -{ - public class SupplyRepository : RepositoryBase, ISupplyRepository - { - public SupplyRepository(ApplicationDbContext context) - : base(context) - { - } - - public async Task> FindAllBySupplierIdAsync(int supplierId) - { - var supplies = await _context.Supplies - .Where(s => s.SupplierId == supplierId) - .ToListAsync(); - - return supplies; - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/AccountService.cs b/Reverse-Analytics/ReverseAnalytics.Services/AccountService.cs deleted file mode 100644 index 6565f47..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/AccountService.cs +++ /dev/null @@ -1,167 +0,0 @@ -using AutoMapper; -using Microsoft.AspNetCore.Identity; -using Microsoft.AspNetCore.WebUtilities; -using Microsoft.EntityFrameworkCore; -using ReverseAnalytics.Domain.DTOs.PasswordReset; -using ReverseAnalytics.Domain.DTOs.UserAccount; -using ReverseAnalytics.Domain.Interfaces.Services; -using System.Text; - -namespace ReverseAnalytics.Services -{ - public class AccountService : IAccountService - { - private readonly UserManager _userManager; - private readonly IMapper _mapper; - - public AccountService(UserManager userManager, IMapper mapper) - { - _userManager = userManager; - _mapper = mapper; - } - - public async Task> GetAllAccountsAsync() - { - try - { - var users = await _userManager.Users.ToListAsync(); - - var userDtos = _mapper.Map>(users); - - return userDtos; - } - catch (Exception) - { - throw; - } - } - - public async Task GetAccountByIdAsync(string id) - { - try - { - var user = await _userManager.FindByIdAsync(id); - - var userDto = _mapper.Map(user); - - return userDto; - } - catch (Exception) - { - throw; - } - } - - public async Task GetAccountByLoginAsync(string name) - { - try - { - var user = await _userManager.FindByNameAsync(name); - - var userDto = _mapper.Map(user); - - return userDto; - } - catch (Exception) - { - throw; - } - } - - public async Task CreateAccountAsync(UserAccountForCreateDto userAccountToCreate) - { - try - { - var user = _mapper.Map(userAccountToCreate); - - var result = await _userManager.CreateAsync(user, userAccountToCreate.Password); - - await _userManager.AddToRoleAsync(user, "Visitor"); - } - catch(Exception) - { - throw; - } - } - - public async Task UpdateAccountAsync(UserAccountForUpdateDto userAccountToUpdate) - { - try - { - var user = await _userManager.FindByIdAsync(userAccountToUpdate.Id); - - user.UserName = userAccountToUpdate.UserName; - user.NormalizedUserName = userAccountToUpdate.UserName.ToUpper(); - - var result = await _userManager.UpdateAsync(user); - } - catch (Exception) - { - throw; - } - } - - public async Task ResetPasswordAsync(PasswordResetRequest request) - { - var user = await _userManager.FindByNameAsync(request.UserName); - - if(request.NewPassword != request.ConfirmPassword) - { - return new PasswordResetResponse - { - IsSuccess = false, - Message = "New password does not match to its confirmation." - }; - } - - if(user is null) - { - return new PasswordResetResponse - { - IsSuccess = false, - Message = "User not found." - }; - } - - var token = await _userManager.GeneratePasswordResetTokenAsync(user); - var result = await _userManager.ResetPasswordAsync(user, token, request.NewPassword); - - if (!result.Succeeded) - { - return new PasswordResetResponse - { - IsSuccess = false, - Message = "Password reset failed, see erros for more details.", - Errors = result.Errors.Select(e => new ResponseError - { - Description = e.Description, - Code = e.Code - }).ToList() - }; - } - - return new PasswordResetResponse - { - IsSuccess = true, - Message = "Password was successfully updated." - }; - } - - public async Task DeleteAccountAsync(string id) - { - try - { - var user = await _userManager.FindByIdAsync(id); - - if(user != null) - { - await _userManager.DeleteAsync(user); - } - } - catch (Exception) - { - throw; - } - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/AuthenticationService.cs b/Reverse-Analytics/ReverseAnalytics.Services/AuthenticationService.cs deleted file mode 100644 index 1a6a415..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/AuthenticationService.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.AspNetCore.Identity; -using ReverseAnalytics.Domain.DTOs.Authentication; -using ReverseAnalytics.Domain.Interfaces.Services; -using System.IdentityModel.Tokens.Jwt; - -namespace ReverseAnalytics.Services -{ - public class AuthenticationService : IAuthenticationService - { - private readonly UserManager _userManager; - private readonly ITokenService _tokenService; - - public AuthenticationService(UserManager userManager, ITokenService tokenService) - { - _userManager = userManager; - _tokenService = tokenService; - } - - public async Task LoginAsync(AuthenticationRequest request) - { - var user = await _userManager.FindByNameAsync(request.UserName); - var authenticated = await _userManager.CheckPasswordAsync(user, request.Password); - - if (!authenticated) - { - List errors = new() - { - "Invalid user name or password." - }; - - return new AuthenticationResponse("", false, errors, null); - } - - var token = _tokenService.CreateToken(request); - string tokenString = new JwtSecurityTokenHandler().WriteToken(token); - - return new AuthenticationResponse(tokenString, true, token.ValidTo); - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/CustomerService.cs b/Reverse-Analytics/ReverseAnalytics.Services/CustomerService.cs deleted file mode 100644 index 00d4067..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/CustomerService.cs +++ /dev/null @@ -1,182 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Customer; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Exceptions; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace ReverseAnalytics.Services -{ - public class CustomerService : ICustomerService - { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public CustomerService(ICommonRepository repository, IMapper mapper) - { - _repository = repository; - _mapper = mapper; - } - - public async Task?> GetAllCustomerAsync(string? searchString, int pageNumber, int pageSize) - { - try - { - var customers = await _repository.Customer.FindAllCustomers(searchString, pageNumber, pageSize); - - if (customers is null) - { - return null; - } - - var customerDtos = _mapper.Map>(customers); - - if (customerDtos is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(Customer)} entities to type {typeof(CustomerDto)}."); - } - - return customerDtos; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error retrieving Customers.", ex); - } - } - - public async Task GetCustomerByIdAsync(int id) - { - try - { - var customer = await _repository.Customer.FindByIdAsync(id); - - if (customer is null) - { - throw new NotFoundException($"Customer with id: {id} was not found."); - } - - var customerDto = _mapper.Map(customer); - - if (customerDto is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(Customer)} to type {typeof(CustomerDto)}"); - } - - return customerDto; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception($"There was an error retrieving customer with id: {id}.", ex); - } - } - - public async Task CreateCustomerAsync(CustomerForCreateDto customerToCreate) - { - try - { - if (customerToCreate is null) - { - throw new ArgumentNullException(nameof(customerToCreate)); - } - - var customerEntity = _mapper.Map(customerToCreate); - - if (customerEntity is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(CustomerForCreateDto)} to {typeof(Customer)}."); - } - - var createdEntity = _repository.Customer.Create(customerEntity); - - var customerDto = _mapper.Map(createdEntity); - - if (customerDto is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(Customer)} to {typeof(CustomerDto)}."); - } - - await _repository.Customer.SaveChangesAsync(); - - return customerDto; - } - catch (ArgumentNullException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error adding new Customer.", ex); - } - } - - public async Task UpdateCustomerAsync(CustomerForUpdateDto customerToUpdate) - { - try - { - if (customerToUpdate is null) - { - throw new ArgumentNullException(nameof(customerToUpdate)); - } - - var customerEntity = _mapper.Map(customerToUpdate); - - if (customerEntity is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(CustomerForUpdateDto)} to type {typeof(Customer)}."); - } - - _repository.Customer.Update(customerEntity); - await _repository.Customer.SaveChangesAsync(); - } - catch (ArgumentNullException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error updating Customer.", ex); - } - } - - public async Task DeleteCustomerAsync(int id) - { - try - { - _repository.Customer.Delete(id); - await _repository.Customer.SaveChangesAsync(); - } - catch (NotFoundException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception($"There was an error deleting Customer with id: {id}", ex); - } - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/DebtService.cs b/Reverse-Analytics/ReverseAnalytics.Services/DebtService.cs deleted file mode 100644 index f990a94..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/DebtService.cs +++ /dev/null @@ -1,130 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Debt; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace ReverseAnalytics.Services -{ - public class DebtService : IDebtService - { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public DebtService(ICommonRepository repository, IMapper mapper) - { - _repository = repository; - _mapper = mapper; - } - - public async Task> GetAllDebtsAsync() - { - try - { - var debts = await _repository.Debt.FindAllAsync(); - - var debtDtos = _mapper.Map>(debts); - - return debtDtos; - } - catch - { - throw; - } - } - - public async Task> GetAllDebtsByPersonIdAsync(int personId) - { - try - { - var debts = await _repository.Debt.FindAllByPersonIdAsync(personId); - - var debtDtos = _mapper.Map>(debts); - - return debtDtos; - } - catch - { - throw; - } - } - - public async Task GetByPersonAndDebtId(int personId, int debtId) - { - try - { - var debt = await _repository.Debt.FindByPersonAndDebtIdAsync(personId, debtId); - var debtDto = _mapper.Map(debt); - - return debtDto; - } - catch - { - throw; - } - } - - public async Task GetDebtByIdAsync(int id) - { - try - { - var debt = await _repository.Debt.FindByIdAsync(id); - - var debtDto = _mapper.Map(debt); - - return debtDto; - } - catch - { - throw; - } - } - - public async Task CreateDebtAsync(DebtForCreateDto debtToCreate) - { - try - { - var debtEntity = _mapper.Map(debtToCreate); - - var createdEntity = _repository.Debt.Create(debtEntity); - await _repository.SaveChangesAsync(); - - var debtDto = _mapper.Map(createdEntity); - - return debtDto; - } - catch - { - throw; - } - } - - public async Task UpdateDebtAsync(DebtForUpdateDto debtToUpdate) - { - try - { - var debtEntity = _mapper.Map(debtToUpdate); - - _repository.Debt.Update(debtEntity); - await _repository.SaveChangesAsync(); - } - catch - { - throw; - } - } - - public async Task DeleteDebtAsync(int id) - { - try - { - _repository.Debt.Delete(id); - await _repository.SaveChangesAsync(); - } - catch - { - throw; - } - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/ProductCategoryService.cs b/Reverse-Analytics/ReverseAnalytics.Services/ProductCategoryService.cs index 6a6f8a8..ccb6fd2 100644 --- a/Reverse-Analytics/ReverseAnalytics.Services/ProductCategoryService.cs +++ b/Reverse-Analytics/ReverseAnalytics.Services/ProductCategoryService.cs @@ -1,219 +1,70 @@ using AutoMapper; - +using ReverseAnalytics.Domain.Common; using ReverseAnalytics.Domain.DTOs.ProductCategory; using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Exceptions; using ReverseAnalytics.Domain.Interfaces.Repositories; using ReverseAnalytics.Domain.Interfaces.Services; +using ReverseAnalytics.Domain.QueryParameters; + +namespace ReverseAnalytics.Services; -namespace ReverseAnalytics.Services +public sealed class ProductCategoryService(ICommonRepository repository, IMapper mapper) : IProductCategoryService { - public class ProductCategoryService : IProductCategoryService + private readonly ICommonRepository _repository = repository ?? throw new ArgumentNullException(nameof(repository)); + private readonly IMapper _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + + public async Task> GetAllAsync() + { + var entities = await _repository.ProductCategory.FindAllAsync(); + + return _mapper.Map>(entities); + } + + public async Task<(IEnumerable Data, PaginationMetaData PaginationMetaData)> GetAllAsync(ProductCategoryQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var paginatedResult = await _repository.ProductCategory.FindAllAsync(queryParameters); + + return (_mapper.Map>(paginatedResult), paginatedResult.MetaData); + } + + public async Task> GetAllByParentIdAsync(int parentId) + { + var entities = await _repository.ProductCategory.FindByParentIdAsync(parentId); + + return _mapper.Map>(entities); + } + + public async Task GetByIdAsync(int id) + { + var entity = await _repository.ProductCategory.FindByIdAsync(id); + + return _mapper.Map(entity); + } + + public async Task CreateAsync(ProductCategoryForCreateDto categoryToCreate) + { + ArgumentNullException.ThrowIfNull(categoryToCreate); + + var entity = _mapper.Map(categoryToCreate); + var createdEntity = await _repository.ProductCategory.CreateAsync(entity); + + return _mapper.Map(createdEntity); + } + + public async Task UpdateAsync(ProductCategoryForUpdateDto categoryToUpdate) + { + ArgumentNullException.ThrowIfNull(categoryToUpdate); + + var entity = _mapper.Map(categoryToUpdate); + var updatedEntity = await _repository.ProductCategory.UpdateAsync(entity); + + return _mapper.Map(updatedEntity); + } + + public async Task DeleteAsync(int id) { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public ProductCategoryService(ICommonRepository repository, IMapper mapper) - { - _repository = repository ?? throw new ArgumentNullException(nameof(repository)); - _mapper = mapper - ?? throw new ArgumentNullException(nameof(mapper)); - } - - public async Task?> GetProductCategoriesAsync() - { - try - { - var productCategories = await _repository.ProductCategory.FindAllAsync(); - - if(productCategories is null) - { - return null; - } - - var productCategoriesDto = _mapper.Map?>(productCategories); - - if (productCategoriesDto is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(ProductCategory)} Entities to {typeof(ProductCategoryDto)}."); - } - - return productCategoriesDto; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error retrieving product categories.", ex); - } - } - - public async Task?> GetProductCategoriesAsync(string? searchString) - { - try - { - var productCategories = await _repository.ProductCategory.FindAllProductCategoriesAsync(searchString); - - if (productCategories is null) - return null; - - var productCategoriesDto = _mapper.Map?>(productCategories); - - if (productCategoriesDto is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(Product)} Entities to {typeof(ProductCategoryDto)}."); - } - - return productCategoriesDto; - } - catch(NotFoundException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch(Exception ex) - { - throw new Exception("There was an error retrieving product categories.", ex); - } - } - - public async Task GetProductCategoryByIdAsync(int id) - { - try - { - var productCategory = await _repository.ProductCategory.FindByIdAsync(id); - - if (productCategory is null) - { - return null; - } - - var productCategoryDto = _mapper.Map(productCategory); - - if (productCategoryDto is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(ProductCategory)} Entity to {typeof(ProductCategoryDto)}."); - } - - return productCategoryDto; - } - catch(NotFoundException ex) - { - throw ex; - } - catch(AutoMapperMappingException ex) - { - throw ex; - } - catch(Exception ex) - { - throw new Exception($"There was an error retrieving Product Category with id: {id}", ex); - } - } - - public async Task CreateProductCategoryAsync(ProductCategoryForCreateDto productCategoryToCreate) - { - try - { - if (productCategoryToCreate is null) - { - throw new ArgumentNullException(nameof(productCategoryToCreate)); - } - - var productCategoryEntity = _mapper.Map(productCategoryToCreate); - - if (productCategoryEntity is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(ProductCategoryForCreateDto)} to {typeof(ProductCategory)}."); - } - - _repository.ProductCategory.Create(productCategoryEntity); - await _repository.ProductCategory.SaveChangesAsync(); - - var productCategoryDto = _mapper.Map(productCategoryEntity); - - if(productCategoryDto is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(ProductCategory)} Entity to {typeof(ProductCategoryDto)}."); - } - - return productCategoryDto; - } - catch(ArgumentNullException ex) - { - throw ex; - } - catch(AutoMapperMappingException ex) - { - throw ex; - } - catch(Exception ex) - { - throw new Exception("There was an error while adding new Product Category.", ex); - } - } - - public async Task UpdateProductCategoryAsync(ProductCategoryForUpdateDto productCategoryToUpdate) - { - try - { - if (productCategoryToUpdate is null) - { - throw new ArgumentNullException(nameof(productCategoryToUpdate)); - } - - var productCategoryEntity = _mapper.Map(productCategoryToUpdate); - - if (productCategoryEntity is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(ProductCategory)} Entity to {typeof(ProductCategoryDto)}."); - } - - _repository.ProductCategory.Update(productCategoryEntity); - await _repository.ProductCategory.SaveChangesAsync(); - } - catch (ArgumentNullException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error updating Product Category", ex); - } - } - - public async Task DeleteProductCategoryAsync(int productCategoryId) - { - try - { - _repository.ProductCategory.Delete(productCategoryId); - await _repository.ProductCategory.SaveChangesAsync(); - } - catch(NotFoundException ex) - { - throw ex; - } - catch(Exception ex) - { - throw new Exception($"There was an error deleting Product Category with id: {productCategoryId}", ex); - } - } + await _repository.ProductCategory.DeleteAsync(id); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Services/ProductService.cs b/Reverse-Analytics/ReverseAnalytics.Services/ProductService.cs index 61136d5..9163319 100644 --- a/Reverse-Analytics/ReverseAnalytics.Services/ProductService.cs +++ b/Reverse-Analytics/ReverseAnalytics.Services/ProductService.cs @@ -1,215 +1,63 @@ using AutoMapper; using ReverseAnalytics.Domain.DTOs.Product; using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Exceptions; using ReverseAnalytics.Domain.Interfaces.Repositories; using ReverseAnalytics.Domain.Interfaces.Services; +using ReverseAnalytics.Domain.QueryParameters; -namespace ReverseAnalytics.Services -{ - public class ProductService : IProductService - { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public ProductService(ICommonRepository repository, IMapper mapper) - { - _repository = repository; - _mapper = mapper; - } - - public async Task?> GetProductsAsync() - { - try - { - var products = await _repository.Product.FindAllAsync(); - - if (products is null) - { - return null; - } - - var productDtos = _mapper.Map?>(products); - - if (productDtos is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(Product)} Entities to {typeof(ProductDto)}."); - } - - return productDtos; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error retrieving Products.", ex); - } - } - - public async Task?> GetProductsAsync(string? searchString, int? categoryId, int pageSize, int pageNumber) - { - try - { - var products = await _repository.Product.FindAllProductsAsync(searchString, categoryId, pageSize, pageNumber); - - if (products is null) - { - return null; - } - - var productDtos = _mapper.Map?>(products); - - if (productDtos is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(Product)} Entities to {typeof(ProductDto)}."); - } - - return productDtos; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error retrieving product categories.", ex); - } - } - - public async Task GetProductByIdAsync(int id) - { - try - { - var product = await _repository.Product.FindByIdAsync(id); - - if(product is null) - { - return null; - } +namespace ReverseAnalytics.Services; - var productDto = _mapper.Map(product); - - if (productDto is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(Product)} Entity to {typeof(ProductDto)}."); - } +public sealed class ProductService(ICommonRepository repository, IMapper mapper) : IProductService +{ + private readonly ICommonRepository _repository = repository ?? throw new ArgumentNullException(nameof(repository)); + private readonly IMapper _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); - return productDto; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error retrieving product categories.", ex); - } - } + public async Task> GetAllAsync() + { + var entities = await _repository.Product.FindAllAsync(); - public async Task CreateProductAsync(ProductForCreateDto productToCreate) - { - try - { - if(productToCreate is null) - { - throw new ArgumentNullException(nameof(productToCreate)); - } + return _mapper.Map>(entities); + } - var productEntity = _mapper.Map(productToCreate); + public async Task> GetAllAsync(ProductQueryParameters queryParameters) + { + var entities = await _repository.Product.FindAllAsync(queryParameters); - if(productEntity is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(ProductForCreateDto)} to {typeof(Product)} Entity."); - } + return _mapper.Map>(entities); + } - productEntity = _repository.Product.Create(productEntity); - await _repository.Product.SaveChangesAsync(); + public async Task> GetByCategoryAsync(int categoryId) + { + var entities = await _repository.Product.FindByCategoryIdAsync(categoryId); - var productDto = _mapper.Map(productEntity); + return _mapper.Map>(entities); + } - if(productDto is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(Product)} Entity to {typeof(ProductDto)}."); - } + public async Task GetByIdAsync(int id) + { + var entity = await _repository.Product.FindByIdAsync(id); - return productDto; - } - catch (ArgumentNullException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error while adding new Product.", ex); - } - } + return _mapper.Map(entity); + } - public async Task UpdateProductAsync(ProductForUpdateDto productToUpdate) - { - try - { - if(productToUpdate is null) - { - throw new ArgumentNullException(nameof(productToUpdate)); - } + public async Task CreateAsync(ProductForCreateDto productToCreate) + { + var entity = _mapper.Map(productToCreate); + var createdEntity = await _repository.Product.CreateAsync(entity); - var productEntity = _mapper.Map(productToUpdate); + return _mapper.Map(createdEntity); + } - if(productEntity is null) - { - throw new AutoMapperMappingException($"Could not map {typeof(ProductForUpdateDto)} to {typeof(Product)} Entity."); - } + public async Task DeleteAsync(int id) + { + await _repository.Product.DeleteAsync(id); + } - _repository.Product.Update(productEntity); - await _repository.Product.SaveChangesAsync(); - } - catch (ArgumentNullException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error while updating Product.", ex); - } - } + public async Task UpdateAsync(ProductForUpdateDto productToUpdate) + { + var entity = _mapper.Map(productToUpdate); + var updatedEntity = await _repository.Product.UpdateAsync(entity); - public async Task DeleteProductAsync(int id) - { - try - { - _repository.Product.Delete(id); - await _repository.Product.SaveChangesAsync(); - } - catch(Exception ex) - { - throw new Exception($"There was an error deleting Product with id: {id}.", ex); - } - } + return _mapper.Map(updatedEntity); } } diff --git a/Reverse-Analytics/ReverseAnalytics.Services/ReverseAnalytics.Services.csproj b/Reverse-Analytics/ReverseAnalytics.Services/ReverseAnalytics.Services.csproj index c4aa5a6..c924c28 100644 --- a/Reverse-Analytics/ReverseAnalytics.Services/ReverseAnalytics.Services.csproj +++ b/Reverse-Analytics/ReverseAnalytics.Services/ReverseAnalytics.Services.csproj @@ -1,22 +1,12 @@ - + - net6.0 + net8.0 enable enable - preview - - - - - - - - - diff --git a/Reverse-Analytics/ReverseAnalytics.Services/SaleDetailService.cs b/Reverse-Analytics/ReverseAnalytics.Services/SaleDetailService.cs deleted file mode 100644 index d558821..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/SaleDetailService.cs +++ /dev/null @@ -1,138 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.SaleDetail; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Exceptions; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace ReverseAnalytics.Services -{ - public class SaleDetailService : ISaleDetailService - { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public SaleDetailService(ICommonRepository repository, IMapper mapper) - { - _repository = repository; - _mapper = mapper; - } - - public async Task?> GetAllSaleDetailsBySaleIdAsync(int saleId) - { - try - { - var saleDetails = await _repository.SaleDetail.FindAllBySaleIdAsync(saleId); - - if (saleDetails is null) - { - return null; - } - - var saleDetailDtos = _mapper.Map>(saleDetails); - - return saleDetailDtos; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception($"There was an error retrieving Sale Details for Sale with id: {saleId}", ex); - } - } - - public async Task GetSaleDetailBySaleAndDetailIdAsync(int saleId, int detailId) - { - try - { - var saleDetail = await _repository.SaleDetail.FindBySaleAndDetailIdAsync(saleId, detailId); - - var saleDetailDto = _mapper.Map(saleDetail); - - return saleDetailDto; - } - catch - { - throw; - } - } - - public async Task GetSaleDetailByIdAsync(int saleDetailId) - { - try - { - var saleDetailEntity = await _repository.SaleDetail.FindByIdAsync(saleDetailId); - - var saleDetailDto = _mapper.Map(saleDetailEntity); - - return saleDetailDto; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception($"There was an error retrieving Sale Detail with Sale Detail with id: {saleDetailId}.", ex); - } - } - - public async Task CreateSaleDetailAsync(SaleDetailForCreateDto saleDetailToCreate) - { - try - { - var saleDetailEntity = _mapper.Map(saleDetailToCreate); - - var createdEntity = _repository.SaleDetail.Create(saleDetailEntity); - await _repository.SaveChangesAsync(); - - var saleDetailDto = _mapper.Map(createdEntity); - - return saleDetailDto; - } - catch (Exception ex) - { - throw new Exception("There was an error creating new Sale Detail.", ex); - } - } - - public async Task UpdateSaleDetailAsync(SaleDetailForUpdateDto saleDetailToUpdate) - { - try - { - if (saleDetailToUpdate is null) - { - throw new ArgumentNullException(nameof(saleDetailToUpdate)); - } - - var saleDetailEntity = _mapper.Map(saleDetailToUpdate); - - _repository.SaleDetail.Update(saleDetailEntity); - await _repository.SaveChangesAsync(); - } - catch (Exception ex) - { - throw new Exception($"There was an error updating Sale Detail with id: {saleDetailToUpdate.Id}", ex); - } - } - - public async Task DeleteSaleDetailAsync(int id) - { - try - { - _repository.SaleDetail.Delete(id); - await _repository.SaveChangesAsync(); - } - catch (NotFoundException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception($"There was an error deleting Sale Detail with id: {id}", ex); - } - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/SaleService.cs b/Reverse-Analytics/ReverseAnalytics.Services/SaleService.cs deleted file mode 100644 index 13a54fa..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/SaleService.cs +++ /dev/null @@ -1,135 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Sale; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Exceptions; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace ReverseAnalytics.Services -{ - public class SaleService : ISaleService - { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public SaleService(ICommonRepository repository, IMapper mapper) - { - _repository = repository; - _mapper = mapper; - } - - public async Task> GetAllSalesAsync(int pageSize, int pageNumber) - { - try - { - var sales = await _repository.Sale.FindAllAsync(pageSize, pageNumber); - - var saleDtos = _mapper.Map>(sales); - - return saleDtos; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("Error while retrieving Sales.", ex); - } - } - - public async Task GetSaleByIdAsync(int id) - { - try - { - var sale = await _repository.Sale.FindByIdAsync(id); - - var saleDto = _mapper.Map(sale); - - return saleDto; - } - catch (NotFoundException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception($"Error retrieving Sale with id: {id}", ex); - } - } - - public async Task CreateSaleAsync(SaleForCreateDto saleToCreate) - { - try - { - var saleEntity = _mapper.Map(saleToCreate); - var saleDetails = _mapper.Map>(saleToCreate?.SaleDetails); - - saleEntity = _repository.Sale.Create(saleEntity); - - if (saleDetails != null && saleDetails.Count > 0) - { - _repository.SaleDetail.CreateRange(saleDetails); - } - - await _repository.SaveChangesAsync(); - - var SaleDto = _mapper.Map(saleEntity); - - return SaleDto; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception("There was an error creating new Sale.", ex); - } - } - - public async Task UpdateSaleAsync(SaleForUpdateDto saleToUpdate) - { - try - { - var saleEntity = _mapper.Map(saleToUpdate); - - _repository.Sale.Update(saleEntity); - await _repository.Sale.SaveChangesAsync(); - } - catch (NotFoundException ex) - { - throw ex; - } - catch (AutoMapperMappingException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception($"There was an error updating Sale with id: {saleToUpdate?.Id}.", ex); - } - } - - public async Task DeleteSaleAsync(int id) - { - try - { - _repository.Sale.Delete(id); - await _repository.Sale.SaveChangesAsync(); - } - catch (NotFoundException ex) - { - throw ex; - } - catch (Exception ex) - { - throw new Exception($"There was an error deleting Sale with id: {id}.", ex); - } - } - } -} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Services/SupplierService.cs b/Reverse-Analytics/ReverseAnalytics.Services/SupplierService.cs deleted file mode 100644 index 4e484a3..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/SupplierService.cs +++ /dev/null @@ -1,134 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Supplier; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Exceptions; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace ReverseAnalytics.Services -{ - public class SupplierService : ISupplierService - { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public SupplierService(ICommonRepository repository, IMapper mapper) - { - _repository = repository; - _mapper = mapper; - } - - public async Task> GetAllSuppliersAsync(string? searchString) - { - try - { - var suppliers = await _repository.Supplier.FindAllAsync(); - - var supplierDtos = _mapper.Map>(suppliers); - - return supplierDtos; - } - catch (AutoMapperMappingException) - { - throw; - } - catch(Exception) - { - throw; - } - } - - public async Task GetSupplierByIdAsync(int id) - { - try - { - var supplier = await _repository.Supplier.FindByIdAsync(id); - - var supplierDto = _mapper.Map(supplier); - - return supplierDto; - } - catch (NotFoundException) - { - throw; - } - catch (AutoMapperMappingException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task CreateSupplierAsync(SupplierForCreateDto supplierToCreate) - { - try - { - var supplierEntity = _mapper.Map(supplierToCreate); - - if(supplierEntity is null) - { - throw new AutoMapperMappingException($"There was an error mapping {typeof(SupplierForCreateDto)} to type {typeof(Supplier)}."); - } - - var createdEntity = _repository.Supplier.Create(supplierEntity); - await _repository.Supplier.SaveChangesAsync(); - - var supplierDto = _mapper.Map(createdEntity); - - return supplierDto; - } - catch (AutoMapperMappingException) - { - throw; - } - catch(Exception) - { - throw; - } - } - - public async Task UpdateSupplierAsync(SupplierForUpdateDto supplierToUpdate) - { - try - { - var supplierEntity = _mapper.Map(supplierToUpdate); - - _repository.Supplier.Update(supplierEntity); - await _repository.Supplier.SaveChangesAsync(); - } - catch (NotFoundException) - { - throw; - } - catch (AutoMapperMappingException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task DeleteSupplierAsync(int id) - { - try - { - _repository.Supplier.Delete(id); - await _repository.Supplier.SaveChangesAsync(); - } - catch (NotFoundException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/SupplyDetailService.cs b/Reverse-Analytics/ReverseAnalytics.Services/SupplyDetailService.cs deleted file mode 100644 index 0c64450..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/SupplyDetailService.cs +++ /dev/null @@ -1,181 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.SupplyDetail; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Exceptions; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace ReverseAnalytics.Services -{ - public class SupplyDetailService : ISupplyDetailService - { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public SupplyDetailService(ICommonRepository repository, IMapper mapper) - { - _repository = repository; - _mapper = mapper; - } - - public async Task> GetAllSupplyDetailsAsync() - { - try - { - var supplyDetails = await _repository.SupplyDetail.FindAllAsync(); - - var supplyDetailDtos = _mapper.Map>(supplyDetails); - - return supplyDetailDtos; - } - catch (AutoMapperMappingException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task> GetAllSupplyDetailsByProductIdAsync(int productId) - { - try - { - var supplyDetails = await _repository.SupplyDetail.FindAllByProductIdAsync(productId); - - var supplyDetailDtos = _mapper.Map>(supplyDetails); - - return supplyDetailDtos; - } - catch (AutoMapperMappingException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task GetBySupplyAndDetailIdAsync(int supplyId, int detailId) - { - try - { - var supplyDetail = await _repository.SupplyDetail.FindBySupplyAndDetailIdAsync(supplyId, detailId); - - var supplyDetailDto = _mapper.Map(supplyDetail); - - return supplyDetailDto; - } - catch - { - throw; - } - } - - public async Task> GetAllSupplyDetailsBySupplyIdAsync(int supplyId) - { - try - { - var supplyDetails = await _repository.SupplyDetail.FindAllBySupplyIdAsync(supplyId); - - var supplyDetailDtos = _mapper.Map>(supplyDetails); - - return supplyDetailDtos; - } - catch (AutoMapperMappingException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task GetSupplyDetailByIdAsync(int supplyDetailid) - { - try - { - var supplyDetail = await _repository.SupplyDetail.FindByIdAsync(supplyDetailid); - - var supplyDetailDto = _mapper.Map(supplyDetail); - - return supplyDetailDto; - } - catch (AutoMapperMappingException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task CreateSupplyDetailAsync(SupplyDetailForCreateDto supplyDetailToCreate) - { - try - { - var supplyDetailEntity = _mapper.Map(supplyDetailToCreate); - - var createdEntity = _repository.SupplyDetail.Create(supplyDetailEntity); - await _repository.SaveChangesAsync(); - - var supplyDetailDto = _mapper.Map(createdEntity); - - return supplyDetailDto; - } - catch (AutoMapperMappingException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task UpdateSupplyDetailAsync(SupplyDetailForUpdateDto supplyDetailToUpdate) - { - try - { - var supplyDetailEntity = _mapper.Map(supplyDetailToUpdate); - - _repository.SupplyDetail.Update(supplyDetailEntity); - await _repository.SaveChangesAsync(); - } - catch (NotFoundException) - { - throw; - } - catch (AutoMapperMappingException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task DeleteSupplyDetailAsync(int supplyDetailid) - { - try - { - _repository.SupplyDetail.Delete(supplyDetailid); - await _repository.SaveChangesAsync(); - } - catch (NotFoundException) - { - - throw; - } - catch (Exception) - { - throw; - } - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/SupplyService.cs b/Reverse-Analytics/ReverseAnalytics.Services/SupplyService.cs deleted file mode 100644 index 0e46153..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/SupplyService.cs +++ /dev/null @@ -1,128 +0,0 @@ -using AutoMapper; -using ReverseAnalytics.Domain.DTOs.Supply; -using ReverseAnalytics.Domain.Entities; -using ReverseAnalytics.Domain.Exceptions; -using ReverseAnalytics.Domain.Interfaces.Repositories; -using ReverseAnalytics.Domain.Interfaces.Services; - -namespace ReverseAnalytics.Services -{ - public class SupplyService : ISupplyService - { - private readonly ICommonRepository _repository; - private readonly IMapper _mapper; - - public SupplyService(ICommonRepository repository, IMapper mapper) - { - _repository = repository; - _mapper = mapper; - } - - public async Task> GetAllSuppliesAsync() - { - try - { - var supplies = await _repository.Supply.FindAllAsync(); - - var supplyDtos = _mapper.Map>(supplies); - - return supplyDtos; - } - catch (Exception) - { - throw; - } - } - - public async Task> GetAllSuppliesBySupplierIdAsync(int supplierId) - { - try - { - var supplies = await _repository.Supply.FindAllBySupplierIdAsync(supplierId); - - var supplyDtos = _mapper.Map>(supplies); - - return supplyDtos; - } - catch (Exception) - { - throw; - } - } - - public async Task GetSupplyByIdAsync(int supplyId) - { - try - { - var supply = await _repository.Supply.FindByIdAsync(supplyId); - - var supplyDto = _mapper.Map(supply); - - return supplyDto; - } - catch (NotFoundException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task CreateSupplyAsync(SupplyForCreateDto supplyToCreate) - { - try - { - var supplyEntity = _mapper.Map(supplyToCreate); - - _repository.Supply.Create(supplyEntity); - await _repository.SaveChangesAsync(); - - var supplyDto = _mapper.Map(supplyEntity); - - return supplyDto; - } - catch (Exception) - { - throw; - } - } - - public async Task UpdateSupplyAsync(SupplyForUpdateDto supplyToUpdate) - { - try - { - var supplyEntity = _mapper.Map(supplyToUpdate); - - _repository.Supply.Update(supplyEntity); - await _repository.SaveChangesAsync(); - } - catch (NotFoundException) - { - throw; - } - catch (Exception) - { - throw; - } - } - - public async Task DeleteSupplyAsync(int supplyId) - { - try - { - _repository.Supply.Delete(supplyId); - await _repository.SaveChangesAsync(); - } - catch (NotFoundException) - { - throw; - } - catch (Exception) - { - - } - } - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.Services/TokenService.cs b/Reverse-Analytics/ReverseAnalytics.Services/TokenService.cs deleted file mode 100644 index 4604a8e..0000000 --- a/Reverse-Analytics/ReverseAnalytics.Services/TokenService.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Tokens; -using ReverseAnalytics.Domain.DTOs.Authentication; -using ReverseAnalytics.Domain.Interfaces.Services; -using ReverseAnalytics.Infrastructure.Configurations; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Text; - -namespace ReverseAnalytics.Services -{ - public class TokenService : ITokenService - { - private readonly CustomTokenOptions _tokenOptions; - - public TokenService(IOptions tokenOptions) - { - _tokenOptions = tokenOptions.Value; - } - - public JwtSecurityToken CreateToken(AuthenticationRequest request) - { - DateTime now = DateTime.Now; - - var accessTokenExpiration = now.AddDays(_tokenOptions.AccessTokenExpiration); - var securityKey = GetSymmetricSecurityKey(_tokenOptions.SecurityKey); - - SigningCredentials signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature); - - JwtSecurityToken token = new( - issuer: _tokenOptions.Issuer, - audience: _tokenOptions.Audience, - expires: accessTokenExpiration, - notBefore: now, - claims: GetClaims(request, new List()), - signingCredentials: signingCredentials); - - return token; - } - - private IEnumerable GetClaims(AuthenticationRequest request, List audiences) - { - var claims = new List - { - new Claim(ClaimTypes.Name, request.UserName), - new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), - }; - - claims.AddRange(audiences.Select(p => new Claim(JwtRegisteredClaimNames.Aud, p))); - return claims; - } - - public static SecurityKey GetSymmetricSecurityKey(string securityKey) - => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(securityKey)); - } -} diff --git a/Reverse-Analytics/ReverseAnalytics.TestDataCreator/Fakers.cs b/Reverse-Analytics/ReverseAnalytics.TestDataCreator/Fakers.cs new file mode 100644 index 0000000..bae1f95 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.TestDataCreator/Fakers.cs @@ -0,0 +1,80 @@ +using Bogus; +using Bogus.Extensions; +using ReverseAnalytics.Domain.Entities; +using ReverseAnalytics.Domain.Enums; + +namespace ReverseAnalytics.TestDataCreator; + +public class Fakers +{ + public Faker Customer() + => new Faker() + .RuleFor(x => x.FirstName, f => f.Person.FirstName) + .RuleFor(x => x.LastName, f => f.Person.LastName) + .RuleFor(x => x.PhoneNumber, f => f.Phone.PhoneNumber("+998 ## ###-##-##")) + .RuleFor(x => x.Company, f => f.Person.Company.Name) + .RuleFor(x => x.Address, f => f.Person.Address.Street) + .RuleFor(x => x.Balance, f => f.Random.Decimal2(0, 1_000_000)) + .RuleFor(x => x.Discount, f => f.Random.Double(0, 99)); + + public Faker ProductCategory() + => new Faker() + .RuleFor(x => x.Name, f => f.Commerce.Department()) + .RuleFor(x => x.Description, f => f.Lorem.Sentence()); + + public Faker Product(int[] categoryIds) + => new Faker() + .RuleFor(x => x.Name, f => f.Commerce.ProductName()) + .RuleFor(x => x.Description, f => f.Commerce.ProductDescription()) + .RuleFor(x => x.SupplyPrice, f => f.Random.Decimal2(10_000, 1_000_00)) + .RuleFor(x => x.SalePrice, (f, x) => f.Random.Decimal2(x.SupplyPrice, 1_500_000)) + .RuleFor(x => x.Volume, f => f.Random.Double(10, 100)) + .RuleFor(x => x.Weight, f => f.Random.Double(100, 1000)) + .RuleFor(x => x.UnitOfMeasurement, f => f.Random.Enum()) + .RuleFor(x => x.CategoryId, f => f.Random.ArrayElement(categoryIds)); + + public Faker Sale(int[] customerIds) + => new Faker() + .RuleFor(x => x.Date, f => f.Date.Between(DateTime.Now.AddYears(-2), DateTime.Now.AddMonths(6))) + .RuleFor(x => x.Comments, f => f.Lorem.Sentence()) + .RuleFor(x => x.TotalDue, f => f.Random.Decimal2(10_000, 5_000_000)) + .RuleFor(x => x.TotalPaid, f => f.Random.Decimal2(5_000, 6_000_000)) + .RuleFor(x => x.TotalDiscount, (_, x) => x.TotalDue - x.TotalPaid) + .RuleFor(x => x.SaleType, f => f.Random.Enum()) + .RuleFor(x => x.Status, f => f.Random.Enum()) + .RuleFor(x => x.PaymentType, f => f.Random.Enum()) + .RuleFor(x => x.Currency, f => f.Random.Enum()) + .RuleFor(x => x.CustomerId, f => f.Random.ArrayElement(customerIds)); + + public Faker SaleItems(int[] saleIds, int[] productIds) + => new Faker() + .RuleFor(x => x.SaleId, f => f.Random.ArrayElement(saleIds)) + .RuleFor(x => x.ProductId, f => f.Random.ArrayElement(productIds)) + .RuleFor(x => x.UnitPrice, f => f.Random.Decimal2(10_000, 1_000_000)) + .RuleFor(x => x.Quantity, f => f.Random.Int(1, 100)); + + public Faker Supplier() + => new Faker() + .RuleFor(x => x.FirstName, f => f.Person.FirstName) + .RuleFor(x => x.LastName, f => f.Person.LastName) + .RuleFor(x => x.PhoneNumber, f => f.Phone.PhoneNumber("+998 ## ###-##-##")) + .RuleFor(x => x.Company, f => f.Person.Company.Name) + .RuleFor(x => x.Balance, f => f.Random.Decimal2(0, 1_000_000)); + + public Faker Supply(int[] supplierIds) + => new Faker() + .RuleFor(x => x.Date, f => f.Date.Between(DateTime.Now.AddYears(-2), DateTime.Now.AddMonths(6))) + .RuleFor(x => x.Comments, f => f.Lorem.Sentence()) + .RuleFor(x => x.TotalDue, f => f.Random.Decimal2(10_000, 5_000_000)) + .RuleFor(x => x.TotalPaid, f => f.Random.Decimal2(5_000, 6_000_000)) + .RuleFor(x => x.PaymentType, f => f.Random.Enum()) + .RuleFor(x => x.Currency, f => f.Random.Enum()) + .RuleFor(x => x.SupplierId, f => f.Random.ArrayElement(supplierIds)); + + public Faker SupplyItems(int[] supplyIds, int[] productIds) + => new Faker() + .RuleFor(x => x.SupplyId, f => f.Random.ArrayElement(supplyIds)) + .RuleFor(x => x.ProductId, f => f.Random.ArrayElement(productIds)) + .RuleFor(x => x.UnitPrice, f => f.Random.Decimal2(10_000, 1_000_000)) + .RuleFor(x => x.Quantity, f => f.Random.Int(100)); +} diff --git a/Reverse-Analytics/ReverseAnalytics.Repositories/ReverseAnalytics.Repositories.csproj b/Reverse-Analytics/ReverseAnalytics.TestDataCreator/ReverseAnalytics.TestDataCreator.csproj similarity index 54% rename from Reverse-Analytics/ReverseAnalytics.Repositories/ReverseAnalytics.Repositories.csproj rename to Reverse-Analytics/ReverseAnalytics.TestDataCreator/ReverseAnalytics.TestDataCreator.csproj index ee2695f..802a11b 100644 --- a/Reverse-Analytics/ReverseAnalytics.Repositories/ReverseAnalytics.Repositories.csproj +++ b/Reverse-Analytics/ReverseAnalytics.TestDataCreator/ReverseAnalytics.TestDataCreator.csproj @@ -1,17 +1,13 @@ - + - net6.0 - enable + net8.0 enable - preview + enable - - - diff --git a/Reverse-Analytics/ReverseAnalytics.Tests.Api/Endpoints/EndpointsTests.cs b/Reverse-Analytics/ReverseAnalytics.Tests.Api/Endpoints/EndpointsTests.cs new file mode 100644 index 0000000..05f3562 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Tests.Api/Endpoints/EndpointsTests.cs @@ -0,0 +1,21 @@ +using FluentAssertions; + +namespace ReverseAnalytics.Tests.Api.Endpoints; + +public class EndpointsTests(TestingWebAppFactory factory) : EndpointsBase(factory) +{ + [Theory] + [InlineData("categories")] + public async Task Get_EndpointsShouldReturnSuccessAndCorrectStatusType(string url) + { + // Arrange + var client = _factory.CreateClient(); + + // Act + var response = await client.GetAsync(url); + + // Assert + response.EnsureSuccessStatusCode(); + response.Content.Headers.ContentType!.ToString().Should().Be("application/json; charset=utf-8"); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Tests.Api/Endpoints/ProductCategoryTests.cs b/Reverse-Analytics/ReverseAnalytics.Tests.Api/Endpoints/ProductCategoryTests.cs new file mode 100644 index 0000000..f6fcdd4 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Tests.Api/Endpoints/ProductCategoryTests.cs @@ -0,0 +1,68 @@ +using FluentAssertions; +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Domain.DTOs.ProductCategory; +using ReverseAnalytics.Domain.Entities; + +namespace ReverseAnalytics.Tests.Api.Endpoints; + +public class ProductCategoryTests(TestingWebAppFactory factory) : EndpointsBase(factory) +{ + public static IEnumerable FilterParameters() + { + return + [ + [new Dictionary { { "pageSize", "10" } }, 10], + [new Dictionary { { "pageSize", "25" } }, 25], + [new Dictionary { { "pageSize", "60" } }, 50], + [new Dictionary { { "pageSize", "100" } }, 50] + ]; + } + + [Theory] + [MemberData(nameof(FilterParameters))] + public async Task GetRequest_ShouldCorrectlyPaginate(Dictionary filterParameters, int expectedCount) + { + // Arrange + var query = string.Join("&", filterParameters.Select(kv => $"{kv.Key}={kv.Value}")); + + // Act + var response = await _client.GetFromJsonAsync>("categories" + $"?{query}"); + + // Assert + response.Should().NotBeEmpty(); + response!.Count.Should().Be(expectedCount); + } + + [Fact] + public async Task GetById_ShouldReturnCorrectCategory() + { + // Arrange + var expected = await _context.ProductCategories + .Include(x => x.Parent) + .Include(x => x.SubCategories) + .Include(x => x.Products) + .FirstOrDefaultAsync(); + + // Act + var actual = await _client.GetFromJsonAsync($"categories/{expected!.Id}"); + + // Assert + Assert.NotNull(actual); + ValidateCategory(expected, actual); + + foreach (var child in expected.SubCategories) + { + ValidateCategory(child, actual); + } + } + + private static void ValidateCategory(ProductCategory expected, ProductCategoryDto actual) + { + actual.Should().NotBeNull(); + actual.Id.Should().Be(expected.Id); + actual.Name.Should().Be(expected.Name); + actual.Description.Should().Be(expected.Description); + actual.ParentId.Should().Be(expected.ParentId); + actual.ParentName.Should().Be(expected.Parent?.Name); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Tests.Api/EndpointsBase.cs b/Reverse-Analytics/ReverseAnalytics.Tests.Api/EndpointsBase.cs new file mode 100644 index 0000000..2bef8aa --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Tests.Api/EndpointsBase.cs @@ -0,0 +1,22 @@ +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Tests.Api; + +public class EndpointsBase : IClassFixture +{ + protected readonly HttpClient _client; + protected readonly TestingWebAppFactory _factory; + protected readonly ApplicationDbContext _context; + + public EndpointsBase(TestingWebAppFactory factory) + { + factory.ClientOptions.BaseAddress = new Uri("https://localhost/api/"); + factory.ClientOptions.AllowAutoRedirect = false; + + _factory = factory; + _client = factory.CreateClient(); + + var scope = factory.Services.CreateScope(); + _context = scope.ServiceProvider.GetRequiredService(); + } +} diff --git a/Reverse-Analytics/ReverseAnalytics.Tests.Api/Properties/launchSettings.json b/Reverse-Analytics/ReverseAnalytics.Tests.Api/Properties/launchSettings.json new file mode 100644 index 0000000..72518ac --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Tests.Api/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "ReverseAnalytics.Tests.Api": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:55515;http://localhost:55516" + } + } +} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Tests.Api/ReverseAnalytics.Tests.Api.csproj b/Reverse-Analytics/ReverseAnalytics.Tests.Api/ReverseAnalytics.Tests.Api.csproj new file mode 100644 index 0000000..1755688 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Tests.Api/ReverseAnalytics.Tests.Api.csproj @@ -0,0 +1,35 @@ + + + + net8.0 + enable + enable + + false + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + diff --git a/Reverse-Analytics/ReverseAnalytics.Tests.Api/TestingWebAppFactory.cs b/Reverse-Analytics/ReverseAnalytics.Tests.Api/TestingWebAppFactory.cs new file mode 100644 index 0000000..b2a7e48 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Tests.Api/TestingWebAppFactory.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.EntityFrameworkCore; +using ReverseAnalytics.Infrastructure.Persistence; + +namespace ReverseAnalytics.Tests.Api; + +public class TestingWebAppFactory : WebApplicationFactory +{ + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.ConfigureServices(services => + { + var descriptor = services.SingleOrDefault( + d => d.ServiceType == typeof(DbContextOptions)); + + if (descriptor != null) + { + services.Remove(descriptor); + } + + services.AddDbContext(options => + { + options.UseSqlite("Data Source = ApiTestsDB", + x => x.MigrationsAssembly("ReverseAnalytics.Migrations.Sqlite")); + }); + + var serviceProvider = services.BuildServiceProvider(); + + using var scope = serviceProvider.CreateScope(); + using var appContext = scope.ServiceProvider.GetRequiredService(); + + try + { + // appContext.Database.EnsureDeleted(); + appContext.Database.EnsureCreated(); + } + catch (Exception) + { + throw; + } + }); + } +} \ No newline at end of file diff --git a/Reverse-Analytics/ReverseAnalytics.Tests.Api/xunit.runner.json b/Reverse-Analytics/ReverseAnalytics.Tests.Api/xunit.runner.json new file mode 100644 index 0000000..1797133 --- /dev/null +++ b/Reverse-Analytics/ReverseAnalytics.Tests.Api/xunit.runner.json @@ -0,0 +1,3 @@ +{ + +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/ArchitectureTestsBase.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/ArchitectureTestsBase.cs new file mode 100644 index 0000000..446179d --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/ArchitectureTestsBase.cs @@ -0,0 +1,57 @@ +namespace ReverseAnalytics.Tests.Unit.Architecture; + +public class ArchitectureTestsBase +{ + protected readonly Assembly DomainAssembly = typeof(BaseEntity).Assembly; + protected readonly Assembly InfrastructureAssembly = typeof(ApplicationDbContext).Assembly; + protected readonly Assembly ServicesAssembly = typeof(ProductCategoryService).Assembly; + + protected ArchitectureTestsBase() + { + } + + protected List GetEntities() + { + return DomainAssembly.GetTypes() + .Where(t => !t.IsAbstract && !t.IsInterface) + .Where(t => t.IsAssignableTo(typeof(BaseEntity))) + .ToList(); + } + + protected List GetConfigurations() + { + return InfrastructureAssembly.GetTypes() + .Where(IsEntityTypeConfiguration) + .ToList(); + } + + protected List GetServices() + { + return ServicesAssembly.GetTypes() + .Where(t => t.Namespace != null && t.Namespace.Equals("ReverseAnalytics.Services")) + .Where(t => !t.IsAbstract && !t.IsInterface && t.IsClass && !t.IsAnsiClass) + .ToList(); + } + + protected List GetMappers() + { + return DomainAssembly.GetTypes() + .Where(t => !t.IsAbstract && !t.IsInterface) + .Where(t => t.IsAssignableTo(typeof(Profile))) + .ToList(); + } + + protected List GetQueryParameters() + { + return DomainAssembly.GetTypes() + .Where(x => !x.IsAbstract && !x.IsInterface) + .Where(t => t.IsAssignableTo(typeof(QueryParametersBase))) + .ToList(); + } + + private static bool IsEntityTypeConfiguration(Type type) + { + var interfaceType = type.GetInterfaces().ToList(); + return interfaceType.Exists(r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)); + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/CommonServicesFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/CommonServicesFixture.cs new file mode 100644 index 0000000..df9dc28 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/CommonServicesFixture.cs @@ -0,0 +1,46 @@ +namespace ReverseAnalytics.Tests.Unit.Architecture; + +public class CommonServicesFixture : ArchitectureTestsBase +{ + [Fact] + public void Services_ShouldBeSealed() + { + // Arrange + var services = GetServices(); + + // Act & Assert + foreach (var service in services) + { + service.IsSealed.Should().BeTrue($"Service: {service.Name} should be sealed."); + } + } + + [Fact] + public void Services_ShouldImplementInterface_FromDomain() + { + // Arrange + var services = GetServices(); + + // Act & Assert + foreach (var service in services) + { + var interfaces = service.GetInterfaces(); + var result = interfaces.Where(t => t.Namespace != null && t.Namespace.Contains("Domain.Interfaces.Services")).ToList(); + + result.Should().NotBeEmpty($"{service.Name} should implement at least one interface defined in Domain"); + } + } + + [Fact] + public void Services_ShouldHaveName_EndWithService() + { + // Arrange + var services = GetServices(); + + // Act & Assert + foreach (var service in services) + { + service.Name.Should().EndWith("Service"); + } + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/ConstructorsFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/ConstructorsFixture.cs new file mode 100644 index 0000000..7ca2bcd --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/ConstructorsFixture.cs @@ -0,0 +1,86 @@ +namespace ReverseAnalytics.Tests.Unit.Architecture; + +public class ConstructorsFixture : ArchitectureTestsBase +{ + [Fact] + public void ConstructorsOfAllControllers_ShouldThrowArgumentNullException_WhenAnyParameterIsNull() + { + // Arrange + var constructors = Types.InAssembly(DomainAssembly) + .GetTypes() + .Where(t => t.Namespace is not null && t.Namespace.Contains("Controllers")) + .Where(t => t.IsAssignableTo(typeof(ControllerBase))) + .SelectMany(t => t.GetConstructors()) + .Where(c => c.GetParameters().Length > 0) + .ToList(); + + // Act & Assert + foreach (var constructor in constructors) + { + var parameters = constructor.GetParameters(); + var nullArgs = new object[parameters.Length]; + var ex = Assert.Throws(() => constructor.Invoke(nullArgs)); + var innerException = ex.InnerException; + + Assert.NotNull(innerException); + Assert.IsType(innerException); + + var paramName = (innerException as ArgumentNullException)?.ParamName; + Assert.Contains(paramName, parameters.Select(p => p.Name)); + } + } + + [Fact] + public void ConstructorsOfAllCoreServices_ShouldThrowArgumentNullException_WhenAnyParameterIsNull() + { + // Arrange + var constructors = typeof(ProductCategoryService).Assembly + .GetTypes() + .Where(t => t.Namespace is not null && t.Namespace.Contains("Services")) + .SelectMany(t => t.GetConstructors()) + .Where(t => t.GetParameters().Length > 0) + .ToList(); + + // Act & Assert + foreach (var constructor in constructors) + { + var parameters = constructor.GetParameters(); + var nullArgs = new object[parameters.Length]; + var ex = Assert.Throws(() => constructor.Invoke(nullArgs)); + var innerException = ex.InnerException; + + innerException.Should().NotBeNull(); + innerException.Should().BeAssignableTo(); + + var paramName = (innerException as ArgumentNullException)?.ParamName; + parameters.Should().Contain(p => p.Name == paramName); + } + } + + [Fact] + public void ConstructorsOfAllRepositories_ShouldThrowArgumentNullException_WhenAnyParameterIsNull() + { + // Arrange + var constructors = typeof(ProductCategoryRepository).Assembly + .GetTypes() + .Where(t => !t.IsAbstract && !t.IsInterface && typeof(RepositoryBase<>).IsAssignableFrom(t)) + .SelectMany(t => t.GetConstructors()) + .Where(t => t.GetParameters().Length > 0) + .ToList(); + + // Act & Assert + foreach (var constructor in constructors) + { + var parameters = constructor.GetParameters(); + var nullArgs = new object[parameters.Length]; + var ex = Assert.Throws(() => constructor.Invoke(nullArgs)); + var innerException = ex.InnerException; + + innerException.Should().NotBeNull(); + innerException.Should().BeAssignableTo(); + + var paramName = (innerException as ArgumentNullException)?.ParamName; + parameters.Should().Contain(p => p.Name == paramName); + } + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/EntitiesFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/EntitiesFixture.cs new file mode 100644 index 0000000..f3b3985 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/EntitiesFixture.cs @@ -0,0 +1,60 @@ +namespace ReverseAnalytics.Tests.Unit.Architecture; + +public class EntitiesFixture : ArchitectureTestsBase +{ + [Fact] + public void Entities_ShouldReside_InEntitiesNamespace() + { + // Arrange + + // Act + var result = Types.InAssembly(DomainAssembly) + .That() + .Inherit(typeof(BaseEntity)) + .And() + .AreNotAbstract() + .And() + .AreNotInterfaces() + .Should() + .ResideInNamespace(Namespaces.ENTITIES) + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void EntitiesNamespace_ShouldContain_OnlyEntities() + { + // Arrange + + // Act + var result = Types.InNamespace(Namespaces.ENTITIES) + .Should() + .Inherit(typeof(BaseEntity)) + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void AllNavigationPropertiesInEntities_ShouldBeVirtual() + { + // Arrange + var properties = GetEntities() + .SelectMany(t => t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) + .Where(p => (p.PropertyType.IsClass || p.PropertyType.IsInterface) && p.PropertyType != typeof(string)) + .ToList(); + + // Act & Assert + properties.Should().NotBeEmpty(); + + foreach (var property in properties) + { + property.GetMethod!.IsVirtual.Should().BeTrue($"{property.DeclaringType}.{property.Name} must be declared as virtual."); + } + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/EntityConfigurationsFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/EntityConfigurationsFixture.cs new file mode 100644 index 0000000..7689f7c --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/EntityConfigurationsFixture.cs @@ -0,0 +1,86 @@ +namespace ReverseAnalytics.Tests.Unit.Architecture; + +public class EntityConfigurationsFixture : ArchitectureTestsBase +{ + [Fact] + public void Configurations_ShouldReside_InConfigurationsNamespace() + { + // Arrange + + // Act + var result = Types.InAssembly(InfrastructureAssembly) + .That() + .ImplementInterface(typeof(IEntityTypeConfiguration<>)) + .And() + .AreNotAbstract() + .And() + .AreNotInterfaces() + .Should() + .ResideInNamespace(Namespaces.ENTITY_CONFIGURATIONS) + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void ConfigurationsNamespace_ShouldContain_OnlyEntityConfigurations() + { + // Arrange + + // Act + var result = Types.InNamespace(Namespaces.ENTITY_CONFIGURATIONS) + .That() + .AreNotAbstract() + .And() + .AreNotInterfaces() + .Should() + .ImplementInterface(typeof(IEntityTypeConfiguration<>)) + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void EachEntity_ShouldHave_Configuration() + { + // Arrange + var entities = GetEntities(); + var configurations = GetConfigurations(); + + // Assert & Assert + entities.Count.Should().Be(configurations.Count, $"Expected entity configurations to be: {entities.Count}, but found: {configurations.Count}"); + } + + [Fact] + public void ConfigurationName_ShouldStart_WithEntityName() + { + // Arrange + var entities = GetEntities(); + var configurations = GetConfigurations(); + + // Act & Assert + foreach (var configuration in configurations) + { + entities.Should().Contain( + entity => configuration.Name.StartsWith(entity.Name), + $"Configuration: {configuration.Name} should start with 'Entity' name"); + } + } + + [Fact] + public void ConfigurationName_ShouldEnd_WithConfiguration() + { + // Arrange + var configurations = GetConfigurations(); + + // Act & Assert + foreach (var configuration in configurations) + { + configuration.Name.Should().EndWith("Configuration", $"{configuration.Name} should end with 'Configuration'"); + } + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/LayersFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/LayersFixture.cs new file mode 100644 index 0000000..0adb812 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/LayersFixture.cs @@ -0,0 +1,20 @@ +namespace ReverseAnalytics.Tests.Unit.Architecture; + +public class LayersFixture : ArchitectureTestsBase +{ + [Fact] + public void DomainLayer_ShouldNotHave_AnyDependencies() + { + // Arrange + + // Act + var result = Types.InAssembly(DomainAssembly) + .Should() + .NotHaveDependencyOnAll("Infrastructure", "Services", "Api") + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/MappersFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/MappersFixture.cs new file mode 100644 index 0000000..7025bac --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/MappersFixture.cs @@ -0,0 +1,82 @@ +namespace ReverseAnalytics.Tests.Unit.Architecture; + +public class MappersFixture : ArchitectureTestsBase +{ + [Fact] + public void Mappings_ShouldReside_InMappingsNamespace() + { + // Arrange + + // Act + var result = Types.InAssembly(DomainAssembly) + .That() + .Inherit(typeof(Profile)) + .Should() + .ResideInNamespace(Namespaces.MAPPINGS) + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void MappingsNamespace_ShouldContain_OnlyMappers() + { + // Arrange + + // Act + var result = Types.InNamespace(Namespaces.MAPPINGS) + .That() + .AreNotAbstract() + .And() + .AreNotInterfaces() + .Should() + .Inherit(typeof(Profile)) + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void EachEntity_ShouldHave_Mapping() + { + // Arrange + var mappers = GetMappers(); + var entities = GetEntities(); + + // Act & Assert + mappers.Count.Should().Be(entities.Count, $"Expected mappings to be: {entities.Count}, but found: {mappers.Count}"); + } + + [Fact] + public void MappingName_ShouldStartWith_EntityName() + { + // Arrange + var mappers = GetMappers(); + var entities = GetEntities(); + + // Act & Assert + foreach (var mapper in mappers) + { + entities.Should().Contain( + entity => mapper.Name.StartsWith(entity.Name), + $"Mapping: {mapper.Name} should start with Entity's name"); + } + } + + [Fact] + public void MappersName_ShouldEndWith_Mappings() + { + // Arrange + var mappers = GetMappers(); + + // Act & Assert + foreach (var mapper in mappers) + { + mapper.Name.Should().EndWith("Mappings", $"Mapper: {mapper.Name} should end with 'Mappings'"); + } + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/QueryParametersFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/QueryParametersFixture.cs new file mode 100644 index 0000000..5a63cc5 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Architecture/QueryParametersFixture.cs @@ -0,0 +1,59 @@ +namespace ReverseAnalytics.Tests.Unit.Architecture; + +public class QueryParametersFixture : ArchitectureTestsBase +{ + [Fact] + public void QueryParameters_ShouldReside_InQueryParametersNamespace() + { + // Arrange + + // Act + var result = Types.InAssembly(DomainAssembly) + .That() + .Inherit(typeof(QueryParametersBase)) + .And() + .AreNotAbstract() + .And() + .AreNotInterfaces() + .Should() + .ResideInNamespace(Namespaces.QUERY_PARAMETERS) + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void QueryParametersNamespace_ShouldContain_OnlyQueryParameters() + { + // Arrange + + // Act + var result = Types.InNamespace(Namespaces.QUERY_PARAMETERS) + .That() + .AreNotAbstract() + .And() + .AreNotInterfaces() + .Should() + .Inherit(typeof(QueryParametersBase)) + .GetResult() + .IsSuccessful; + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void QueryParameters_ShouldEnd_WithQueryParameters() + { + // Arrange + var queryParameters = GetQueryParameters(); + + // Act & Assert + foreach (var type in queryParameters) + { + type.Name.Should().EndWith("QueryParameters", $"{type.Name} should end with 'QueryParameters'."); + } + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Constants/Namespaces.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Constants/Namespaces.cs new file mode 100644 index 0000000..65a4ee5 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Constants/Namespaces.cs @@ -0,0 +1,9 @@ +namespace ReverseAnalytics.Tests.Unit.Constants; + +internal static class Namespaces +{ + public const string QUERY_PARAMETERS = "ReverseAnalytics.Domain.QueryParameters"; + public const string ENTITIES = "ReverseAnalytics.Domain.Entities"; + public const string MAPPINGS = "ReverseAnalytics.Domain.Mappings"; + public const string ENTITY_CONFIGURATIONS = "ReverseAnalytics.Infrastructure.Persistence.Configurations"; +} \ No newline at end of file diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Controllers/ControllerFixtureBase.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Controllers/ControllerFixtureBase.cs new file mode 100644 index 0000000..b70ef88 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Controllers/ControllerFixtureBase.cs @@ -0,0 +1,46 @@ +namespace ReverseAnalytics.Tests.Unit.Controllers; + +public abstract class ControllerFixtureBase : FixtureBase +{ + protected readonly ControllerContext _controllerContext; + protected readonly HttpResponse _response; + + protected ControllerFixtureBase() + { + _controllerContext = GetControllerContext(); + _response = _controllerContext.HttpContext.Response; + } + + private static ControllerContext GetControllerContext() + { + var httpContext = new DefaultHttpContext(); + var controllerContext = new ControllerContext { HttpContext = httpContext }; + + return controllerContext; + } + + /// + /// Creates a PaginatedList with randomized data for + /// testing purposes while ensuring valid pagination parameters. + /// This method prevents potential errors caused by AutoFixture + /// when creating PaginatedList with invalid constructor params, + /// such as Items length being more than the TotalCount value. + /// + /// + /// + protected PaginatedList CreatePaginatedList() + { + // Generate a list of items using AutoFixture + var items = _fixture.CreateMany().ToList(); + + // Ensure totalCount is greater than or equal to the count of items + var totalCount = _fixture.Create() + items.Count; + + // Generate currentPage and pageSize + var currentPage = _fixture.Create(); + var pageSize = _fixture.Create(); + + // Create and return the PaginatedList instance + return new PaginatedList(items, currentPage, pageSize, totalCount); + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Controllers/ProductCategoryControllerFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Controllers/ProductCategoryControllerFixture.cs new file mode 100644 index 0000000..922c098 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Controllers/ProductCategoryControllerFixture.cs @@ -0,0 +1,295 @@ +using FluentValidation.Results; +using Microsoft.AspNetCore.JsonPatch; +using ReverseAnalytics.Domain.DTOs.Product; + +namespace ReverseAnalytics.Tests.Unit.Controllers; + +public class ProductCategoryControllerTests : ControllerFixtureBase +{ + private readonly Mock _mockCategoryService; + private readonly Mock _mockProductService; + private readonly Mock> _mockValidator; + private readonly Mock> _mockPatchDocument; + private readonly ProductCategoryController _controller; + + public ProductCategoryControllerTests() + : base() + { + _mockCategoryService = new Mock(); + _mockProductService = new Mock(); + _mockValidator = new Mock>(); + _mockPatchDocument = new Mock>(); + + _controller = new ProductCategoryController(_mockProductService.Object, _mockCategoryService.Object, _mockValidator.Object) + { + ControllerContext = _controllerContext + }; + } + + [Fact] + public async Task GetCategoriesAsync_ShouldReturnAllCategories_WhenCalled() + { + // Arrange + var queryParameters = _fixture.Create(); + var paginatedCategories = CreatePaginatedList(); + var metadata = paginatedCategories.MetaData; + + _mockCategoryService.Setup(x => x.GetAllAsync(queryParameters)).ReturnsAsync((paginatedCategories, metadata)); + + // Act + var result = await _controller.GetCategoriesAsync(queryParameters); + var okResult = result.Result as OkObjectResult; + + // Assert + okResult.Should().NotBeNull(); + okResult!.StatusCode.Should().Be((int)HttpStatusCode.OK); + okResult!.Value.Should().BeAssignableTo>(); + okResult!.Value.Should().BeEquivalentTo(paginatedCategories); + } + + [Fact] + public async Task GetCategoriesAsync_ShouldAddPaginationHeaders_WhenCalled() + { + // Arrange + var queryParameters = _fixture.Create(); + var categories = new List(); + var metadata = _fixture.Create(); + + _mockCategoryService.Setup(x => x.GetAllAsync(queryParameters)).ReturnsAsync((categories, metadata)); + + // Act + _ = await _controller.GetCategoriesAsync(queryParameters); + var actualHeaderValue = _response.Headers["X-Pagination"].FirstOrDefault(); + var expectedHeaderValue = JsonConvert.SerializeObject(metadata, Formatting.Indented); + + // Assert + actualHeaderValue.Should().NotBeNull(); + actualHeaderValue.Should().Be(expectedHeaderValue); + } + + [Fact] + public async Task GetByIdAsync_ShouldReturnCategoryDto_WhenCalled() + { + // Arrange + var categoryId = _fixture.Create(); + var categoryDto = _fixture.Build() + .With(x => x.Id, categoryId) + .Create(); + + _mockCategoryService.Setup(x => x.GetByIdAsync(categoryId)).ReturnsAsync(categoryDto); + + // Act + var result = await _controller.GetByIdAsync(categoryId); + var okResult = result.Result as OkObjectResult; + + // Assert + okResult.Should().NotBeNull(); + okResult!.StatusCode.Should().Be(((int)HttpStatusCode.OK)); + okResult!.Value.Should().BeAssignableTo(); + okResult!.Value.Should().Be(categoryDto); + } + + [Fact] + public async Task GetByIdAsync_ShouldReturnNotFound_WhenCategoryDoesNotExist() + { + ProductCategoryDto? categoryDto = null; + + _mockCategoryService.Setup(x => x.GetByIdAsync(It.IsAny())).ReturnsAsync(categoryDto); + + // Act + var result = await _controller.GetByIdAsync(_fixture.Create()); + + // Assert + result.Result.Should().BeOfType(); + } + + [Fact] + public async Task GetProductsAsync_ShouldReturnProducts() + { + // Arrange + var categoryId = _fixture.Create(); + var products = _fixture.CreateMany(10); + + _mockProductService.Setup(x => x.GetByCategoryAsync(categoryId)).ReturnsAsync(products); + + // Act + var result = await _controller.GetProductsAsync(categoryId); + var okResult = result.Result as OkObjectResult; + + // Assert + okResult.Should().NotBeNull(); + okResult!.StatusCode.Should().Be((int)HttpStatusCode.OK); + okResult!.Value.Should().BeAssignableTo>(); + okResult!.Value.Should().BeEquivalentTo(products); + } + + [Fact] + public async Task GetChildrenAsync_ShouldReturnCategories() + { + // Arrange + var parentCategoryId = _fixture.Create(); + var childrenCategories = _fixture.CreateMany(5); + + _mockCategoryService.Setup(x => x.GetAllByParentIdAsync(parentCategoryId)).ReturnsAsync(childrenCategories); + + // Act + var result = await _controller.GetChildrenAsync(parentCategoryId); + var okResult = result.Result as OkObjectResult; + + // Assert + okResult.Should().NotBeNull(); + okResult!.StatusCode.Should().Be((int)HttpStatusCode.OK); + okResult!.Value.Should().BeAssignableTo>(); + okResult!.Value.Should().BeEquivalentTo(childrenCategories); + } + + [Fact] + public async Task CreateAsync_ShouldReturnCreatedCategory() + { + // Arrange + var categoryToReturn = _fixture.Create(); + var categoryToCreate = _fixture.Create(); + + _mockCategoryService.Setup(x => x.CreateAsync(categoryToCreate)).ReturnsAsync(categoryToReturn); + + // Act + var result = await _controller.CreateAsync(categoryToCreate); + var okResult = result.Result as OkObjectResult; + + // Assert + okResult.Should().NotBeNull(); + okResult!.StatusCode.Should().Be((int)HttpStatusCode.OK); + okResult!.Value.Should().BeAssignableTo(); + okResult!.Value.Should().BeEquivalentTo(categoryToReturn); + } + + [Fact] + public async Task UpdateAsync_ShouldReturnBadRequest_WhenPassedInvalidRoutePath() + { + // Arrange + var categoryToUpdate = _fixture.Create(); + var routeId = categoryToUpdate.Id + _fixture.Create(); + + // Act + var result = await _controller.UpdateAsync(routeId, categoryToUpdate); + var badRequestResult = result.Result as BadRequestObjectResult; + + // Assert + badRequestResult.Should().NotBeNull(); + badRequestResult!.StatusCode.Should().Be((int)HttpStatusCode.BadRequest); + badRequestResult!.Value.Should().Be($"Route id: {routeId} does not match with category id: {categoryToUpdate.Id}."); + } + + [Fact] + public async Task UpdateAsync_SHouldReturnUpdatedCategory() + { + // Arrange + var categoryToUpdate = _fixture.Create(); + var categoryToReturn = _fixture.Create(); + + _mockCategoryService.Setup(x => x.UpdateAsync(categoryToUpdate)).ReturnsAsync(categoryToReturn); + + // Act + var result = await _controller.UpdateAsync(categoryToUpdate.Id, categoryToUpdate); + var okResult = result.Result as OkObjectResult; + + // Assert + okResult.Should().NotBeNull(); + okResult!.StatusCode.Should().Be((int)HttpStatusCode.OK); + okResult!.Value.Should().BeAssignableTo(); + okResult!.Value.Should().BeEquivalentTo(categoryToReturn); + } + + [Fact] + public async Task PatchAsync_ShouldReturnNotFound_WhenCategoryNotFound() + { + // Arrange + int id = _fixture.Create(); + ProductCategoryDto? dto = null; + + _mockCategoryService.Setup(x => x.GetByIdAsync(id)).ReturnsAsync(dto); + + // Act + var result = await _controller.PatchAsync(id, _mockPatchDocument.Object); + var notFoundResult = result as NotFoundObjectResult; + + // Assert + notFoundResult.Should().NotBeNull(); + notFoundResult!.Value.Should().Be($"Category with id: {id} does not exist."); + } + + [Fact] + public async Task PatchAsync_ShouldReturnBadRequest_WhenValidationFails() + { + // Arrange + int id = _fixture.Create(); + var categoryToUpdate = _fixture.Create(); + + _mockCategoryService.Setup(x => x.GetByIdAsync(id)).ReturnsAsync(categoryToUpdate); + _mockValidator.Setup(x => x.Validate(It.IsAny())) + .Returns(new ValidationResult(new List { new("Name", "Name is required.") })); + + // Act + var result = await _controller.PatchAsync(id, _mockPatchDocument.Object); + var badRequestResult = result as BadRequestObjectResult; + + // Assert + badRequestResult.Should().NotBeNull(); + badRequestResult!.Value.Should().BeOfType(); + + var errors = badRequestResult!.Value as SerializableError; + errors!.Should().ContainKey("Name"); + } + + [Fact] + public async Task PatchAsync_ShouldReturnNoContent_WhenPatchAppliedSuccessfully() + { + // Arrange + int id = _fixture.Create(); + var categoryToUpdate = _fixture.Create(); + + _mockCategoryService.Setup(x => x.GetByIdAsync(id)).ReturnsAsync(categoryToUpdate); + _mockValidator.Setup(x => x.Validate(It.IsAny())).Returns(new ValidationResult()); + + // Act + var result = await _controller.PatchAsync(id, _mockPatchDocument.Object); + var noContentResult = result as NoContentResult; + + // Assert + noContentResult.Should().NotBeNull(); + noContentResult!.StatusCode.Should().Be((int)HttpStatusCode.NoContent); + } + + [Fact] + public async Task DeleteAsync_ShoudlReturnNoContent() + { + // Assert + var categoryId = _fixture.Create(); + + // Act + var result = await _controller.DeleteAsync(categoryId); + var noContent = result as NoContentResult; + + // Assert + noContent.Should().NotBeNull(); + noContent!.StatusCode.Should().Be((int)HttpStatusCode.NoContent); + } + + [Fact] + public void GetOptions_ShouldReturnOkResult() + { + // Arrange + var expectedHeaderValues = "GET,HEAD,POST,OPTIONS"; + + // Act + var result = _controller.GetOptions(); + var okResult = result as OkResult; + var actualHeaderValue = _response.Headers["Allow"].FirstOrDefault(); + + // Assert + okResult.Should().NotBeNull(); + okResult!.StatusCode.Should().Be((int)HttpStatusCode.OK); + + actualHeaderValue.Should().BeEquivalentTo(expectedHeaderValues); + } +} \ No newline at end of file diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Domain/PaginatedListFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Domain/PaginatedListFixture.cs new file mode 100644 index 0000000..8e2aba3 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Domain/PaginatedListFixture.cs @@ -0,0 +1,179 @@ +namespace ReverseAnalytics.Tests.Unit.Domain; + +public class PaginatedListFixture +{ + [Fact] + public void Constructor_ShouldThrowArgumentNullExceptionWhenItemsNull() + { + // Arrange + List? items = null; + int currentPage = 1; + int pageSize = 10; + int totalCount = 20; + + // Act & Assert + var exception = Assert.Throws(() => new PaginatedList(items!, currentPage, pageSize, totalCount)); + exception.ParamName.Should().Be(nameof(items)); + } + + [Theory] + [InlineData(-1)] + [InlineData(-5)] + public void Constructor_ShouldThrowArgumentExceptionWhenTotalCountIsNegative(int totalCount) + { + // Arrange + List items = [1, 2, 3]; + int currentPage = 1; + int pageSize = 10; + + // Act & Assert + var exception = Assert.Throws(() => new PaginatedList(items!, currentPage, pageSize, totalCount)); + exception.ParamName.Should().Be(nameof(totalCount)); + + exception.Message.Should().Be("Total count cannot be negative. (Parameter 'totalCount')"); + } + + [Theory] + [InlineData(0)] + [InlineData(-1)] + public void Constructor_ShouldThrowArgumentException_WhenCurrentPageIsLessThan1(int currentPage) + { + // Arrange + var items = new List(); + int pageSize = 10; + int totalCount = 20; + + // Act & Assert + var exception = Assert.Throws(() => new PaginatedList(items, currentPage, pageSize, totalCount)); + exception.ParamName.Should().Be(nameof(currentPage)); + exception.Message.Should().Be("Current page must be greater than 0. (Parameter 'currentPage')"); + } + + [Theory] + [InlineData(0)] + [InlineData(-1)] + public void Constructor_ShouldThrowArgumentException_WhenPageSizeIsLessThan1(int pageSize) + { + // Arrange + var items = new List(); + int currentPage = 1; + int totalCount = 20; + + // Act & Assert + var exception = Assert.Throws(() => new PaginatedList(items, currentPage, pageSize, totalCount)); + exception.ParamName.Should().Be(nameof(pageSize)); + exception.Message.Should().Be("Page size must be greater than 0. (Parameter 'pageSize')"); + } + + [Theory] + [InlineData(3, 2)] + [InlineData(5, 1)] + public void Constructor_ShouldThrowArgumentException_WhenTotalCountIsLessThanItemsCount(int itemsCount, int totalCount) + { + // Arrange + var fixture = new Fixture(); + var items = fixture.CreateMany(itemsCount).ToList(); + int currentPage = 1; + int pageSize = 10; + + // Act & Assert + Assert.Throws(() => new PaginatedList(items, currentPage, pageSize, totalCount)); + } + + [Fact] + public void Constructor_ShouldCalculatePagesCountCorrectly_WhenTotalCountIs0() + { + // Arrange + var items = new List(); + int currentPage = 1; + int pageSize = 10; + int totalCount = 0; // 0 total items + + // Act + var paginatedList = new PaginatedList(items, currentPage, pageSize, totalCount); + + // Assert + paginatedList.PagesCount.Should().Be(0); + } + + [Fact] + public void Constructor_ShouldInitializePropertiesCorrectly() + { + // Arrange + var items = new List { 1, 2, 3 }; + int currentPage = 1; + int pageSize = 10; + int totalCount = 20; + + // Act + var paginatedList = new PaginatedList(items, currentPage, pageSize, totalCount); + + // Assert + paginatedList.CurrentPage.Should().Be(currentPage); + paginatedList.PageSize.Should().Be(pageSize); + paginatedList.TotalCount.Should().Be(totalCount); + paginatedList.PagesCount.Should().Be(2); // 20 total items, 10 items per page + paginatedList.Should().BeEquivalentTo(items); + } + + [Theory] + [InlineData(4, 1, 10, 20, true)] + [InlineData(5, 2, 10, 20, false)] + public void HasNext_ShouldReturnExpectedResult(int itemsCount, int currentPage, int pageSize, int totalCount, bool expectedResult) + { + // Arrange + var fixture = new Fixture(); + var items = fixture.CreateMany(itemsCount).ToList(); + var paginatedList = new PaginatedList(items, currentPage, pageSize, totalCount); + + // Act & Assert + paginatedList.HasNext.Should().Be(expectedResult); + } + + [Theory] + [InlineData(4, 2, 10, 20, true)] + [InlineData(5, 1, 10, 20, false)] + public void HasPrevious_ShouldReturnExpectedResult(int itemsCount, int currentPage, int pageSize, int totalCount, bool expectedResult) + { + // Arrange + var fixture = new Fixture(); + var items = fixture.CreateMany(itemsCount).ToList(); + var paginatedList = new PaginatedList(items, currentPage, pageSize, totalCount); + + // Act & Assert + paginatedList.HasPrevious.Should().Be(expectedResult); + } + + [Fact] + public void Constructor_ShouldAddElementsToList() + { + // Arrange + var fixture = new Fixture(); + var items = fixture.CreateMany(5).ToList(); + + // Act + var paginatedList = new PaginatedList(items, 1, 10, 20); + + // Assert + paginatedList.Should().BeEquivalentTo(items); + } + + [Fact] + public void ToMetaData_ShouldReturnCorrectPaginationMetaData() + { + // Arrange + var items = new List { 1, 2, 3 }; + var paginatedList = new PaginatedList(items, 1, 10, 20); + + // Act + var metaData = paginatedList.MetaData; + + // Assert + metaData.TotalCount.Should().Be(20); + metaData.PageSize.Should().Be(10); + metaData.CurrentPage.Should().Be(1); + metaData.PagesCount.Should().Be(2); + metaData.HasNext.Should().BeTrue(); + metaData.HasPrevious.Should().BeFalse(); + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/FixtureBase.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/FixtureBase.cs new file mode 100644 index 0000000..12257cf --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/FixtureBase.cs @@ -0,0 +1,20 @@ +namespace ReverseAnalytics.Tests.Unit; + +public abstract class FixtureBase +{ + protected readonly Fixture _fixture; + + protected FixtureBase() + { + _fixture = CreateFixture(); + } + + private static Fixture CreateFixture() + { + var fixture = new Fixture(); + fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); + fixture.Behaviors.Add(new NullRecursionBehavior()); + + return fixture; + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/ReverseAnalytics.Tests.Unit.csproj b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/ReverseAnalytics.Tests.Unit.csproj new file mode 100644 index 0000000..88e61eb --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/ReverseAnalytics.Tests.Unit.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Services/ProductCategoryServiceFixture.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Services/ProductCategoryServiceFixture.cs new file mode 100644 index 0000000..58ddfd0 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Services/ProductCategoryServiceFixture.cs @@ -0,0 +1,252 @@ +namespace ReverseAnalytics.Tests.Unit.Services; + +public class ProductCategoryServiceFixture : ServiceFixtureBase +{ + protected readonly ProductCategoryService _productCategoryService; + + public ProductCategoryServiceFixture() + : base() + { + _productCategoryService = new ProductCategoryService(_mockRepository.Object, _mockMapper.Object); + _fixture.Register(() => new PaginatedList( + _fixture.CreateMany(5).ToList(), + _fixture.Create(), _fixture.Create(), + _fixture.Create())); + } + + [Fact] + public async Task GetAllAsync_ShouldReturnAllProductCategories() + { + // Arrange + var categories = _fixture.CreateMany(5); + _mockRepository.Setup(r => r.ProductCategory.FindAllAsync()).ReturnsAsync(categories); + + var categoryDtos = _fixture.CreateMany(5); + _mockMapper.Setup(m => m.Map>(categories)).Returns(categoryDtos); + + // Act + var result = await _productCategoryService.GetAllAsync(); + + // Assert + _mockRepository.Verify(x => x.ProductCategory.FindAllAsync(), Times.Once, "Repository was not called."); + _mockMapper.Verify(x => x.Map>(categories), Times.Once, "Automapper was not called."); + categoryDtos.Should().BeEquivalentTo(result); + } + + [Fact] + public async Task GetAllAsync_ShouldReturnHandleEmptyResult() + { + // Arrange + var categories = new List(); + _mockRepository.Setup(r => r.ProductCategory.FindAllAsync()).ReturnsAsync(categories); + + var categoryDtos = new List(); + _mockMapper.Setup(m => m.Map>(categories)).Returns(categoryDtos); + + // Act + var result = await _productCategoryService.GetAllAsync(); + + // Assert + _mockRepository.Verify(x => x.ProductCategory.FindAllAsync(), Times.Once, "Repository was not called."); + _mockMapper.Verify(x => x.Map>(categories), Times.Once, "Automapper was not called."); + result.Should().BeEmpty(); + } + + [Fact] + public async Task GetAllAsync_ShouldRethrowRepositoryException() + { + // Arrange + _mockRepository.Setup(r => r.ProductCategory.FindAllAsync()).ThrowsAsync(new Exception("Database exception.")); + + // Act & Assert + await Assert.ThrowsAsync(() => _productCategoryService.GetAllAsync()); + } + + [Fact] + public async Task GetAllAsync_ShouldRethrowMappingException() + { + // Arrange + var categories = new List(); + _mockRepository.Setup(r => r.ProductCategory.FindAllAsync()).ReturnsAsync(categories); + + _mockMapper.Setup(m => m.Map>(categories)).Throws(new Exception("Mapping failed.")); + + // Act & Assert + await Assert.ThrowsAsync(() => _productCategoryService.GetAllAsync()); + } + + [Fact] + public async Task GetAllAsync_ShouldThrowArgumentNullException_WhenPassedNull() + { + ProductCategoryQueryParameters? request = default; + + await Assert.ThrowsAsync(async () => await _productCategoryService.GetAllAsync(request!)); + } + + [Fact] + public async Task GetAllAsync_ShouldReturnPaginatedListWithPaginationMetaData() + { + // Arrange + var request = _fixture.Create(); + var paginatedCategories = _fixture.Create>(); + var metadata = paginatedCategories.MetaData; + var categoryDtos = _fixture.CreateMany(5); + + _mockRepository.Setup(x => x.ProductCategory.FindAllAsync(request)).ReturnsAsync(paginatedCategories); + _mockMapper.Setup(x => x.Map>(paginatedCategories)).Returns(categoryDtos); + + // Act + var result = await _productCategoryService.GetAllAsync(request); + + // Assert + _mockRepository.Verify(x => x.ProductCategory.FindAllAsync(request), Times.Once); + _mockMapper.Verify(x => x.Map>(paginatedCategories), Times.Once); + + result.Data.Should().BeEquivalentTo(categoryDtos); + result.PaginationMetaData.Should().BeEquivalentTo(metadata); + } + + [Fact] + public async Task GetAllByParentIdAsync_ShouldReturnAllMatchingCategories() + { + // Arrange + var categories = _fixture.CreateMany(5).ToList(); + var categoryDtos = _fixture.CreateMany(5).ToList(); + var parentId = _fixture.Create(); + + _mockRepository.Setup(x => x.ProductCategory.FindByParentIdAsync(parentId)).ReturnsAsync(categories); + _mockMapper.Setup(x => x.Map>(categories)).Returns(categoryDtos); + + // Act + var result = await _productCategoryService.GetAllByParentIdAsync(parentId); + + // Assert + result.Should().BeEquivalentTo(categoryDtos); + _mockRepository.Verify(x => x.ProductCategory.FindByParentIdAsync(parentId), Times.Once); + _mockMapper.Verify(x => x.Map>(categories), Times.Once); + } + + [Fact] + public async Task GetAllByParentIdAsync_ShouldReturnEmptyResult_WhenNoMatchingFound() + { + List categories = []; + List categoryDtos = []; + var parentId = _fixture.Create(); + + _mockRepository.Setup(x => x.ProductCategory.FindByParentIdAsync(parentId)).ReturnsAsync(categories); + _mockMapper.Setup(x => x.Map>(categories)).Returns(categoryDtos); + + // Act + var result = await _productCategoryService.GetAllByParentIdAsync(parentId); + + // Assert + result.Should().BeEquivalentTo(categoryDtos); + _mockRepository.Verify(x => x.ProductCategory.FindByParentIdAsync(parentId), Times.Once); + _mockMapper.Verify(x => x.Map>(categories), Times.Once); + } + + [Fact] + public async Task GetByIdAsync_ShouldThrowNotFoundException_WhenCategoryIsNotFound() + { + // Arrange + var categoryId = _fixture.Create(); + + // Act + _mockRepository.Setup(x => x.ProductCategory.FindByIdAsync(categoryId)).ThrowsAsync(new EntityNotFoundException()); + + // Assert + await Assert.ThrowsAsync(() => _productCategoryService.GetByIdAsync(categoryId)); + } + + [Fact] + public async Task GetById_ShouldReturnMatchingCategory() + { + // Arrange + var categoryId = _fixture.Create(); + var category = _fixture.Build().With(x => x.Id, categoryId).Create(); + var categoryDto = _fixture.Create(); + + _mockRepository.Setup(x => x.ProductCategory.FindByIdAsync(categoryId)).ReturnsAsync(category); + _mockMapper.Setup(x => x.Map(category)).Returns(categoryDto); + + // Act + var result = await _productCategoryService.GetByIdAsync(categoryId); + + // Assert + result.Should().BeEquivalentTo(categoryDto); + } + + [Fact] + public async Task CreateAsync_ShouldThrowArgumenNullException_WhenPassedNull() + { + // Arrange + ProductCategoryForCreateDto? request = null; + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => _productCategoryService.CreateAsync(request!)); + exception.ParamName.Should().Be("categoryToCreate"); + } + + [Fact] + public async Task CreateAsync_ShouldReturnCreatedRecord() + { + // Arrange + var request = _fixture.Create(); + var category = _fixture.Create(); + var categoryDto = _fixture.Create(); + + _mockMapper.Setup(x => x.Map(request)).Returns(category); + _mockRepository.Setup(x => x.ProductCategory.CreateAsync(category)).ReturnsAsync(category); + _mockMapper.Setup(x => x.Map(category)).Returns(categoryDto); + + // Act + var result = await _productCategoryService.CreateAsync(request); + + // Assert + result.Should().BeEquivalentTo(categoryDto); + } + + [Fact] + public async Task UpdateAsync_ShouldThrowArgumentNullException_WhenPassedNull() + { + // Arrange + ProductCategoryForUpdateDto? request = null; + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => _productCategoryService.UpdateAsync(request!)); + exception.ParamName.Should().Be("categoryToUpdate"); + } + + [Fact] + public async Task UpdateAsync_ShouldReturnUpdatedRecord() + { + // Arrange + var request = _fixture.Create(); + var category = _fixture.Create(); + var categoryDto = _fixture.Create(); + + _mockMapper.Setup(x => x.Map(request)).Returns(category); + _mockRepository.Setup(x => x.ProductCategory.UpdateAsync(category)).ReturnsAsync(category); + _mockMapper.Setup(x => x.Map(category)).Returns(categoryDto); + + // Act + var result = await _productCategoryService.UpdateAsync(request); + + // Assert + result.Should().BeEquivalentTo(categoryDto); + } + + [Fact] + public async Task DeleteAsync_ShouldCallRepositoryOnce() + { + // Arrange + var categoryId = _fixture.Create(); + _mockRepository.Setup(x => x.ProductCategory.DeleteAsync(categoryId)); + + // Act + await _productCategoryService.DeleteAsync(categoryId); + + // Assert + _mockRepository.Verify(x => x.ProductCategory.DeleteAsync(categoryId), Times.Once); + } +} \ No newline at end of file diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Services/ServiceFixtureBase.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Services/ServiceFixtureBase.cs new file mode 100644 index 0000000..026908b --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Services/ServiceFixtureBase.cs @@ -0,0 +1,16 @@ +using AutoMapper; +using Moq; +using ReverseAnalytics.Domain.Interfaces.Repositories; + +namespace ReverseAnalytics.Tests.Unit.Services; +public abstract class ServiceFixtureBase : FixtureBase +{ + protected readonly Mock _mockRepository; + protected readonly Mock _mockMapper; + + protected ServiceFixtureBase() + { + _mockRepository = new Mock(); + _mockMapper = new Mock(); + } +} diff --git a/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Usings.cs b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Usings.cs new file mode 100644 index 0000000..a116483 --- /dev/null +++ b/Reverse-Analytics/Tests/ReverseAnalytics.Tests.Unit/Usings.cs @@ -0,0 +1,25 @@ +global using AutoFixture; +global using AutoMapper; +global using FluentAssertions; +global using FluentValidation; +global using Moq; +global using NetArchTest.Rules; +global using Newtonsoft.Json; + +global using Microsoft.EntityFrameworkCore; +global using Microsoft.AspNetCore.Http; +global using Microsoft.AspNetCore.Mvc; +global using System.Reflection; +global using System.Net; + +global using ReverseAnalytics.Domain.Common; +global using ReverseAnalytics.Domain.Entities; +global using ReverseAnalytics.Domain.DTOs.ProductCategory; +global using ReverseAnalytics.Domain.Exceptions; +global using ReverseAnalytics.Domain.QueryParameters; +global using ReverseAnalytics.Domain.Interfaces.Services; +global using ReverseAnalytics.Infrastructure.Persistence; +global using ReverseAnalytics.Infrastructure.Repositories; +global using ReverseAnalytics.Services; +global using Reverse_Analytics.Api.Controllers; +global using ReverseAnalytics.Tests.Unit.Constants; \ No newline at end of file