diff --git a/MyOffice.Data.Repositories/Account/AccountRepository.cs b/MyOffice.Data.Repositories/Account/AccountRepository.cs index ad6c931..7dbd16f 100644 --- a/MyOffice.Data.Repositories/Account/AccountRepository.cs +++ b/MyOffice.Data.Repositories/Account/AccountRepository.cs @@ -103,7 +103,7 @@ public class AccountRepository : AppRepository, IAccountRepository { return _context.Accounts .Where(x => x.AccessRights!.Any(a => a.UserId == userId)) - .Where(x => x.Name.Contains(term)) + .Where(x => x.Name.ToLower().Contains(term.ToLower())) .ToList(); } diff --git a/MyOffice.Data.Repositories/Item/ItemRepository.cs b/MyOffice.Data.Repositories/Item/ItemRepository.cs index 3f1fe27..f3a268f 100644 --- a/MyOffice.Data.Repositories/Item/ItemRepository.cs +++ b/MyOffice.Data.Repositories/Item/ItemRepository.cs @@ -49,7 +49,7 @@ public class ItemRepository : AppRepository, IItemRepository return _context .Items .Include(x => x.ItemGlobal) - .Where(x => x.Category!.UserId == userId && x.ItemGlobal.Name.Contains(term)) + .Where(x => x.Category!.UserId == userId && x.ItemGlobal.Name.ToLower().Contains(term.ToLower())) .OrderByDescending(x => x!.Motions!.Count()) .Take(limit) .ToList(); diff --git a/MyOffice.DbContext/AppDbContext.cs b/MyOffice.DbContext/AppDbContext.cs index a6bc5b0..3ba5af7 100644 --- a/MyOffice.DbContext/AppDbContext.cs +++ b/MyOffice.DbContext/AppDbContext.cs @@ -71,6 +71,14 @@ public class AppDbContext : DbContext .Property(x => x.Email) .UseCollation(noCaseCollation); + /*modelBuilder.Entity() + .Property(x => x.Name) + .UseCollation(noCaseCollation);*/ + + /*modelBuilder.Entity() + .Property(x => x.Name) + .UseCollation(noCaseCollation);*/ + modelBuilder.Entity() .HasOne(x => x.User) diff --git a/MyOffice.Migration.Postgres/Migrations/20230725054028_Collation.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230725054028_Collation.Designer.cs new file mode 100644 index 0000000..b92d8a3 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230725054028_Collation.Designer.cs @@ -0,0 +1,652 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyOffice.DbContext; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20230725054028_Collation")] + partial class Collation + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyGlobalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyGlobalId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("IsAllowManage") + .HasColumnType("boolean"); + + b.Property("IsAllowRead") + .HasColumnType("boolean"); + + b.Property("IsAllowWrite") + .HasColumnType("boolean"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("UserId"); + + b.ToTable("AccountAccesses"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CategoryId"); + + b.ToTable("AccountAccountCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccountCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("AmountMinus") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("AmountPlus") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ItemId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("ItemId"); + + b.HasIndex("UserId"); + + b.ToTable("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyGlobalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("CurrentRateId") + .HasColumnType("integer"); + + b.Property("IsPrimary") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortName") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyGlobalId"); + + b.HasIndex("CurrentRateId"); + + b.HasIndex("UserId"); + + b.ToTable("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("DefaultQuantity") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Symbol") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("CurrencyGlobals"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CurrencyId") + .HasColumnType("uuid"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Quantity") + .HasColumnType("integer"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyId"); + + b.ToTable("CurrencyRates"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("ItemGlobalId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("ItemGlobalId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsInternal") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.HasKey("Id"); + + b.ToTable("ItemGlobals"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("FullName") + .HasColumnType("text"); + + b.Property("IsEmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal") + .WithMany("Accounts") + .HasForeignKey("CurrencyGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId"); + + b.Navigation("CurrencyGlobal"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("AccessRights") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("AccountAccess") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("Categories") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category") + .WithMany("Accounts") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("AccountCategories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("Motions") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Items.Item", "Item") + .WithMany("Motions") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", null) + .WithMany("AccountMotions") + .HasForeignKey("UserId"); + + b.Navigation("Account"); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal") + .WithMany("Currencies") + .HasForeignKey("CurrencyGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate") + .WithMany("Currencies") + .HasForeignKey("CurrentRateId"); + + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("Currencies") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CurrencyGlobal"); + + b.Navigation("CurrentRate"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency") + .WithMany("Rates") + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Currency"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category") + .WithMany("Items") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal") + .WithMany("Items") + .HasForeignKey("ItemGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + + b.Navigation("ItemGlobal"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("ItemCategories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency") + .WithMany() + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Currency"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("UserClaims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.Navigation("AccessRights"); + + b.Navigation("Categories"); + + b.Navigation("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.Navigation("Accounts"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.Navigation("Rates"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b => + { + b.Navigation("Accounts"); + + b.Navigation("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.Navigation("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.Navigation("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.Navigation("AccountAccess"); + + b.Navigation("AccountCategories"); + + b.Navigation("AccountMotions"); + + b.Navigation("Accounts"); + + b.Navigation("Currencies"); + + b.Navigation("ItemCategories"); + + b.Navigation("UserClaims"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230725054028_Collation.cs b/MyOffice.Migration.Postgres/Migrations/20230725054028_Collation.cs new file mode 100644 index 0000000..7b07646 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230725054028_Collation.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class Collation : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "ItemGlobals", + type: "text", + nullable: false, + collation: "my_ci_collation", + oldClrType: typeof(string), + oldType: "text"); + + migrationBuilder.AlterColumn( + name: "Name", + table: "Accounts", + type: "text", + nullable: false, + collation: "my_ci_collation", + oldClrType: typeof(string), + oldType: "text"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "ItemGlobals", + type: "text", + nullable: false, + oldClrType: typeof(string), + oldType: "text", + oldCollation: "my_ci_collation"); + + migrationBuilder.AlterColumn( + name: "Name", + table: "Accounts", + type: "text", + nullable: false, + oldClrType: typeof(string), + oldType: "text", + oldCollation: "my_ci_collation"); + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230725061203_CollationR.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230725061203_CollationR.Designer.cs new file mode 100644 index 0000000..5bbd3dd --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230725061203_CollationR.Designer.cs @@ -0,0 +1,651 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyOffice.DbContext; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20230725061203_CollationR")] + partial class CollationR + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyGlobalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyGlobalId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("IsAllowManage") + .HasColumnType("boolean"); + + b.Property("IsAllowRead") + .HasColumnType("boolean"); + + b.Property("IsAllowWrite") + .HasColumnType("boolean"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("UserId"); + + b.ToTable("AccountAccesses"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CategoryId"); + + b.ToTable("AccountAccountCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccountCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("AmountMinus") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("AmountPlus") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ItemId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("ItemId"); + + b.HasIndex("UserId"); + + b.ToTable("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyGlobalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("CurrentRateId") + .HasColumnType("integer"); + + b.Property("IsPrimary") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortName") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyGlobalId"); + + b.HasIndex("CurrentRateId"); + + b.HasIndex("UserId"); + + b.ToTable("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("DefaultQuantity") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Symbol") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("CurrencyGlobals"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CurrencyId") + .HasColumnType("uuid"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Quantity") + .HasColumnType("integer"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyId"); + + b.ToTable("CurrencyRates"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("ItemGlobalId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("ItemGlobalId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsInternal") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.HasKey("Id"); + + b.ToTable("ItemGlobals"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("FullName") + .HasColumnType("text"); + + b.Property("IsEmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal") + .WithMany("Accounts") + .HasForeignKey("CurrencyGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId"); + + b.Navigation("CurrencyGlobal"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("AccessRights") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("AccountAccess") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("Categories") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category") + .WithMany("Accounts") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("AccountCategories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("Motions") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Items.Item", "Item") + .WithMany("Motions") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", null) + .WithMany("AccountMotions") + .HasForeignKey("UserId"); + + b.Navigation("Account"); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal") + .WithMany("Currencies") + .HasForeignKey("CurrencyGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate") + .WithMany("Currencies") + .HasForeignKey("CurrentRateId"); + + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("Currencies") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CurrencyGlobal"); + + b.Navigation("CurrentRate"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency") + .WithMany("Rates") + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Currency"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category") + .WithMany("Items") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal") + .WithMany("Items") + .HasForeignKey("ItemGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + + b.Navigation("ItemGlobal"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("ItemCategories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency") + .WithMany() + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Currency"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("UserClaims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.Navigation("AccessRights"); + + b.Navigation("Categories"); + + b.Navigation("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.Navigation("Accounts"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.Navigation("Rates"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b => + { + b.Navigation("Accounts"); + + b.Navigation("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.Navigation("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.Navigation("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.Navigation("AccountAccess"); + + b.Navigation("AccountCategories"); + + b.Navigation("AccountMotions"); + + b.Navigation("Accounts"); + + b.Navigation("Currencies"); + + b.Navigation("ItemCategories"); + + b.Navigation("UserClaims"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230725061203_CollationR.cs b/MyOffice.Migration.Postgres/Migrations/20230725061203_CollationR.cs new file mode 100644 index 0000000..ce688f3 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230725061203_CollationR.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class CollationR : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "Accounts", + type: "text", + nullable: false, + oldClrType: typeof(string), + oldType: "text", + oldCollation: "my_ci_collation"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "Accounts", + type: "text", + nullable: false, + collation: "my_ci_collation", + oldClrType: typeof(string), + oldType: "text"); + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230725061910_CollationR2.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230725061910_CollationR2.Designer.cs new file mode 100644 index 0000000..f45afe7 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230725061910_CollationR2.Designer.cs @@ -0,0 +1,650 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using MyOffice.DbContext; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20230725061910_CollationR2")] + partial class CollationR2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "7.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyGlobalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyGlobalId"); + + b.HasIndex("OwnerId"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("IsAllowManage") + .HasColumnType("boolean"); + + b.Property("IsAllowRead") + .HasColumnType("boolean"); + + b.Property("IsAllowWrite") + .HasColumnType("boolean"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("UserId"); + + b.ToTable("AccountAccesses"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("CategoryId"); + + b.ToTable("AccountAccountCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AccountCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AccountId") + .HasColumnType("uuid"); + + b.Property("AmountMinus") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("AmountPlus") + .HasPrecision(18, 6) + .HasColumnType("numeric(18,6)"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("ItemId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.HasIndex("ItemId"); + + b.HasIndex("UserId"); + + b.ToTable("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyGlobalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("CurrentRateId") + .HasColumnType("integer"); + + b.Property("IsPrimary") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortName") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyGlobalId"); + + b.HasIndex("CurrentRateId"); + + b.HasIndex("UserId"); + + b.ToTable("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("DefaultQuantity") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Symbol") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("CurrencyGlobals"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CurrencyId") + .HasColumnType("uuid"); + + b.Property("DateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Quantity") + .HasColumnType("integer"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyId"); + + b.ToTable("CurrencyRates"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CategoryId") + .HasColumnType("uuid"); + + b.Property("ItemGlobalId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("CategoryId"); + + b.HasIndex("ItemGlobalId"); + + b.ToTable("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("IsInternal") + .HasColumnType("boolean"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("ItemCategories"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("ItemGlobals"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CurrencyId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("FirstName") + .HasColumnType("text"); + + b.Property("FullName") + .HasColumnType("text"); + + b.Property("IsEmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LastName") + .HasColumnType("text"); + + b.Property("PasswordHash") + .IsRequired() + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("UserName") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Provider") + .IsRequired() + .HasColumnType("text") + .UseCollation("my_ci_collation"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaims"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal") + .WithMany("Accounts") + .HasForeignKey("CurrencyGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", "Owner") + .WithMany("Accounts") + .HasForeignKey("OwnerId"); + + b.Navigation("CurrencyGlobal"); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("AccessRights") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("AccountAccess") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("Categories") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category") + .WithMany("Accounts") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + + b.Navigation("Category"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("AccountCategories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b => + { + b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") + .WithMany("Motions") + .HasForeignKey("AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Items.Item", "Item") + .WithMany("Motions") + .HasForeignKey("ItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Users.User", null) + .WithMany("AccountMotions") + .HasForeignKey("UserId"); + + b.Navigation("Account"); + + b.Navigation("Item"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal") + .WithMany("Currencies") + .HasForeignKey("CurrencyGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate") + .WithMany("Currencies") + .HasForeignKey("CurrentRateId"); + + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("Currencies") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CurrencyGlobal"); + + b.Navigation("CurrentRate"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency") + .WithMany("Rates") + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Currency"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category") + .WithMany("Items") + .HasForeignKey("CategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal") + .WithMany("Items") + .HasForeignKey("ItemGlobalId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Category"); + + b.Navigation("ItemGlobal"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("ItemCategories") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency") + .WithMany() + .HasForeignKey("CurrencyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Currency"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b => + { + b.HasOne("MyOffice.Data.Models.Users.User", "User") + .WithMany("UserClaims") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b => + { + b.Navigation("AccessRights"); + + b.Navigation("Categories"); + + b.Navigation("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b => + { + b.Navigation("Accounts"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b => + { + b.Navigation("Rates"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b => + { + b.Navigation("Accounts"); + + b.Navigation("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b => + { + b.Navigation("Currencies"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b => + { + b.Navigation("Motions"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b => + { + b.Navigation("Items"); + }); + + modelBuilder.Entity("MyOffice.Data.Models.Users.User", b => + { + b.Navigation("AccountAccess"); + + b.Navigation("AccountCategories"); + + b.Navigation("AccountMotions"); + + b.Navigation("Accounts"); + + b.Navigation("Currencies"); + + b.Navigation("ItemCategories"); + + b.Navigation("UserClaims"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230725061910_CollationR2.cs b/MyOffice.Migration.Postgres/Migrations/20230725061910_CollationR2.cs new file mode 100644 index 0000000..d544478 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230725061910_CollationR2.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class CollationR2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "ItemGlobals", + type: "text", + nullable: false, + oldClrType: typeof(string), + oldType: "text", + oldCollation: "my_ci_collation"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "Name", + table: "ItemGlobals", + type: "text", + nullable: false, + collation: "my_ci_collation", + oldClrType: typeof(string), + oldType: "text"); + } + } +} diff --git a/MyOffice.SPA/src/app/layout/sidebar/sidebar-items.ts b/MyOffice.SPA/src/app/layout/sidebar/sidebar-items.ts index da1eeb3..f74bfb0 100644 --- a/MyOffice.SPA/src/app/layout/sidebar/sidebar-items.ts +++ b/MyOffice.SPA/src/app/layout/sidebar/sidebar-items.ts @@ -95,7 +95,7 @@ export const ROUTES: RouteInfo[] = [ }, { path: '/settings/item-categories', - title: '', + title: 'MENUITEMS.SETTINGS.LIST.ITEMCATEGORIES', iconType: '', icon: '', class: 'ml-menu', diff --git a/MyOffice.SPA/src/app/model/motion.model.ts b/MyOffice.SPA/src/app/model/motion.model.ts index 2190b2a..40a82d5 100644 --- a/MyOffice.SPA/src/app/model/motion.model.ts +++ b/MyOffice.SPA/src/app/model/motion.model.ts @@ -3,6 +3,9 @@ export interface MotionModel { date?: Date; item?: string; description?: string; + itemId?: string; + accountId?: string; plus?: number; minus?: number; + amountBalancing?: number; } diff --git a/MyOffice.SPA/src/app/pages/accounts/account.component.ts b/MyOffice.SPA/src/app/pages/accounts/account.component.ts index 82cc197..27bcb34 100644 --- a/MyOffice.SPA/src/app/pages/accounts/account.component.ts +++ b/MyOffice.SPA/src/app/pages/accounts/account.component.ts @@ -11,6 +11,7 @@ import { EventEmitter } from '@angular/core'; // libs import * as moment from 'moment'; +import { Observable } from 'rxjs'; // app import { ApiRoutes } from '../../api-routes'; @@ -28,8 +29,9 @@ export class AccountComponent { public form!: UntypedFormGroup; @Input('account') account!: AccountDetailedModel; @Input('active') active: boolean = false; + @Input() reloadEvent!: Observable; - @Output() onUpdate: EventEmitter = new EventEmitter(); + @Output() onUpdate: EventEmitter = new EventEmitter(); constructor( private fb: UntypedFormBuilder, @@ -55,13 +57,21 @@ export class AccountComponent { ], }); this.loadMotions(); + + this.reloadEvent.subscribe(x => { + if (x.find(x => x === this.account.account.id)) { + this.loadMotions(); + } + }); } onSubmitClick() { } - handlerOnAdd(motion: MotionModel) { + handlerOnAdd(motions: MotionModel[]) { + this.onUpdate?.emit(motions.filter(x => x.accountId !== this.account.account!.id)); this.loadMotions(); + this.httpClient .get(ApiRoutes.Account.replace(':id', this.account.account!.id!)) .subscribe(data => { @@ -93,6 +103,10 @@ export class AccountComponent { refresh += window.location.host; refresh += window.location.pathname; refresh += window.location.hash; + var idx = refresh.indexOf('/account/'); + if (idx > -1) { + refresh = refresh.substr(0, idx); + } refresh += '/account/' + this.account.account.id; window.history.pushState({ path: refresh }, '', refresh); } diff --git a/MyOffice.SPA/src/app/pages/accounts/account.list.component.html b/MyOffice.SPA/src/app/pages/accounts/account.list.component.html index 0f4121a..8af7ec9 100644 --- a/MyOffice.SPA/src/app/pages/accounts/account.list.component.html +++ b/MyOffice.SPA/src/app/pages/accounts/account.list.component.html @@ -8,8 +8,11 @@
-
- +
+
diff --git a/MyOffice.SPA/src/app/pages/accounts/account.list.component.ts b/MyOffice.SPA/src/app/pages/accounts/account.list.component.ts index dc9f581..b655b62 100644 --- a/MyOffice.SPA/src/app/pages/accounts/account.list.component.ts +++ b/MyOffice.SPA/src/app/pages/accounts/account.list.component.ts @@ -4,11 +4,13 @@ import { HttpClient } from '@angular/common/http'; import { ActivatedRoute } from '@angular/router'; // libs +import { Subject } from 'rxjs'; // app import { AccountCategoryService } from '../../services/account.category.service'; import { ApiRoutes } from '../../api-routes'; import { AccountDetailedModel } from '../../model/account.detailed.model'; +import { MotionModel } from '../../model/motion.model'; @Component({ templateUrl: './account.list.component.html', @@ -19,6 +21,8 @@ export class AccountListComponent { public category = ''; public activeAccount = ''; + reloadSubject: Subject = new Subject(); + constructor( private httpClient: HttpClient, private activatedRoute: ActivatedRoute, @@ -43,4 +47,8 @@ export class AccountListComponent { }); }); } + + handlerOnUpdate(motions: MotionModel[]) { + this.reloadSubject.next(motions.map(x => x.accountId!)); + } } diff --git a/MyOffice.SPA/src/app/pages/accounts/motion.component.html b/MyOffice.SPA/src/app/pages/accounts/motion.component.html index 09a8bd0..91e378b 100644 --- a/MyOffice.SPA/src/app/pages/accounts/motion.component.html +++ b/MyOffice.SPA/src/app/pages/accounts/motion.component.html @@ -27,7 +27,7 @@ Motion !! - + Please enter motion @@ -38,7 +38,7 @@ - +
diff --git a/MyOffice.SPA/src/app/pages/accounts/motion.component.scss b/MyOffice.SPA/src/app/pages/accounts/motion.component.scss index e69de29..47f7e12 100644 --- a/MyOffice.SPA/src/app/pages/accounts/motion.component.scss +++ b/MyOffice.SPA/src/app/pages/accounts/motion.component.scss @@ -0,0 +1,3 @@ +.mat-mdc-option.mdc-list-item.mat-mdc-option-active { + filter: brightness(50%) +} diff --git a/MyOffice.SPA/src/app/pages/accounts/motion.component.ts b/MyOffice.SPA/src/app/pages/accounts/motion.component.ts index ebc6cb7..3850fee 100644 --- a/MyOffice.SPA/src/app/pages/accounts/motion.component.ts +++ b/MyOffice.SPA/src/app/pages/accounts/motion.component.ts @@ -42,7 +42,7 @@ export class MotionComponent { @Input('motion') motion!: MotionModel; @Input('account') account!: AccountModel; - @Output() onAdd: EventEmitter = new EventEmitter(); + @Output() onAdd: EventEmitter = new EventEmitter(); @Output() onDelete: EventEmitter = new EventEmitter(); @ViewChild('motionInput') motionInput?: ElementRef; @@ -93,6 +93,15 @@ export class MotionComponent { this.filteredItems = x; }); }); + + this.form.valueChanges.subscribe(val => { + this.form.controls['plus'].markAsPristine(); + this.form.controls['plus'].markAsUntouched(); + this.form.controls['plus'].setErrors(null); + this.form.controls['minus'].markAsPristine(); + this.form.controls['minus'].markAsUntouched(); + this.form.controls['minus'].setErrors(null); + }); } displayFn(item: any): string { @@ -107,24 +116,36 @@ export class MotionComponent { add() { this.form.markAllAsTouched(); + if (this.form.hasError('atLeastOne')) { + this.form.get('plus')!.setErrors(this.form.errors); + this.form.get('minus')!.setErrors(this.form.errors); + return; + } + if (!this.form.valid) { - if (this.form.hasError('atLeastOne')) { - this.form.get('plus')!.setErrors(this.form.errors); - this.form.get('minus')!.setErrors(this.form.errors); - } return; } this.setInProgress(); - var data = this.form.value; - data.motion = data.item.name - ? data.item.name - : data.item; - data.itemId = this.selectedItem?.id; + var data: MotionModel = { + description: this.form.value.description, + plus: this.form.value.plus || 0, + minus: this.form.value.minus || 0, + }; + + if (this.form.value.item.name) { + data.date = this.form.value.date; + data.item = this.form.value.item.name; + data.itemId = this.form.value.item.id; + data.accountId = this.form.value.item.accountId; + data.amountBalancing = data.plus! > 0 ? data.plus : data.minus; + } else { + data.item = this.form.value.item; + } this.httpClient - .post(ApiRoutes.Motions.replace(':id', this.account.id!), data) + .post(ApiRoutes.Motions.replace(':id', this.account.id!), data) .subscribe(response => { this.onAdd?.emit(response); diff --git a/MyOffice.Services/Account/AccountService.cs b/MyOffice.Services/Account/AccountService.cs index fe61037..9e5ff54 100644 --- a/MyOffice.Services/Account/AccountService.cs +++ b/MyOffice.Services/Account/AccountService.cs @@ -332,7 +332,7 @@ return result.Set(categories); } - public Exec MotionAdd( + public Exec, MotionAddResult> MotionAdd( Guid userId, Guid accountId, MotionAddUpdate motion @@ -343,7 +343,7 @@ if (motion.Item == null) throw new ArgumentNullException(nameof(motion.Item)); - var result = new Exec(MotionAddResult.success); + var result = new Exec, MotionAddResult>(MotionAddResult.success); var account = _accountRepository.Get(userId, accountId); if (account == null) @@ -364,20 +364,55 @@ DateTime = motion.Date, AccountId = account.Id, ItemId = itemExec.Result!.Id, + Description = motion.Description, AmountPlus = motion.Plus, AmountMinus = motion.Minus, - Description = motion.Description, }; if (!_motionRepository.Add(motionDb)) { return result.Set(MotionAddResult.failure); + } + result.Set(new List()); + result.Result!.Add(motionDb); + + if (motion.AccountId.IsPresent() && motion.AmountBalancing != 0) + { + var accountBalancing = _accountRepository.Get(userId, motion.AccountId!.AsGuid()); + if (accountBalancing != null) + { + var balancingName = $"+{account.Name}"; + var itemBalancingExec = _itemService.GetOrCreate(userId, balancingName); + var plus = motion.AmountBalancing; + var minus = 0m; + if (motion.Plus != 0) + { + plus = 0; + minus = motion.AmountBalancing; + } + var motionBalancing = new Motion + { + Id = Guid.NewGuid(), + CreatedOn = DateTime.UtcNow, + DateTime = motion.Date, + AccountId = accountBalancing.Id, + ItemId = itemBalancingExec.Result!.Id, + Description = motion.Description, + AmountPlus = plus, + AmountMinus = minus, + }; + + if (_motionRepository.Add(motionBalancing)) + { + result.Result!.Add(motionBalancing); + } + } } motionDb.Item = itemExec.Result!; - return result.Set(motionDb); + return result; } public Exec MotionUpdate( diff --git a/MyOffice.Services/Account/AccountServiceProfile.cs b/MyOffice.Services/Account/AccountServiceProfile.cs new file mode 100644 index 0000000..cb8346c --- /dev/null +++ b/MyOffice.Services/Account/AccountServiceProfile.cs @@ -0,0 +1,30 @@ +using MyOffice.Services.Account.Domain; + +namespace MyOffice.Services.Account; + +using AutoMapper; +using Data.Models.Accounts; +using Data.Models.Users; + +public class AccountServiceProfile : Profile +{ + public AccountServiceProfile() + { + CreateMap(); + + CreateMap() + .ForMember(x => x.HasMotions, o => o.MapFrom(x => x.Motions.Any())) + ; + + CreateMap(); + + CreateMap(); + + CreateMap(); + + CreateMap() + .ForMember(x => x.Id, o => o.MapFrom(x => x.Id)) + .ForMember(x => x.Id, o => o.MapFrom(x => x.Id)) + ; + } +} \ No newline at end of file diff --git a/MyOffice.Services/Account/Domain/AccountAccessDto.cs b/MyOffice.Services/Account/Domain/AccountAccessDto.cs new file mode 100644 index 0000000..0d96ee1 --- /dev/null +++ b/MyOffice.Services/Account/Domain/AccountAccessDto.cs @@ -0,0 +1,17 @@ +namespace MyOffice.Services.Account.Domain; + +using Data.Models.Accounts; +using Data.Models.Users; + +public class AccountAccessDto +{ + public Guid AccountId { get; set; } + public AccountDto? Account { get; set; } + public Guid UserId { get; set; } + public User? User { get; set; } + + public bool IsAllowRead { get; set; } + public bool IsAllowWrite { get; set; } + public bool IsAllowManage { get; set; } + public AccountAccessTypeEnum Type { get; set; } +} \ No newline at end of file diff --git a/MyOffice.Services/Account/Domain/AccountAccountCategoryDto.cs b/MyOffice.Services/Account/Domain/AccountAccountCategoryDto.cs new file mode 100644 index 0000000..0560f41 --- /dev/null +++ b/MyOffice.Services/Account/Domain/AccountAccountCategoryDto.cs @@ -0,0 +1,7 @@ +namespace MyOffice.Services.Account.Domain; + +public class AccountAccountCategoryDto +{ + public Guid CategoryId { get; set; } + public AccountCategoryDto? Category { get; set; } = null!; +} \ No newline at end of file diff --git a/MyOffice.Services/Account/Domain/AccountCategoryDto.cs b/MyOffice.Services/Account/Domain/AccountCategoryDto.cs new file mode 100644 index 0000000..46377ab --- /dev/null +++ b/MyOffice.Services/Account/Domain/AccountCategoryDto.cs @@ -0,0 +1,6 @@ +public class AccountCategoryDto +{ + public Guid Id { get; set; } + public Guid UserId { get; set; } + public string Name { get; set; } = null!; +} \ No newline at end of file diff --git a/MyOffice.Services/Account/Domain/AccountDto.cs b/MyOffice.Services/Account/Domain/AccountDto.cs index 3484006..43036da 100644 --- a/MyOffice.Services/Account/Domain/AccountDto.cs +++ b/MyOffice.Services/Account/Domain/AccountDto.cs @@ -1,13 +1,6 @@ -using MyOffice.Data.Models.Accounts; -using MyOffice.Data.Models.Users; -using MyOffice.Services.Account.Domain; - -namespace MyOffice.Services.Account.Domain +namespace MyOffice.Services.Account.Domain { - using AutoMapper; - using MyOffice.Data.Models.Accounts; using MyOffice.Data.Models.Currencies; - using MyOffice.Data.Models.Users; using System; public class AccountDto @@ -26,67 +19,4 @@ namespace MyOffice.Services.Account.Domain public List? AccessRights { get; set; } public List? Categories { get; set; } } - - public class AccountAccessDto - { - public Guid AccountId { get; set; } - public AccountDto? Account { get; set; } - public Guid UserId { get; set; } - public User? User { get; set; } - - public bool IsAllowRead { get; set; } - public bool IsAllowWrite { get; set; } - public bool IsAllowManage { get; set; } - public AccountAccessTypeEnum Type { get; set; } - } - - public class AccountAccountCategoryDto - { - public Guid CategoryId { get; set; } - public AccountCategoryDto? Category { get; set; } = null!; - } - - public class AccountMappingProfile : Profile - { - public AccountMappingProfile() - { - CreateMap(); - - CreateMap() - .ForMember(x => x.HasMotions, o => o.MapFrom(x => x.Motions.Any())) - ; - - CreateMap(); - - CreateMap(); - - CreateMap(); - - CreateMap() - .ForMember(x => x.Id, o => o.MapFrom(x => x.Id)) - .ForMember(x => x.Id, o => o.MapFrom(x => x.Id)) - ; - } - } - - public class UserDto - { - public Guid Id { get; set; } - public string UserName { get; set; } = null!; - public string Email { get; set; } = null!; - public string? FirstName { get; set; } - public string? LastName { get; set; } - public string? FullName { get; set; } - public string? Phone { get; set; } - - public string CurrencyId { get; set; } - public CurrencyGlobal? Currency { get; set; } - } -} - -public class AccountCategoryDto -{ - public Guid Id { get; set; } - public Guid UserId { get; set; } - public string Name { get; set; } = null!; } \ No newline at end of file diff --git a/MyOffice.Services/Account/Domain/MotionAddUpdate.cs b/MyOffice.Services/Account/Domain/MotionAddUpdate.cs index 1b1d85d..fe22da4 100644 --- a/MyOffice.Services/Account/Domain/MotionAddUpdate.cs +++ b/MyOffice.Services/Account/Domain/MotionAddUpdate.cs @@ -4,8 +4,11 @@ { public DateTime Date { get; set; } public string Item { get; set; } = null!; + public string? ItemId { get; set; } = null!; + public string? AccountId { get; set; } = null!; public string? Description { get; set; } public decimal Plus { get; set; } public decimal Minus { get; set; } + public decimal AmountBalancing { get; set; } } } diff --git a/MyOffice.Services/Account/Domain/UserDto.cs b/MyOffice.Services/Account/Domain/UserDto.cs new file mode 100644 index 0000000..5e92d59 --- /dev/null +++ b/MyOffice.Services/Account/Domain/UserDto.cs @@ -0,0 +1,17 @@ +namespace MyOffice.Services.Account.Domain; + +using Data.Models.Currencies; + +public class UserDto +{ + public Guid Id { get; set; } + public string UserName { get; set; } = null!; + public string Email { get; set; } = null!; + public string? FirstName { get; set; } + public string? LastName { get; set; } + public string? FullName { get; set; } + public string? Phone { get; set; } + + public string CurrencyId { get; set; } + public CurrencyGlobal? Currency { get; set; } +} \ No newline at end of file diff --git a/MyOffice.Web/Controllers/AccountController.cs b/MyOffice.Web/Controllers/AccountController.cs index 995eaac..9ff9279 100644 --- a/MyOffice.Web/Controllers/AccountController.cs +++ b/MyOffice.Web/Controllers/AccountController.cs @@ -3,6 +3,7 @@ namespace MyOffice.Web.Controllers; using AutoMapper; using Core; using Core.Extensions; +using Data.Models.Accounts; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -76,7 +77,8 @@ public class AccountController : BaseApiController return ProblemBadRequest("Account not found."); case GeneralExecStatus.success: - return exec.Result!.Select(x => x.ToModel()); + //return exec.Result!.Select(x => x.ToModel()); + return _mapper.Map(exec.Result!); default: throw new NotSupportedException(exec.Status.ToString()); @@ -86,7 +88,7 @@ public class AccountController : BaseApiController [HttpPost("~/api/accounts/{id}/motions")] public object MotionsPost(string id, MotionRequest motion) { - var exec = _accountService.MotionAdd(UserId, id.AsGuid(), motion.FromModel()); + var exec = _accountService.MotionAdd(UserId, id.AsGuid(), _mapper.Map(motion)); switch (exec.Status) { @@ -95,7 +97,7 @@ public class AccountController : BaseApiController case MotionAddResult.failure: return ProblemBadRequest("Adding motion failed."); case MotionAddResult.success: - return exec.Result!.ToModel(); + return _mapper.Map(exec.Result!); default: throw new NotSupportedException(exec.Status.ToString()); @@ -105,7 +107,7 @@ public class AccountController : BaseApiController [HttpPut("~/api/accounts/{id}/motions/{motionId}")] public object MotionsPut(string id, string motionId, MotionRequest motion) { - var exec = _accountService.MotionUpdate(UserId, id.AsGuid(), motionId.AsGuid(), motion.FromModel()); + var exec = _accountService.MotionUpdate(UserId, id.AsGuid(), motionId.AsGuid(), _mapper.Map(motion)); switch (exec.Status) { @@ -154,7 +156,7 @@ public class AccountController : BaseApiController foreach (var account in accounts) { var accountName = $"+{account.Name}"; - var item = items.FirstOrDefault(x => x.Name == accountName); + var item = items.FirstOrDefault(x => x.Name.IsPresent() && x.Name!.Length > 1 && x.Name.Substring(1) == accountName); if (item == null) { diff --git a/MyOffice.Web/Models/Motion/AccountControllerProfile.cs b/MyOffice.Web/Models/Motion/AccountControllerProfile.cs new file mode 100644 index 0000000..8508dad --- /dev/null +++ b/MyOffice.Web/Models/Motion/AccountControllerProfile.cs @@ -0,0 +1,20 @@ +namespace MyOffice.Web.Models.Motion; + +using AutoMapper; +using Data.Models.Accounts; +using Services.Account.Domain; + +public class AccountControllerProfile : Profile +{ + public AccountControllerProfile() + { + CreateMap(); + + CreateMap() + .ForMember(x => x.Date, o => o.MapFrom(x => x.DateTime)) + .ForMember(x => x.Item, o => o.MapFrom(x => x.Item.ItemGlobal.Name)) + .ForMember(x => x.Plus, o => o.MapFrom(x => x.AmountPlus)) + .ForMember(x => x.Minus, o => o.MapFrom(x => x.AmountMinus)) + ; + } +} \ No newline at end of file diff --git a/MyOffice.Web/Models/Motion/MotionRequest.cs b/MyOffice.Web/Models/Motion/MotionRequest.cs index 6a700a6..46753f9 100644 --- a/MyOffice.Web/Models/Motion/MotionRequest.cs +++ b/MyOffice.Web/Models/Motion/MotionRequest.cs @@ -1,27 +1,13 @@ namespace MyOffice.Web.Models.Motion; -using MyOffice.Services.Account.Domain; - public class MotionRequest { public DateTime Date { get; set; } public string Item { get; set; } = null!; + public string? ItemId { get; set; } = null!; + public string? AccountId { get; set; } = null!; public string? Description { get; set; } public decimal? Plus { get; set; } public decimal? Minus { get; set; } -} - -public static class MotionRequestExtension -{ - public static MotionAddUpdate FromModel(this MotionRequest input) - { - return new MotionAddUpdate - { - Date = input.Date, - Item = input.Item, - Minus = input.Minus ?? 0, - Plus = input.Plus ?? 0, - Description = input.Description, - }; - } -} + public decimal? AmountBalancing { get; set; } +} \ No newline at end of file diff --git a/MyOffice.Web/Models/Motion/MotionViewModel.cs b/MyOffice.Web/Models/Motion/MotionViewModel.cs index 0f78364..56cb6dd 100644 --- a/MyOffice.Web/Models/Motion/MotionViewModel.cs +++ b/MyOffice.Web/Models/Motion/MotionViewModel.cs @@ -7,6 +7,7 @@ { public string Id { get; set; } = null!; public DateTime Date { get; set; } + public string AccountId { get; set; } = null!; public string Item { get; set; } = null!; public string? Description { get; set; } public decimal Plus { get; set; } diff --git a/MyOffice.Web/Program.cs b/MyOffice.Web/Program.cs index ed9e54d..4aa7ab3 100644 --- a/MyOffice.Web/Program.cs +++ b/MyOffice.Web/Program.cs @@ -45,6 +45,13 @@ using MyOffice.Services.Dashboard; using Services.Account.Domain; using MyOffice.Services.Identity; using AutoMapper; +using Models.Motion; + +//TODO: Data.Model only Repository and Service, response <-> mapper <-> web <-> mapper <-> service <-> repository +//TODO: Project management +//TODO: Model names. Controller = xxxRequest/xxxResponse. Service xxxInput/xxxOutput. +//TODO: Validate string as Guid when id +//TODO: Logging public class Program { @@ -217,14 +224,12 @@ public class Program { builder.Services.AddSingleton(provider => new MapperConfiguration(cfg => { - cfg.AddProfile(new AccountMappingProfile()); + cfg.AddProfile(new AccountServiceProfile()); cfg.AddProfile(new ViewModelProfile()); cfg.AddProfile(new AccountViewModelProfile(provider.CreateScope().ServiceProvider.GetService()!)); - }).CreateMapper()); - //builder.Services.AddAutoMapper(typeof(AccountMappingProfile)); - //builder.Services.AddAutoMapper(typeof(AccountViewModelProfile)); - //builder.Services.AddAutoMapper(typeof(ViewModelProfile)); + cfg.AddProfile(new AccountControllerProfile()); + }).CreateMapper()); } private static void AddRepositories(WebApplicationBuilder builder)