diff --git a/MyOffice.Data.Models/Accounts/Account.cs b/MyOffice.Data.Models/Accounts/Account.cs index a8c3e28..700e96d 100644 --- a/MyOffice.Data.Models/Accounts/Account.cs +++ b/MyOffice.Data.Models/Accounts/Account.cs @@ -1,22 +1,16 @@ namespace MyOffice.Data.Models.Accounts; using Currencies; - -public enum AccountTypeEnum -{ - debit, - credit, - transit, - other, -} +using MyOffice.Data.Models.Users; public class Account { public Guid Id { get; set; } public string CurrencyGlobalId { get; set; } = null!; public CurrencyGlobal? CurrencyGlobal { get; set; } + public Guid? OwnerId { get; set; } + public User? Owner { get; set; } public string Name { get; set; } = null!; - public AccountTypeEnum Type { get; set; } public IEnumerable? AccessRights { get; set; } public IEnumerable? Motions { get; set; } public IEnumerable? Categories { get; set; } @@ -34,8 +28,9 @@ public struct AccountSimple { public Guid Id { get; set; } public string Name { get; set; } - public string? CurrencyName { get; set; } - public string? CurrencyShortName { get; set; } + public AccountAccessTypeEnum Type { get; set; } + public string CurrencyName { get; set; } + public string CurrencyShortName { get; set; } public decimal? CurrencyRate { get; set; } public int? CurrencyQuantity { get; set; } public decimal? TotalPlus { get; set; } diff --git a/MyOffice.Data.Models/Accounts/AccountAccess.cs b/MyOffice.Data.Models/Accounts/AccountAccess.cs index 9514ac3..4b4e305 100644 --- a/MyOffice.Data.Models/Accounts/AccountAccess.cs +++ b/MyOffice.Data.Models/Accounts/AccountAccess.cs @@ -2,6 +2,14 @@ using MyOffice.Data.Models.Users; +public enum AccountAccessTypeEnum +{ + balance, + credit, + external, + other, +} + public class AccountAccess { public int Id { get; set; } @@ -13,4 +21,5 @@ public class AccountAccess 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.Data.Models/Currencies/CurrencyGlobal.cs b/MyOffice.Data.Models/Currencies/CurrencyGlobal.cs index 87df8d9..78ea67e 100644 --- a/MyOffice.Data.Models/Currencies/CurrencyGlobal.cs +++ b/MyOffice.Data.Models/Currencies/CurrencyGlobal.cs @@ -2,6 +2,19 @@ using MyOffice.Data.Models.Accounts; +public enum CurrencyGlobalIdEnum +{ + UAH, + USD, + EUR, + GBP, + RUB, + BTC, + ETH, + TON, + OTHER, +} + public class CurrencyGlobal { public string Id { get; set; } = null!; diff --git a/MyOffice.Data.Models/Users/User.cs b/MyOffice.Data.Models/Users/User.cs index 24c39a6..7536438 100644 --- a/MyOffice.Data.Models/Users/User.cs +++ b/MyOffice.Data.Models/Users/User.cs @@ -29,4 +29,5 @@ public class User public IEnumerable? AccountMotions { get; set; } public IEnumerable? AccountCategories { get; set; } public IEnumerable? ItemCategories { get; set; } + public IEnumerable? Accounts { get; set; } } \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Account/AccountAccessRepository.cs b/MyOffice.Data.Repositories/Account/AccountAccessRepository.cs new file mode 100644 index 0000000..5c5424c --- /dev/null +++ b/MyOffice.Data.Repositories/Account/AccountAccessRepository.cs @@ -0,0 +1,13 @@ +namespace MyOffice.Data.Repositories.Account; + +using Models.Accounts; +using MyOffice.Data.Repositories; + +public class AccountAccessRepository : AppRepository, IAccountAccessRepository +{ + + public bool Update(AccountAccess accountAccess) + { + return UpdateBase(accountAccess) > 0; + } +} \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Account/AccountRepository.cs b/MyOffice.Data.Repositories/Account/AccountRepository.cs index 51ffb16..ad6c931 100644 --- a/MyOffice.Data.Repositories/Account/AccountRepository.cs +++ b/MyOffice.Data.Repositories/Account/AccountRepository.cs @@ -1,9 +1,7 @@ namespace MyOffice.Data.Repositories.Account; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Internal; using Models.Accounts; -using MyOffice.Data.Models.Currencies; using MyOffice.Data.Repositories; public class AccountRepository : AppRepository, IAccountRepository @@ -16,6 +14,7 @@ public class AccountRepository : AppRepository, IAccountRepository .ThenInclude(x => x.Category) .Include(x => x.AccessRights)! .ThenInclude(x => x.User) + .Include(x => x.Motions)! .Where(x => x.AccessRights!.Any(a => a.UserId == userId)) .ToList(); } @@ -28,6 +27,7 @@ public class AccountRepository : AppRepository, IAccountRepository .ThenInclude(x => x.Category) .Include(x => x.AccessRights)! .ThenInclude(x => x.User) + .Include(x => x.Motions)! .Where(x => x.Categories!.Any(c => c.CategoryId == categoryId) && x.AccessRights!.Any(a => a.UserId == userId)) .ToList(); } @@ -73,6 +73,11 @@ public class AccountRepository : AppRepository, IAccountRepository return AddBase(account) > 0; } + public bool Delete(Account account) + { + return RemoveBase(account) > 0; + } + public Account? Get(Guid userId, Guid id) { return _context.Accounts! @@ -80,6 +85,7 @@ public class AccountRepository : AppRepository, IAccountRepository .ThenInclude(x => x.Category) .Include(x => x.AccessRights)! .ThenInclude(x => x.User) + .Include(x => x.Motions)! .FirstOrDefault(x => x.Id == id && x.AccessRights!.Any(r => r.UserId == userId)); } @@ -141,27 +147,42 @@ public class AccountRepository : AppRepository, IAccountRepository public List GetRestAtDate(Guid userId, DateTime date) { - return _context.Accounts - .Include(x => x.CurrencyGlobal!) + return _context.AccountAccesses! + .Where(x => x.UserId == userId) + .Include(x => x.Account!) + .ThenInclude(x => x.CurrencyGlobal!) .ThenInclude(x => x.Currencies!) .ThenInclude(x => x.CurrentRate!) - .Where(x => x.AccessRights!.Any(u => u.UserId == userId)) - .Select(x => new { - Id = x.Id, - Name = x.Name, - Currency = x.CurrencyGlobal!.Currencies!.FirstOrDefault(x => x.UserId == userId), - Rest = x.Motions!.Sum(m => (m.AmountPlus - m.AmountMinus)) + .Include(x => x.Account) + .ThenInclude(x => x!.Motions) + .Select(x => new + { + Id = x.AccountId, + Name = x.Account!.Name, + Type = x.Type, + Currency = x.Account!.CurrencyGlobal!.Currencies!.FirstOrDefault(c => c.UserId == userId), + CurrentRate = x.Account!.CurrencyGlobal!.Currencies!.FirstOrDefault(c => c.UserId == userId)!.CurrentRate, + Plus = x.Account.Motions! + .Where(x => !x.DeletedOn.HasValue) + .Sum(m => m.AmountPlus), + Minus = x.Account.Motions! + .Where(x => !x.DeletedOn.HasValue) + .Sum(m => m.AmountMinus), }) .ToList() .Select(x => new AccountSimple { Id = x.Id, Name = x.Name, - Balance = x.Rest, - CurrencyName = x.Currency?.Name, - CurrencyShortName = x.Currency?.ShortName, - CurrencyRate = x.Currency?.CurrentRate?.Rate, - CurrencyQuantity = x.Currency?.CurrentRate?.Quantity, - }).ToList(); + Type = x.Type, + CurrencyName = x.Currency!.Name, + CurrencyShortName = x.Currency!.ShortName, + CurrencyRate = x.CurrentRate?.Rate, + CurrencyQuantity = x.CurrentRate?.Quantity, + TotalMinus = x.Minus, + TotalPlus = x.Plus, + Balance = x.Plus - x.Minus, + }) + .ToList(); } } \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Account/IAccountAccessRepository.cs b/MyOffice.Data.Repositories/Account/IAccountAccessRepository.cs new file mode 100644 index 0000000..627dbee --- /dev/null +++ b/MyOffice.Data.Repositories/Account/IAccountAccessRepository.cs @@ -0,0 +1,8 @@ +namespace MyOffice.Data.Repositories.Account; + +using Models.Accounts; + +public interface IAccountAccessRepository +{ + bool Update(AccountAccess accountAccess); +} \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Account/IAccountyRepository.cs b/MyOffice.Data.Repositories/Account/IAccountyRepository.cs index 8e0c2c5..1c8cf8c 100644 --- a/MyOffice.Data.Repositories/Account/IAccountyRepository.cs +++ b/MyOffice.Data.Repositories/Account/IAccountyRepository.cs @@ -9,6 +9,7 @@ public interface IAccountRepository List GetByCategoryDetailed(Guid userId, Guid categoryId); AccountDetailed? GetByIdDetailed(Guid userId, Guid id); bool Add(Account account); + bool Delete(Account account); Account? Get(Guid userId, Guid id); bool Update(Account account); bool Remove(Account account); diff --git a/MyOffice.Data.Repositories/Item/ItemRepository.cs b/MyOffice.Data.Repositories/Item/ItemRepository.cs index 4c981d1..3f1fe27 100644 --- a/MyOffice.Data.Repositories/Item/ItemRepository.cs +++ b/MyOffice.Data.Repositories/Item/ItemRepository.cs @@ -11,7 +11,7 @@ public class ItemRepository : AppRepository, IItemRepository .Include(x => x.Motions) .Include(x => x.Category) .Include(x => x.ItemGlobal) - .Where(x => x.Category.UserId == userId) + .Where(x => x.Category!.UserId == userId) .ToList(); } @@ -21,7 +21,7 @@ public class ItemRepository : AppRepository, IItemRepository .Include(x => x.Motions) .Include(x => x.Category) .Include(x => x.ItemGlobal) - .Where(x => x.Category.UserId == userId && x.CategoryId == categoryId) + .Where(x => x.Category!.UserId == userId && x.CategoryId == categoryId) .ToList(); } @@ -50,7 +50,7 @@ public class ItemRepository : AppRepository, IItemRepository .Items .Include(x => x.ItemGlobal) .Where(x => x.Category!.UserId == userId && x.ItemGlobal.Name.Contains(term)) - .OrderByDescending(x => x.Motions.Count()) + .OrderByDescending(x => x!.Motions!.Count()) .Take(limit) .ToList(); } diff --git a/MyOffice.Data.Repositories/RepositoryBase.cs b/MyOffice.Data.Repositories/RepositoryBase.cs index 2e6eff2..34ac212 100644 --- a/MyOffice.Data.Repositories/RepositoryBase.cs +++ b/MyOffice.Data.Repositories/RepositoryBase.cs @@ -44,6 +44,11 @@ public class RepositoryBase where TEntity : class return await _context.Set().FindAsync(id); } + protected TEntity? GetBase(Guid id) + { + return _context.Set().Find(id); + } + protected async Task AddBaseAsync(TEntity entity) { //await _context.Set().AddAsync(entity); diff --git a/MyOffice.Data.Repositories/Users/IUserRepository.cs b/MyOffice.Data.Repositories/Users/IUserRepository.cs index 1f8f6f1..c1865a2 100644 --- a/MyOffice.Data.Repositories/Users/IUserRepository.cs +++ b/MyOffice.Data.Repositories/Users/IUserRepository.cs @@ -5,6 +5,7 @@ using MyOffice.Data.Models.Users; public interface IUserRepository { Task GetUserAsync(Guid id); + User? GetUser(Guid id); Task GetByUserUserNameAsync(string userName); User? GetByUserUserName(string userName); diff --git a/MyOffice.Data.Repositories/Users/UserRepository.cs b/MyOffice.Data.Repositories/Users/UserRepository.cs index bfd3e45..da3d4ed 100644 --- a/MyOffice.Data.Repositories/Users/UserRepository.cs +++ b/MyOffice.Data.Repositories/Users/UserRepository.cs @@ -11,6 +11,11 @@ public class UserRepository : AppRepository, IUserRepository return await GetBaseAsync(id); } + public User? GetUser(Guid id) + { + return GetBase(id); + } + public async Task GetByUserUserNameAsync(string userName) { return await _context.Users.FirstOrDefaultAsync(x => x.UserName == userName); diff --git a/MyOffice.DbContext/AppDbContext.cs b/MyOffice.DbContext/AppDbContext.cs index f90fa64..092d417 100644 --- a/MyOffice.DbContext/AppDbContext.cs +++ b/MyOffice.DbContext/AppDbContext.cs @@ -5,6 +5,7 @@ using Data.Models.Currencies; using Data.Models.Items; using Microsoft.EntityFrameworkCore; using Data.Models.Users; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; public enum AppDbContextProvidersEnum { @@ -144,6 +145,11 @@ public class AppDbContext : DbContext .WithMany(x => x.Accounts) .HasForeignKey(x => x.CurrencyGlobalId); + modelBuilder.Entity() + .HasOne(x => x.Owner) + .WithMany(x => x.Accounts) + .HasForeignKey(x => x.OwnerId); + modelBuilder.Entity() .HasOne(x => x.Account) .WithMany(x => x.AccessRights) @@ -173,6 +179,11 @@ public class AppDbContext : DbContext .HasOne(x => x.Category) .WithMany(x => x.Accounts) .HasForeignKey(x => x.CategoryId); + + modelBuilder + .Entity() + .Property(d => d.Type) + .HasConversion(new EnumToStringConverter()); } private void MotionsCreating(ModelBuilder modelBuilder) diff --git a/MyOffice.DbContext/RepositoryInitializer.cs b/MyOffice.DbContext/RepositoryInitializer.cs index 96f962b..c212db2 100644 --- a/MyOffice.DbContext/RepositoryInitializer.cs +++ b/MyOffice.DbContext/RepositoryInitializer.cs @@ -32,15 +32,15 @@ public class RepositoryInitializer // CurrencyGlobals var predefinedCurrencyGlobals = new List() { - new() { Id = "UAH", DefaultQuantity = 1, Symbol = "₴", Name = "Ukrainian hryvnias" }, - new() { Id = "USD", DefaultQuantity = 1, Symbol = "$", Name = "US Dollar" }, - new() { Id = "EUR", DefaultQuantity = 1, Symbol = "€", Name = "Euros" }, - new() { Id = "GBP", DefaultQuantity = 1, Symbol = "£", Name = "British pounds sterling" }, - new() { Id = "RUB", DefaultQuantity = 10, Symbol = "₽", Name = "Russia Ruble" }, - new() { Id = "BTC", DefaultQuantity = 10, Symbol = "btc", Name = "Bitcoin" }, - new() { Id = "ETH", DefaultQuantity = 10, Symbol = "eth", Name = "Ethereum" }, - new() { Id = "TON", DefaultQuantity = 10, Symbol = "ton", Name = "TON" }, - new() { Id = "OTHER", DefaultQuantity = 1, Symbol = "", Name = "Other" }, + new() { Id = CurrencyGlobalIdEnum.UAH.ToString(), DefaultQuantity = 1, Symbol = "₴", Name = "Ukrainian hryvnias" }, + new() { Id = CurrencyGlobalIdEnum.USD.ToString(), DefaultQuantity = 1, Symbol = "$", Name = "US Dollar" }, + new() { Id = CurrencyGlobalIdEnum.EUR.ToString(), DefaultQuantity = 1, Symbol = "€", Name = "Euros" }, + new() { Id = CurrencyGlobalIdEnum.GBP.ToString(), DefaultQuantity = 1, Symbol = "£", Name = "British pounds sterling" }, + new() { Id = CurrencyGlobalIdEnum.RUB.ToString(), DefaultQuantity = 10, Symbol = "₽", Name = "Russia Ruble" }, + new() { Id = CurrencyGlobalIdEnum.BTC.ToString(), DefaultQuantity = 10, Symbol = "btc", Name = "Bitcoin" }, + new() { Id = CurrencyGlobalIdEnum.ETH.ToString(), DefaultQuantity = 10, Symbol = "eth", Name = "Ethereum" }, + new() { Id = CurrencyGlobalIdEnum.TON.ToString(), DefaultQuantity = 10, Symbol = "ton", Name = "TON" }, + new() { Id = CurrencyGlobalIdEnum.OTHER.ToString(), DefaultQuantity = 1, Symbol = "", Name = "Other" }, }; var currencyGlobals = dbContext.CurrencyGlobals.ToList(); diff --git a/MyOffice.Migration.Postgres/Migrations/20230721200424_AccountType.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230721200424_AccountType.Designer.cs new file mode 100644 index 0000000..af69953 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230721200424_AccountType.Designer.cs @@ -0,0 +1,636 @@ +// +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("20230721200424_AccountType")] + partial class AccountType + { + /// + 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("Type") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CurrencyGlobalId"); + + 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("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.Navigation("CurrencyGlobal"); + }); + + 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("Currencies"); + + b.Navigation("ItemCategories"); + + b.Navigation("UserClaims"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230721200424_AccountType.cs b/MyOffice.Migration.Postgres/Migrations/20230721200424_AccountType.cs new file mode 100644 index 0000000..c29a649 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230721200424_AccountType.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class AccountType : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Type", + table: "Accounts", + type: "integer", + nullable: false, + defaultValue: 0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Type", + table: "Accounts"); + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230722051335_AccountType2.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230722051335_AccountType2.Designer.cs new file mode 100644 index 0000000..2c92520 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230722051335_AccountType2.Designer.cs @@ -0,0 +1,637 @@ +// +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("20230722051335_AccountType2")] + partial class AccountType2 + { + /// + 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.HasKey("Id"); + + b.HasIndex("CurrencyGlobalId"); + + 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.Navigation("CurrencyGlobal"); + }); + + 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("Currencies"); + + b.Navigation("ItemCategories"); + + b.Navigation("UserClaims"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230722051335_AccountType2.cs b/MyOffice.Migration.Postgres/Migrations/20230722051335_AccountType2.cs new file mode 100644 index 0000000..09ff120 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230722051335_AccountType2.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class AccountType2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Type", + table: "AccountAccesses", + type: "text", + nullable: false, + defaultValue: ""); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Type", + table: "AccountAccesses"); + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230722052053_AccountOwner.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230722052053_AccountOwner.Designer.cs new file mode 100644 index 0000000..d81cbe5 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230722052053_AccountOwner.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("20230722052053_AccountOwner")] + partial class AccountOwner + { + /// + 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/20230722052053_AccountOwner.cs b/MyOffice.Migration.Postgres/Migrations/20230722052053_AccountOwner.cs new file mode 100644 index 0000000..277a90e --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230722052053_AccountOwner.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class AccountOwner : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "OwnerId", + table: "Accounts", + type: "uuid", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Accounts_OwnerId", + table: "Accounts", + column: "OwnerId"); + + migrationBuilder.AddForeignKey( + name: "FK_Accounts_Users_OwnerId", + table: "Accounts", + column: "OwnerId", + principalTable: "Users", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Accounts_Users_OwnerId", + table: "Accounts"); + + migrationBuilder.DropIndex( + name: "IX_Accounts_OwnerId", + table: "Accounts"); + + migrationBuilder.DropColumn( + name: "OwnerId", + table: "Accounts"); + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/AppDbContextModelSnapshot.cs b/MyOffice.Migration.Postgres/Migrations/AppDbContextModelSnapshot.cs index 2e03a1e..544aa65 100644 --- a/MyOffice.Migration.Postgres/Migrations/AppDbContextModelSnapshot.cs +++ b/MyOffice.Migration.Postgres/Migrations/AppDbContextModelSnapshot.cs @@ -37,10 +37,15 @@ namespace MyOffice.Migrations.Postgres.Migrations .IsRequired() .HasColumnType("text"); + b.Property("OwnerId") + .HasColumnType("uuid"); + b.HasKey("Id"); b.HasIndex("CurrencyGlobalId"); + b.HasIndex("OwnerId"); + b.ToTable("Accounts"); }); @@ -64,6 +69,10 @@ namespace MyOffice.Migrations.Postgres.Migrations b.Property("IsAllowWrite") .HasColumnType("boolean"); + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + b.Property("UserId") .HasColumnType("uuid"); @@ -401,7 +410,13 @@ namespace MyOffice.Migrations.Postgres.Migrations .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 => @@ -618,6 +633,8 @@ namespace MyOffice.Migrations.Postgres.Migrations b.Navigation("AccountMotions"); + b.Navigation("Accounts"); + b.Navigation("Currencies"); b.Navigation("ItemCategories"); diff --git a/MyOffice.SPA/src/app/core/core.module.ts b/MyOffice.SPA/src/app/core/core.module.ts index c1121af..af58986 100644 --- a/MyOffice.SPA/src/app/core/core.module.ts +++ b/MyOffice.SPA/src/app/core/core.module.ts @@ -23,6 +23,7 @@ import { AuthCodeFlowConfig, AuthModuleConfig } from '../config.oidc'; import { SubjectExtensions } from './extensions/general.extensions'; import { ExternalLoginConfig } from '../config.external-login'; import { AccountCategoryService } from '../services/account.category.service'; +import { AccountService } from '../services/account.service'; export function storageFactory(): OAuthStorage { return localStorage; @@ -49,6 +50,7 @@ export function storageFactory(): OAuthStorage { OidcHelperService, SubjectExtensions, AccountCategoryService, + AccountService, ], schemas: [ CUSTOM_ELEMENTS_SCHEMA diff --git a/MyOffice.SPA/src/app/core/service/language.service.ts b/MyOffice.SPA/src/app/core/service/language.service.ts index 20643b5..ecd5691 100644 --- a/MyOffice.SPA/src/app/core/service/language.service.ts +++ b/MyOffice.SPA/src/app/core/service/language.service.ts @@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core'; providedIn: 'root', }) export class LanguageService { - languages: string[] = ['en', 'es', 'de']; + languages: string[] = ['en', 'es', 'de', 'ua']; constructor(public translate: TranslateService) { let browserLang: string; @@ -16,7 +16,8 @@ export class LanguageService { } else { browserLang = translate.getBrowserLang() as string; } - translate.use(browserLang.match(/en|es|de/) ? browserLang : 'en'); + console.log(browserLang.match(/en|es|de|ua/)); + translate.use(browserLang.match(/en|es|de|ua/) ? browserLang : 'en'); } setLanguage(lang: string) { diff --git a/MyOffice.SPA/src/app/dashboard/dashboard.module.ts b/MyOffice.SPA/src/app/dashboard/dashboard.module.ts index 51a6ba8..e3b22fb 100644 --- a/MyOffice.SPA/src/app/dashboard/dashboard.module.ts +++ b/MyOffice.SPA/src/app/dashboard/dashboard.module.ts @@ -1,9 +1,9 @@ +// angular import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { DecimalPipe } from '@angular/common'; -import { DashboardRoutingModule } from './dashboard-routing.module'; -import { Dashboard1Component } from './dashboard1/dashboard1.component'; -import { Dashboard2Component } from './dashboard2/dashboard2.component'; +// libs import { NgScrollbarModule } from 'ngx-scrollbar'; import { NgChartsModule } from 'ng2-charts'; import { MatIconModule } from '@angular/material/icon'; @@ -14,6 +14,12 @@ import { DragDropModule } from '@angular/cdk/drag-drop'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatTooltipModule } from '@angular/material/tooltip'; import { NgApexchartsModule } from 'ng-apexcharts'; +import { TranslateModule } from '@ngx-translate/core'; + +// app +import { DashboardRoutingModule } from './dashboard-routing.module'; +import { Dashboard1Component } from './dashboard1/dashboard1.component'; +import { Dashboard2Component } from './dashboard2/dashboard2.component'; import { ComponentsModule } from 'src/app/shared/components/components.module'; import { SharedModule } from '../shared/shared.module'; @@ -34,7 +40,11 @@ import { SharedModule } from '../shared/shared.module'; MatProgressBarModule, ComponentsModule, SharedModule, + TranslateModule, ], + providers: [ + DecimalPipe, + ] }) export class DashboardModule { } diff --git a/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.html b/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.html index 163023c..bf00b57 100644 --- a/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.html +++ b/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.html @@ -2,7 +2,7 @@
- +
@@ -12,7 +12,7 @@
-
Balance
+
{{'BALANCE' | translate}}

{{dashboardModel?.balance | number: '0.2-2'}}

@@ -25,7 +25,7 @@
-
Debit balance
+
{{'DEBIT.BALANCE' | translate}}

{{dashboardModel?.balanceDebit | number: '0.2-2'}}

@@ -39,7 +39,7 @@
-
Credit balance
+
{{'CREDIT.BALANCE' | translate}}

{{dashboardModel?.balanceCredit | number: '0.2-2'}}

@@ -53,7 +53,7 @@
-

Current rest

+

{{'CURRENT.BALANCE' | translate}}

@@ -65,491 +65,32 @@
- +
- - - - + + + + - - - + + + - - - - - - - - - - -
India23+32%
{{item.name}}{{item.balance | number: '1.2'}} ({{item.currencyShortName}}){{item.balanceAtRate | number: '1.2'}}
USA32+12% {{'OTHER' | translate}}{{top10BalanceOther | number: '1.2'}}
Shrilanka12-12%
Australia32+3%
-
-
-
-
-
-
-
-
-
-

Notice Board

- - - - - - -
-
- -
-
-
- ... -
-
-
Airi Satou
-

Lorem ipsum dolor sit amet, id quo eruditi eloquentiam.

- 7 hours ago -
-
-
-
- ... -
-
-
Sarah Smith
-

Lorem ipsum dolor sit amet, id quo eruditi eloquentiam.

-

1 hour ago

-
-
-
-
- ... -
-
-
Cara Stevens
-

Lorem ipsum dolor sit amet, id quo eruditi eloquentiam.

-
Yesterday
-
-
-
-
- ... -
-
-
Ashton Cox
-

Lorem ipsum dolor sit amet, id quo eruditi eloquentiam.

-
Yesterday
-
-
-
-
- ... -
-
-
Mark Hay
-

Lorem ipsum dolor sit amet, id quo eruditi eloquentiam.

-

1 hour ago

-
-
-
-
- ... -
-
-
Jay Pandya
-

Lorem ipsum dolor sit amet, id quo eruditi eloquentiam.

-

3 hour ago

-
-
-
-
-
-
-
-
-
-
-

Project Status

- - - - - - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Project NameProgressDuration
Project A - 30% - - - 2 Months
Project B - 55% - - - 3 Months
Project C - 67% - - - 1 Months
Project D - 70% - - - 2 Months
Project E - 24% - - - 3 Months
Project F - 77% - - - 4 Months
Project G - 41% - - - 2 Months
Project H - 41% - - - 2 Months
-
-
-
-
-
-
-
-
-

Earning Source

- - - - - - -
-
-
-

$90,808

-
-
-
    -
  • -
    - envato.com - 17% -
    -
    -
    -
    -
    -
  • -
  • -
    - google.com - 27% -
    -
    -
    -
    -
    -
  • -
  • -
    - yahoo.com - 25% -
    -
    -
    -
    -
    -
  • -
  • -
    - store - 18% -
    -
    -
    -
    -
    -
  • -
  • -
    - Others - 13% -
    -
    -
    -
    -
    -
  • -
-
-
-
-
-
-
-
-
-
-

Recent Orders

- - - - - - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +
Order IDCustomer NameItemOrder DateQuantityPaymentStatusInvoiceDetails
ID7865 - Jens - Brincker - iPhone X22/05/20212Credit Card -
Paid
-
- - - -
ID9357 - Mark Harry - Pixel 212/06/20211COD -
Unpaid
-
- - - -
ID3987 - Anthony - Davie - OnePlus02/02/20215Debit Card -
Pending
-
- - - -
ID2483 - David Perry - Moto Z210/01/20212Credit Card -
Paid
-
- - - -
ID2986 - John Doe - Samsung F6220/05/20213Net Banking -
Unpaid
-
- - - -
ID1267 - Sarah Smith - iPhone 1210/07/20211COD -
Paid
-
- - - -
ID3398 - Cara Stevens - Moto Gs511/04/20212UPI Payment -
Pending
-
- - - -
ID9965 - Ashton Cox - Pixel 214/05/20214Credit Card -
Paid
-
- - - - {{'TOTAL' | translate}}{{top10BalanceTotal | number: '1.2'}}
diff --git a/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.ts b/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.ts index 6615bb9..99c8441 100644 --- a/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.ts +++ b/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.ts @@ -1,6 +1,9 @@ // angular -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; +import { OnInit } from '@angular/core'; +import { ViewChild } from '@angular/core'; import { HttpClient } from '@angular/common/http'; +import { DecimalPipe } from '@angular/common'; // libs import { @@ -19,10 +22,12 @@ import { ApexResponsive, ApexNonAxisChartSeries, } from 'ng-apexcharts'; +import { ChartComponent } from "ng-apexcharts"; // app import { ApiRoutes } from '../../api-routes'; import { DashboardModel } from '../../model/dashboard.model'; +import { DashboardRestModel } from '../../model/dashboard.model'; export type ChartOptions = { series: ApexAxisChartSeries; @@ -49,24 +54,48 @@ export type ChartOptions = { styleUrls: ['./dashboard2.component.scss'], }) export class Dashboard2Component implements OnInit { - lineChartOptions!: Partial; - pieChartOptions!: Partial; + + @ViewChild("chart") chart!: ChartComponent; + public pieChartOptions!: Partial; + top10Balance?: DashboardRestModel[]; + top10BalanceOther?: number; + top10BalanceTotal?: number; dashboardModel?: DashboardModel; // color: ["#3FA7DC", "#F6A025", "#9BC311"], - constructor(private httpClient: HttpClient) { - + constructor( + private httpClient: HttpClient, + private _decimalPipe: DecimalPipe + ) { + } ngOnInit() { - this.chart1(); - this.chart2(); - this.httpClient .get(ApiRoutes.Dashboard) .subscribe(data => { data.incomeChange = this.calcChanges(data.incomeLast, data.incomePrevious); data.outcomeChange = this.calcChanges(data.outcomeLast, data.outcomePrevious); + + var labels = []; + var series2: number[] = []; + for (var i = 0; i < data.balanceRests.length; i++) { + let item = data.balanceRests[i]; + labels.push(item.name); + series2.push(item.balanceAtRate); + } + + this.balanceChart(labels, series2); + + this.top10Balance = data.balanceRests + .filter(x => x.balanceAtRate > 0) + .sort(x => x.balanceAtRate) + .slice(0, 10); + + this.top10BalanceTotal = data.balanceRests.reduce((sum, current) => sum + current.balanceAtRate, 0); + this.top10BalanceOther = this.top10Balance.reduce((sum, current) => sum + current.balanceAtRate, 0); + this.top10BalanceOther = this.top10BalanceTotal - this.top10BalanceOther; + this.dashboardModel = data; }); } @@ -82,101 +111,41 @@ export class Dashboard2Component implements OnInit { return 0; } - private chart1() { - this.lineChartOptions = { - series: [ - { - name: 'Product 1', - data: [70, 200, 80, 180, 170, 105, 210], - }, - { - name: 'Product 2', - data: [80, 250, 30, 120, 260, 100, 180], - }, - { - name: 'Product 3', - data: [85, 130, 85, 225, 80, 190, 120], - }, - ], - chart: { - height: 350, - type: 'line', - foreColor: '#9aa0ac', - dropShadow: { - enabled: true, - color: '#000', - top: 18, - left: 7, - blur: 10, - opacity: 0.2, - }, - toolbar: { - show: false, - }, - }, - colors: ['#00E396', '#775DD0', '#FEB019'], - stroke: { - curve: 'smooth', - }, - grid: { - show: true, - borderColor: '#9aa0ac', - strokeDashArray: 1, - }, - markers: { - size: 3, - }, - xaxis: { - categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'], - title: { - text: 'Month', - }, - }, - yaxis: { - // opposite: true, - title: { - text: 'Sales', - }, - }, - legend: { - position: 'top', - horizontalAlign: 'right', - floating: true, - offsetY: -25, - offsetX: -5, - }, - tooltip: { - theme: 'dark', - marker: { - show: true, - }, - x: { - show: true, - }, - }, - }; - } + private balanceChart(labels: string[], series2: number[]) { + var self = this; - private chart2() { this.pieChartOptions = { - series2: [44, 55, 13, 43, 22], + labels: labels, + series2: series2, chart: { type: 'donut', - width: 225, + width: 600, + height: 600, }, legend: { - show: false, + show: true, }, dataLabels: { enabled: false, }, - labels: ['Science', 'Mathes', 'Economics', 'History', 'Music'], - responsive: [ - { - breakpoint: 480, - options: {}, + responsive: [{ + breakpoint: 480, + options: { + legend: { + position: 'bottom' + } }, - ], + }], + tooltip: { + x: { + show: false, + }, + y: { + formatter: function (value, series) { + return self._decimalPipe.transform(value, '1.2-2') || ""; + } + } + } }; } } diff --git a/MyOffice.SPA/src/app/layout/header/header.component.ts b/MyOffice.SPA/src/app/layout/header/header.component.ts index 43ef39b..df9abb3 100644 --- a/MyOffice.SPA/src/app/layout/header/header.component.ts +++ b/MyOffice.SPA/src/app/layout/header/header.component.ts @@ -67,6 +67,7 @@ export class HeaderComponent extends UnsubscribeOnDestroyAdapter implements OnIn { text: 'English', flag: 'assets/images/flags/us.jpg', lang: 'en' }, { text: 'Spanish', flag: 'assets/images/flags/spain.jpg', lang: 'es' }, { text: 'German', flag: 'assets/images/flags/germany.jpg', lang: 'de' }, + { text: 'Ukraine', flag: 'assets/images/flags/ukraine.png', lang: 'ua' }, ]; notifications: Notifications[] = [ { diff --git a/MyOffice.SPA/src/app/layout/sidebar/sidebar-items.ts b/MyOffice.SPA/src/app/layout/sidebar/sidebar-items.ts index 72ff57e..c35e390 100644 --- a/MyOffice.SPA/src/app/layout/sidebar/sidebar-items.ts +++ b/MyOffice.SPA/src/app/layout/sidebar/sidebar-items.ts @@ -22,20 +22,9 @@ export const ROUTES: RouteInfo[] = [ badge: '', badgeClass: '', submenu: [ - { - path: 'dashboard/dashboard1', - title: 'MENUITEMS.DASHBOARD.LIST.DASHBOARD1', - iconType: '', - icon: '', - class: 'ml-menu', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - }, { path: 'dashboard/dashboard2', - title: 'MENUITEMS.DASHBOARD.LIST.DASHBOARD2', + title: 'MENUITEMS.DASHBOARD.LIST.DASHBOARD1', iconType: '', icon: '', class: 'ml-menu', @@ -48,66 +37,10 @@ export const ROUTES: RouteInfo[] = [ }, // Common Modules - { - path: '', - title: 'Authentication', - iconType: 'feather', - icon: 'user-check', - class: 'menu-toggle', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [ - { - path: '/authentication/forgot-password', - title: 'Forgot Password', - iconType: '', - icon: '', - class: 'ml-menu', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - }, - { - path: '/authentication/locked', - title: 'Locked', - iconType: '', - icon: '', - class: 'ml-menu', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - }, - { - path: '/authentication/page404', - title: '404 - Not Found', - iconType: '', - icon: '', - class: 'ml-menu', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - }, - { - path: '/authentication/page500', - title: '500 - Server Error', - iconType: '', - icon: '', - class: 'ml-menu', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - }, - ], - }, { id: 'accounts', path: '', - title: 'Accounts', + title: 'MENUITEMS.ACCOUNTS.TEXT', iconType: 'feather', icon: 'chevrons-down', class: 'menu-toggle', @@ -115,79 +48,11 @@ export const ROUTES: RouteInfo[] = [ badge: '', badgeClass: '', submenu: [ - /*{ - path: '/multilevel/first1', - title: 'First', - iconType: '', - icon: '', - class: 'ml-menu', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - }, - { - path: '/', - title: 'Second', - iconType: '', - icon: '', - class: 'ml-sub-menu', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [ - { - path: '/multilevel/secondlevel/second1', - title: 'Second 1', - iconType: '', - icon: '', - class: 'ml-menu2', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - }, - { - path: '/', - title: 'Second 2', - iconType: '', - icon: '', - class: 'ml-sub-menu2', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [ - { - path: '/multilevel/thirdlevel/third1', - title: 'third 1', - iconType: '', - icon: '', - class: 'ml-menu3', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - }, - ], - }, - ], - }, - { - path: '/multilevel/first3', - title: 'Third', - iconType: '', - icon: '', - class: 'ml-menu', - groupTitle: false, - badge: '', - badgeClass: '', - submenu: [], - },*/ ], }, { path: '', - title: 'Settings', + title: 'MENUITEMS.SETTINGS.TEXT', iconType: 'feather', icon: 'settings', class: 'menu-toggle', @@ -197,7 +62,7 @@ export const ROUTES: RouteInfo[] = [ submenu: [ { path: '/settings/currencies', - title: 'Currencies', + title: 'MENUITEMS.SETTINGS.LIST.CURRENCIES', iconType: '', icon: '', class: 'ml-menu', @@ -208,7 +73,7 @@ export const ROUTES: RouteInfo[] = [ }, { path: '/settings/account-categories', - title: 'Account categories', + title: 'MENUITEMS.SETTINGS.LIST.ACCOUNTCATEGORIES', iconType: '', icon: '', class: 'ml-menu', @@ -219,7 +84,7 @@ export const ROUTES: RouteInfo[] = [ }, { path: '/settings/accounts', - title: 'Accounts', + title: 'MENUITEMS.SETTINGS.LIST.ACCOUNTS', iconType: '', icon: '', class: 'ml-menu', @@ -230,7 +95,7 @@ export const ROUTES: RouteInfo[] = [ }, { path: '/settings/item-categories', - title: 'Item categories', + title: '', iconType: '', icon: '', class: 'ml-menu', @@ -241,7 +106,7 @@ export const ROUTES: RouteInfo[] = [ }, { path: '/settings/items', - title: 'Items', + title: 'MENUITEMS.SETTINGS.LIST.ITEMS', iconType: '', icon: '', class: 'ml-menu', diff --git a/MyOffice.SPA/src/app/model/account.model.ts b/MyOffice.SPA/src/app/model/account.model.ts index c60bd8d..4631b7d 100644 --- a/MyOffice.SPA/src/app/model/account.model.ts +++ b/MyOffice.SPA/src/app/model/account.model.ts @@ -6,6 +6,8 @@ export interface AccountModel { name?: string, currencyId?: string, currencyName?: string, + type?: string, + allowDelete: boolean, categories?: AccountCategoryModel[], accessRights?: AccountAccessRightModel[], } diff --git a/MyOffice.SPA/src/app/model/dashboard.model.ts b/MyOffice.SPA/src/app/model/dashboard.model.ts index 6311c36..bb73130 100644 --- a/MyOffice.SPA/src/app/model/dashboard.model.ts +++ b/MyOffice.SPA/src/app/model/dashboard.model.ts @@ -5,7 +5,21 @@ export interface DashboardModel { outcomeLast: number; outcomePrevious: number; outcomeChange: number; + balance: number; balanceDebit: number; balanceCredit: number; + + balanceRests: DashboardRestModel[]; +} + +export interface DashboardRestModel { + id: string; + name: string; + currencyName: string; + currencyShortName: string; + balance: number; + currencyRate: number; + currencyQuantity: number; + balanceAtRate: number; } diff --git a/MyOffice.SPA/src/app/pages/settings/account/account.component.html b/MyOffice.SPA/src/app/pages/settings/account/account.component.html index 827c855..4207782 100644 --- a/MyOffice.SPA/src/app/pages/settings/account/account.component.html +++ b/MyOffice.SPA/src/app/pages/settings/account/account.component.html @@ -30,11 +30,12 @@ {{account.name}} {{account.currencyId}} + {{account.type}} - - @@ -48,11 +49,12 @@ {{account.name}} {{account.currencyId}} + {{account.type}} - - @@ -67,10 +69,10 @@ {{account.name}} {{account.currencyId}} - - diff --git a/MyOffice.SPA/src/app/pages/settings/account/account.component.ts b/MyOffice.SPA/src/app/pages/settings/account/account.component.ts index 5beea57..b558604 100644 --- a/MyOffice.SPA/src/app/pages/settings/account/account.component.ts +++ b/MyOffice.SPA/src/app/pages/settings/account/account.component.ts @@ -81,15 +81,15 @@ export class SettingsAccountComponent { }); } - public remove(category: AccountModel) { - /*Swal.fire({ - title: 'Remove account category ' + category.name, + public remove(account: AccountModel) { + Swal.fire({ + title: 'Remove account ' + account.name, showCancelButton: true, - confirmButtonText: 'Add', + confirmButtonText: 'Delete', showLoaderOnConfirm: true, preConfirm: (name) => { return new Promise((resolve, reject) => { - this.httpClient.delete(ApiRoutes.SettingsAccountCategory.replace(':id', category.id!)) + this.httpClient.delete(ApiRoutes.SettingsAccount.replace(':id', account.id!)) .subscribe(data => { resolve(data); }, error => { @@ -103,7 +103,7 @@ export class SettingsAccountComponent { }, allowOutsideClick: () => !Swal.isLoading(), }).then((result) => { - this.load(); - });*/ + this.loadAccounts(); + }); } } diff --git a/MyOffice.SPA/src/app/pages/settings/account/add.account.component.html b/MyOffice.SPA/src/app/pages/settings/account/add.account.component.html index da528b8..5b6981a 100644 --- a/MyOffice.SPA/src/app/pages/settings/account/add.account.component.html +++ b/MyOffice.SPA/src/app/pages/settings/account/add.account.component.html @@ -4,6 +4,22 @@
+ +
+
+
+ + Type + + + {{type.key}} ({{type.value}}) + + + +
+
+
+
diff --git a/MyOffice.SPA/src/app/pages/settings/account/add.account.component.ts b/MyOffice.SPA/src/app/pages/settings/account/add.account.component.ts index 723f53c..cd03e0a 100644 --- a/MyOffice.SPA/src/app/pages/settings/account/add.account.component.ts +++ b/MyOffice.SPA/src/app/pages/settings/account/add.account.component.ts @@ -19,6 +19,7 @@ import { CurrencyModel } from '../../../model/currency.model'; import { AccountCategoryService } from '../../../services/account.category.service'; import { AccountCategoryModel } from '../../../model/account.category.model'; import { AuthService } from '../../../core/service/auth.service'; +import { AccountService } from '../../../services/account.service'; @Component({ templateUrl: './add.account.component.html', @@ -30,6 +31,7 @@ export class SettingsAccountAddComponent { public currencies?: CurrencyModel[]; public categories?: AccountCategoryModel[]; public username: string; + public types = new Map(); constructor( private fb: UntypedFormBuilder, @@ -38,9 +40,11 @@ export class SettingsAccountAddComponent { private currencyService: CurrencyService, private accountCategoryService: AccountCategoryService, private authService: AuthService, + private accountService: AccountService, @Inject(MAT_DIALOG_DATA) public account: AccountModel ) { this.username = authService.currentUserValue.userName; + this.types = this.accountService.getTypes(); } ngOnInit(): void { @@ -60,6 +64,9 @@ export class SettingsAccountAddComponent { '', [Validators.required], ], + type: [ + this.account.type + ] }); this.currencyService diff --git a/MyOffice.SPA/src/app/pages/settings/account/edit.account.component.html b/MyOffice.SPA/src/app/pages/settings/account/edit.account.component.html index fc335a5..706b2f6 100644 --- a/MyOffice.SPA/src/app/pages/settings/account/edit.account.component.html +++ b/MyOffice.SPA/src/app/pages/settings/account/edit.account.component.html @@ -4,6 +4,22 @@
+ +
+
+
+ + Type + + + {{type.key}} ({{type.value}}) + + + +
+
+
+
@@ -26,7 +42,9 @@
+
+
@@ -42,20 +60,21 @@
- +
- - - - + + + +
{{category.name}} - -
{{category.name}} + +
+
@@ -70,20 +89,24 @@
- - +
+
+ - - + - -
{{accessRight.user.email}} + {{accessRight.user.email}}
+ + +
+
+
diff --git a/MyOffice.SPA/src/app/pages/settings/account/edit.account.component.ts b/MyOffice.SPA/src/app/pages/settings/account/edit.account.component.ts index 32b8416..040da43 100644 --- a/MyOffice.SPA/src/app/pages/settings/account/edit.account.component.ts +++ b/MyOffice.SPA/src/app/pages/settings/account/edit.account.component.ts @@ -19,6 +19,7 @@ import { CurrencyModel } from '../../../model/currency.model'; import { AccountCategoryService } from '../../../services/account.category.service'; import { AccountCategoryModel } from '../../../model/account.category.model'; import { AccountAccessRightModel } from '../../../model/account.accessRight.model'; +import { AccountService } from '../../../services/account.service'; @Component({ templateUrl: './edit.account.component.html', @@ -29,6 +30,7 @@ export class SettingsAccountEditComponent { public errorMessage?: string; public currencies?: CurrencyModel[]; public categories?: AccountCategoryModel[]; + public types = new Map(); constructor( private fb: UntypedFormBuilder, @@ -36,8 +38,10 @@ export class SettingsAccountEditComponent { private dialogRef: MatDialogRef, private currencyService: CurrencyService, private accountCategoryService: AccountCategoryService, + private accountService: AccountService, @Inject(MAT_DIALOG_DATA) public account: AccountModel ) { + this.types = this.accountService.getTypes(); } ngOnInit(): void { @@ -56,6 +60,9 @@ export class SettingsAccountEditComponent { categoryId: [ '', ], + type: [ + this.account.type, + ], }); this.currencyService diff --git a/MyOffice.SPA/src/app/services/account.service.ts b/MyOffice.SPA/src/app/services/account.service.ts new file mode 100644 index 0000000..06d4216 --- /dev/null +++ b/MyOffice.SPA/src/app/services/account.service.ts @@ -0,0 +1,28 @@ +// angular +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +// libs +import { Observable } from 'rxjs'; + +// app +import { ApiRoutes } from '../api-routes'; +import { AccountCategoryModel } from '../model/account.category.model'; + +@Injectable() +export class AccountService { + private types = new Map(); + + constructor( + private httpClient: HttpClient, + ) { + this.types.set('balance', 'Account with balance'); + this.types.set('credit', 'Account with loan funds'); + this.types.set('external', 'External account'); + this.types.set('other', 'Other account'); + } + + public getTypes(): Map { + return this.types; + } +} diff --git a/MyOffice.SPA/src/app/shared/components/breadcrumb/breadcrumb.component.html b/MyOffice.SPA/src/app/shared/components/breadcrumb/breadcrumb.component.html index 01d8897..805084e 100644 --- a/MyOffice.SPA/src/app/shared/components/breadcrumb/breadcrumb.component.html +++ b/MyOffice.SPA/src/app/shared/components/breadcrumb/breadcrumb.component.html @@ -2,7 +2,7 @@
@@ -12,8 +12,8 @@ - - + +
diff --git a/MyOffice.SPA/src/app/shared/components/components.module.ts b/MyOffice.SPA/src/app/shared/components/components.module.ts index 30ceb7e..deb4fae 100644 --- a/MyOffice.SPA/src/app/shared/components/components.module.ts +++ b/MyOffice.SPA/src/app/shared/components/components.module.ts @@ -1,12 +1,25 @@ +// angular import { NgModule } from '@angular/core'; + +// libs +import { TranslateModule } from '@ngx-translate/core'; import { FileUploadComponent } from './file-upload/file-upload.component'; import { BreadcrumbComponent } from './breadcrumb/breadcrumb.component'; import { SharedModule } from '../shared.module'; @NgModule({ - declarations: [FileUploadComponent, BreadcrumbComponent], - imports: [SharedModule], - exports: [FileUploadComponent, BreadcrumbComponent], + declarations: [ + FileUploadComponent, + BreadcrumbComponent + ], + imports: [ + SharedModule, + TranslateModule, + ], + exports: [ + FileUploadComponent, + BreadcrumbComponent + ], }) export class ComponentsModule { } diff --git a/MyOffice.SPA/src/assets/i18n/en.json b/MyOffice.SPA/src/assets/i18n/en.json index 6312a93..eea1e58 100644 --- a/MyOffice.SPA/src/assets/i18n/en.json +++ b/MyOffice.SPA/src/assets/i18n/en.json @@ -14,11 +14,23 @@ "DASHBOARD": { "TEXT": "Dashboard", "LIST": { - "DASHBOARD1": "Dashboard 1", - "DASHBOARD2": "Dashboard 2", - "DASHBOARD3": "Dashboard 3" + "DASHBOARD1": "Dashboard" } }, + "ACCOUNTS": { + "TEXT": "Accounts" + }, + "SETTINGS": { + "TEXT": "Settings", + "LIST": { + "CURRENCIES": "Currencies", + "ACCOUNTCATEGORIES": "Account categories", + "ACCOUNTS": "Accounts", + "ITEMCATEGORIES": "Item categories", + "ITEMS": "Items" + } + }, + "ADVANCE-TABLE": { "TEXT": "Advance Table" }, @@ -80,5 +92,13 @@ "NGX-DATATABLE": "NGX-Datatable" } } - } + }, + + "BALANCE": "Balance", + "DEBIT.BALANCE": "Debit balance", + "CREDIT.BALANCE": "Credit balance", + "CURRENT.BALANCE": "Current balance", + "HOME": "Home", + "OTHER": "Other", + "TOTAL": "Total" } diff --git a/MyOffice.SPA/src/assets/i18n/ua.json b/MyOffice.SPA/src/assets/i18n/ua.json new file mode 100644 index 0000000..bc656eb --- /dev/null +++ b/MyOffice.SPA/src/assets/i18n/ua.json @@ -0,0 +1,103 @@ +{ + "HEADER": { + "SEARCH": { + "TEXT": "Шукати.." + } + }, + "MENUITEMS": { + "USER": { + "POST": "Manager" + }, + "MAIN": { + "TEXT": "Головне" + }, + "DASHBOARD": { + "TEXT": "Панелі", + "LIST": { + "DASHBOARD1": "Панель" + } + }, + "ACCOUNTS": { + "TEXT": "Рахунки" + }, + "SETTINGS": { + "TEXT": "Налаштування", + "LIST": { + "CURRENCIES": "Валюти", + "ACCOUNTCATEGORIES": "Категорії рахунків", + "ACCOUNTS": "Рахунки", + "ITEMCATEGORIES": "Категорії статей", + "ITEMS": "Статті" + } + }, + + "ADVANCE-TABLE": { + "TEXT": "Advance Table" + }, + "APPS": { + "TEXT": "Apps" + }, + "CALENDAR": { + "TEXT": "Calendar" + }, + "TASK": { + "TEXT": "Task" + }, + "CONTACTS": { + "TEXT": "Contacts" + }, + "EMAIL": { + "TEXT": "Email", + "LIST": { + "INBOX": "Inbox", + "COMPOSE": "Compose", + "READ": "Read Email" + } + }, + "MORE-APPS": { + "TEXT": "More Apps", + "LIST": { + "CHAT": "Chat", + "SUPPORT": "Support", + "DRAG-DROP": "Drag & Drop", + "CONTACT-GRID": "Contact Grid" + } + }, + "COMPONENTS": { + "TEXT": "Components" + }, + "WIDGETS": { + "TEXT": "Widgets", + "LIST": { + "CHART-WIDGET": "Chart-Widget", + "DATA-WIDGET": "Data-Widget" + } + }, + "FORMS": { + "TEXT": "Forms", + "LIST": { + "CONTROLS": "Form Controls", + "ADVANCE": "Advance Control", + "EXAMPLE": "Form Examples", + "VALIDATION": "Form Validation", + "WIZARD": "Wizard", + "EDITORS": "Editors" + } + }, + "TABLES": { + "TEXT": "Tables", + "LIST": { + "BASIC": "Basic Tables", + "MATERIAL": "Material Tables", + "NGX-DATATABLE": "NGX-Datatable" + } + } + }, + "BALANCE": "Баланс", + "DEBIT.BALANCE": "Остаток", + "CREDIT.BALANCE": "Кредиты", + "CURRENT.BALANCE": "Поточний баланс", + "HOME": "Головна", + "OTHER": "Інші", + "TOTAL": "Всього" +} diff --git a/MyOffice.SPA/src/assets/images/flags/ukraine.png b/MyOffice.SPA/src/assets/images/flags/ukraine.png new file mode 100644 index 0000000..3479ad3 Binary files /dev/null and b/MyOffice.SPA/src/assets/images/flags/ukraine.png differ diff --git a/MyOffice.Services/Account/AccountService.cs b/MyOffice.Services/Account/AccountService.cs index a476f28..fe61037 100644 --- a/MyOffice.Services/Account/AccountService.cs +++ b/MyOffice.Services/Account/AccountService.cs @@ -1,5 +1,6 @@ namespace MyOffice.Services.Account { + using AutoMapper; using Core; using Core.Extensions; using Core.Helpers; @@ -16,7 +17,9 @@ public class AccountService { private ILogger _logger; + private readonly IMapper _mapper; private readonly IAccountCategoryRepository _accountCategoryRepository; + private readonly IAccountAccessRepository _accountAccessRepository; private readonly IAccountRepository _accountRepository; private readonly ICurrencyRepository _currencyRepository; private readonly IAccountAccountCategoryRepository _accountAccountCategoryRepository; @@ -27,7 +30,9 @@ public AccountService( ILogger logger, + IMapper mapper, IAccountCategoryRepository accountCategoryRepository, + IAccountAccessRepository accountAccessRepository, IAccountRepository accountRepository, ICurrencyRepository currencyRepository, IAccountAccountCategoryRepository accountAccountCategoryRepository, @@ -38,7 +43,9 @@ ) { _logger = logger; + _mapper = mapper; _accountCategoryRepository = accountCategoryRepository; + _accountAccessRepository = accountAccessRepository; _accountRepository = accountRepository; _currencyRepository = currencyRepository; _accountAccountCategoryRepository = accountAccountCategoryRepository; @@ -130,24 +137,24 @@ return result.Set(exists); } - public List GetAllAccounts(Guid userId) + public List GetAllAccounts(Guid userId) { - return _accountRepository.GetAll(userId); + return _mapper.Map>(_accountRepository.GetAll(userId)); } - public List GetByCategory(Guid userId, Guid categoryId) + public List GetByCategory(Guid userId, Guid categoryId) { - return _accountRepository.GetByCategory(userId, categoryId); + return _mapper.Map>(_accountRepository.GetByCategory(userId, categoryId)); } - public List GetByCategoryDetailed(Guid userId, Guid categoryId) + public List GetByCategoryDetailed(Guid userId, Guid categoryId) { - return _accountRepository.GetByCategoryDetailed(userId, categoryId); + return _mapper.Map>(_accountRepository.GetByCategoryDetailed(userId, categoryId)); } - public Exec GetByIdDetailed(Guid userId, Guid id) + public Exec GetByIdDetailed(Guid userId, Guid id) { - var result = new Exec(GeneralExecStatus.success); + var result = new Exec(GeneralExecStatus.success); var account = _accountRepository.GetByIdDetailed(userId, id); if (account == null) @@ -155,7 +162,7 @@ return result.Set(GeneralExecStatus.not_found); } - return result.Set(account); + return result.Set(_mapper.Map(account)); } public Exec AccountAdd(Guid userId, AccountAdd input) @@ -208,9 +215,40 @@ return result.Set(AccountAddResult.failure); } + var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId); + if (access != null && access.Type.ToString() != input.Type) + { + if (Enum.TryParse(input.Type, out var enumType)) + { + access.Type = enumType; + _accountAccessRepository.Update(access); + } + } + return result.Set(account); } + public Exec AccountDelete(Guid userId, string id) + { + var result = new Exec(GeneralExecStatus.success); + + var account = _accountRepository.Get(userId, id.AsGuid()); + if (account == null) + { + return result.Set(GeneralExecStatus.not_found); + } + + if (account.Motions!.Any()) + { + return result.Set(GeneralExecStatus.not_found); + } + + _accountRepository.Delete(account); + result.Set(account); + + return result; + } + public Exec AccountUpdate(Guid userId, Guid accountId, AccountEdit input) { if (input == null) @@ -263,6 +301,16 @@ return result.Set(AccountEditResult.failure); } + var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId); + if (access != null && access.Type.ToString() != input.Type) + { + if (Enum.TryParse(input.Type, out var enumType)) + { + access.Type = enumType; + _accountAccessRepository.Update(access); + } + } + return result.Set(account); } diff --git a/MyOffice.Services/Account/Domain/AccountAdd.cs b/MyOffice.Services/Account/Domain/AccountAdd.cs index bcb7190..1077830 100644 --- a/MyOffice.Services/Account/Domain/AccountAdd.cs +++ b/MyOffice.Services/Account/Domain/AccountAdd.cs @@ -5,5 +5,6 @@ public string Name { get; set; } = null!; public string CurrencyId { get; set; } = null!; public Guid CategoryId { get; set; } + public string Type { get; set; } = null!; } } diff --git a/MyOffice.Services/Account/Domain/AccountDetailedDto.cs b/MyOffice.Services/Account/Domain/AccountDetailedDto.cs new file mode 100644 index 0000000..4a583db --- /dev/null +++ b/MyOffice.Services/Account/Domain/AccountDetailedDto.cs @@ -0,0 +1,9 @@ +namespace MyOffice.Services.Account.Domain; + +public class AccountDetailedDto +{ + public AccountDto Account { get; set; } = null!; + public decimal TotalPlus { get; set; } + public decimal TotalMinus { get; set; } + public decimal Rest => TotalPlus - TotalMinus; +} diff --git a/MyOffice.Services/Account/Domain/AccountDto.cs b/MyOffice.Services/Account/Domain/AccountDto.cs new file mode 100644 index 0000000..3484006 --- /dev/null +++ b/MyOffice.Services/Account/Domain/AccountDto.cs @@ -0,0 +1,92 @@ +using MyOffice.Data.Models.Accounts; +using MyOffice.Data.Models.Users; +using 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 + { + public Guid Id { get; set; } + public string CurrencyGlobalId { get; set; } = null!; + public CurrencyGlobal? CurrencyGlobal { get; set; } + public Guid CurrencyId { get; set; } + public Currency? Currency { get; set; } + public Guid UserId { get; set; } + public UserDto? User { get; set; } + public Guid OwnerId { get; set; } + public UserDto? Owner { get; set; } + public string Name { get; set; } = null!; + public bool HasMotions { get; set; } + 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/AccountEdit.cs b/MyOffice.Services/Account/Domain/AccountEdit.cs index 75fdfc6..8a19d69 100644 --- a/MyOffice.Services/Account/Domain/AccountEdit.cs +++ b/MyOffice.Services/Account/Domain/AccountEdit.cs @@ -6,4 +6,5 @@ public class AccountEdit public string CurrencyId { get; set; } = null!; public Guid? CategoryId { get; set; } public Guid? UserId { get; set; } + public string? Type { get; set; } } \ No newline at end of file diff --git a/MyOffice.Services/Dashboard/DashboardService.cs b/MyOffice.Services/Dashboard/DashboardService.cs index 11a6c4f..935f999 100644 --- a/MyOffice.Services/Dashboard/DashboardService.cs +++ b/MyOffice.Services/Dashboard/DashboardService.cs @@ -27,21 +27,37 @@ public class DashboardService public DashboardData GetDashboardRestData(Guid userId) { - /*var lastDaysStart = DateTime.UtcNow.AddMonths(-3).StartOfDay(); - var lastDaysEnd = lastDaysStart.AddMonths(3).EndOfDay(); - var previousDaysStart = lastDaysStart.AddMonths(-3).StartOfDay(); - var previousDaysEnd = previousDaysStart.AddMonths(3).EndOfDay();*/ var rests = _accountRepository.GetRestAtDate(userId, DateTime.UtcNow); var result = new DashboardData { - //IncomeLast = _accountRepository.GetPeriodIncome(userId, lastDaysStart, lastDaysEnd), - //IncomePrevious = _accountRepository.GetPeriodIncome(userId, previousDaysStart, previousDaysEnd), - //OutcomeLast = _accountRepository.GetPeriodOutcome(userId, lastDaysStart, lastDaysEnd), - //OutcomePrevious = _accountRepository.GetPeriodOutcome(userId, previousDaysStart, previousDaysEnd), - Balance = rests.Sum(x => x.Balance * (x.CurrencyRate * x.CurrencyQuantity)), - BalanceDebit = rests.Where(x => x.Balance > 0).Sum(x => x.Balance * (x.CurrencyRate * x.CurrencyQuantity)), - BalanceCredit = rests.Where(x => x.Balance < 0).Sum(x => x.Balance * (x.CurrencyRate * x.CurrencyQuantity)), + Balance = rests + .Where(x => (x.Type == AccountAccessTypeEnum.balance || x.Type == AccountAccessTypeEnum.credit) && x.CurrencyRate.HasValue) + .Sum(x => x.Balance * (x.CurrencyRate * x.CurrencyQuantity)), + + BalanceDebit = rests + .Where(x => x.Type == AccountAccessTypeEnum.balance && x.CurrencyRate.HasValue) + .Sum(x => x.Balance * (x.CurrencyRate * x.CurrencyQuantity)), + + BalanceCredit = rests + .Where(x => x.Type == AccountAccessTypeEnum.credit && x.CurrencyRate.HasValue) + .Sum(x => x.Balance * (x.CurrencyRate * x.CurrencyQuantity)), + + BalanceRests = rests + .Where(x => x.Type == AccountAccessTypeEnum.balance) + .Where(x => x.CurrencyRate.HasValue && x.Balance.HasValue && x.Balance != 0) + .Select(x => new DashboardRestData + { + Id = x.Id, + Name = x.Name, + Balance = x.Balance, + CurrencyName = x.CurrencyName, + CurrencyShortName = x.CurrencyShortName, + CurrencyRate = x.CurrencyRate, + CurrencyQuantity = x.CurrencyQuantity, + }) + .OrderByDescending(x => x.BalanceAtRate) + .ToList(), }; return result; diff --git a/MyOffice.Services/Dashboard/Domain/DashboardData.cs b/MyOffice.Services/Dashboard/Domain/DashboardData.cs index 5c31403..d3dd8b1 100644 --- a/MyOffice.Services/Dashboard/Domain/DashboardData.cs +++ b/MyOffice.Services/Dashboard/Domain/DashboardData.cs @@ -13,13 +13,18 @@ public class DashboardData public decimal? Balance { get; set; } public decimal? BalanceDebit { get; set; } public decimal? BalanceCredit { get; set; } + public List BalanceRests { get; set; } } public class DashboardRestData { - public AccountSimple AccountSimple { get; set; } - public decimal? Balance => AccountSimple.Balance; + public Guid Id { get; set; } + public string Name { get; set; } = null!; + public string CurrencyName { get; set; } = null!; + public string CurrencyShortName { get; set; } = null!; + public decimal? Balance { get; set; } + public decimal? CurrencyRate { get; set; } + public decimal? CurrencyQuantity { get; set; } - public decimal? BalanceAtRate => - AccountSimple.Balance * (AccountSimple.CurrencyRate * AccountSimple.CurrencyQuantity); + public decimal? BalanceAtRate => Balance * (CurrencyRate * CurrencyQuantity); } \ No newline at end of file diff --git a/MyOffice.Services/Identity/IContextProvider.cs b/MyOffice.Services/Identity/IContextProvider.cs new file mode 100644 index 0000000..b57fd11 --- /dev/null +++ b/MyOffice.Services/Identity/IContextProvider.cs @@ -0,0 +1,10 @@ +namespace MyOffice.Services.Identity; + +using Data.Models.Users; + +public interface IContextProvider +{ + User User { get; } + Guid UserId { get; } +} + diff --git a/MyOffice.Services/MyOffice.Services.csproj b/MyOffice.Services/MyOffice.Services.csproj index 7349330..6fa9991 100644 --- a/MyOffice.Services/MyOffice.Services.csproj +++ b/MyOffice.Services/MyOffice.Services.csproj @@ -6,6 +6,10 @@ enable + + + + diff --git a/MyOffice.Web/Controllers/AccountController.cs b/MyOffice.Web/Controllers/AccountController.cs index bdf2073..995eaac 100644 --- a/MyOffice.Web/Controllers/AccountController.cs +++ b/MyOffice.Web/Controllers/AccountController.cs @@ -1,5 +1,6 @@ namespace MyOffice.Web.Controllers; +using AutoMapper; using Core; using Core.Extensions; using Microsoft.AspNetCore.Authorization; @@ -18,28 +19,29 @@ using Services.Item; public class AccountController : BaseApiController { private readonly ILogger _logger; + private readonly IMapper _mapper; private readonly AccountService _accountService; private readonly ItemService _itemService; public AccountController( ILogger logger, + IMapper mapper, AccountService accountService, ItemService itemService ) { _logger = logger; + _mapper = mapper; _accountService = accountService; _itemService = itemService; } [HttpGet("~/api/accounts")] - public object AccountsGet(string category) + public List AccountsGet(string category) { var list = _accountService.GetByCategoryDetailed(UserId, category!.AsGuid()); - return list - .OrderBy(x => x.Account.Name) - .Select(x => x.ToModel()); + return _mapper.Map>(list.OrderBy(x => x.Account.Name).ToList()); } [HttpGet("~/api/accounts/{id}")] @@ -54,7 +56,8 @@ public class AccountController : BaseApiController return ProblemBadRequest("Account not found."); case GeneralExecStatus.success: - return exec.Result!.ToModel(); + return _mapper.Map(exec.Result); + //return exec.Result!.ToModel(); default: throw new NotSupportedException(exec.Status.ToString()); diff --git a/MyOffice.Web/Controllers/SettingsAccountController.cs b/MyOffice.Web/Controllers/SettingsAccountController.cs index 43aa23d..7b0c41e 100644 --- a/MyOffice.Web/Controllers/SettingsAccountController.cs +++ b/MyOffice.Web/Controllers/SettingsAccountController.cs @@ -1,5 +1,6 @@ namespace MyOffice.Web.Controllers; +using AutoMapper; using Core; using Core.Extensions; using Data.Models.Accounts; @@ -15,14 +16,17 @@ using Services.Account.Domain; public class SettingsAccountController : BaseApiController { private readonly ILogger _logger; + private readonly IMapper _mapper; private readonly AccountService _accountService; public SettingsAccountController( ILogger logger, + IMapper mapper, AccountService accountService ) { _logger = logger; + _mapper = mapper; _accountService = accountService; } @@ -111,15 +115,13 @@ public class SettingsAccountController : BaseApiController } [HttpGet("~/api/settings/accounts")] - public object AccountsGet(string? category) + public List AccountsGet(string? category) { var list = category.IsPresent() ? _accountService.GetByCategory(UserId, category!.AsGuid()) : _accountService.GetAllAccounts(UserId); - return list - .OrderBy(x => x.Name) - .Select(x => x.ToModel()); + return _mapper.Map>(list.OrderBy(x => x.Name)); } [HttpPost("~/api/settings/accounts")] @@ -130,6 +132,7 @@ public class SettingsAccountController : BaseApiController Name = request.Name, CurrencyId = request.CurrencyId, CategoryId = request.CategoryId.AsGuid(), + Type = request.Type, }); switch (exec.Status) @@ -158,6 +161,7 @@ public class SettingsAccountController : BaseApiController CurrencyId = request.CurrencyId, CategoryId = request.CategoryId?.AsGuidNull(), UserId = request.UserId?.AsGuidNull(), + Type = request.Type, }); switch (exec.Status) @@ -177,7 +181,23 @@ public class SettingsAccountController : BaseApiController throw new NotSupportedException(exec.Status.ToString()); } } - + + [HttpDelete("~/api/settings/accounts/{id}")] + public object AccountsDelete(string id) + { + var exec = _accountService.AccountDelete(UserId, id); + switch (exec.Status) + { + case GeneralExecStatus.not_found: + return ProblemBadRequest("Account not found."); + case GeneralExecStatus.success: + return exec.Result!; + + default: + throw new NotSupportedException(exec.Status.ToString()); + } + } + [HttpDelete("~/api/settings/accounts/{id}/category/{categoryId}")] public object AccountsCategoryRemove(string id, string categoryId) { diff --git a/MyOffice.Web/Controllers/UserController.cs b/MyOffice.Web/Controllers/UserController.cs index d28e915..9a4438a 100644 --- a/MyOffice.Web/Controllers/UserController.cs +++ b/MyOffice.Web/Controllers/UserController.cs @@ -13,6 +13,7 @@ using MyOffice.Core.Identity; using Core; using Services.Users; using Services.Users.Domain; +using MyOffice.Data.Models.Currencies; [ApiController] [Route("api/[controller]")] @@ -40,7 +41,8 @@ public class UserController : BaseApiController { Id = Guid.NewGuid(), UserName = request.UserName, - Email = request.UserName + Email = request.UserName, + CurrencyId = CurrencyGlobalIdEnum.USD.ToString(), }; var result = await _userManager.CreateAsync(user, request.Password); diff --git a/MyOffice.Web/Identity/Configure/ConfigureIdentityServerOptions.cs b/MyOffice.Web/Identity/Configure/ConfigureIdentityServerOptions.cs index 7b04fac..99edc27 100644 --- a/MyOffice.Web/Identity/Configure/ConfigureIdentityServerOptions.cs +++ b/MyOffice.Web/Identity/Configure/ConfigureIdentityServerOptions.cs @@ -20,7 +20,6 @@ public class ConfigureIdentityServerOptions : IConfigureNamedOptions x.Type == "sub")!.Value); + } + } +} diff --git a/MyOffice.Web/Models/Account/AccessRightsViewModel.cs b/MyOffice.Web/Models/Account/AccessRightsViewModel.cs index cb7bbc3..4d43bd9 100644 --- a/MyOffice.Web/Models/Account/AccessRightsViewModel.cs +++ b/MyOffice.Web/Models/Account/AccessRightsViewModel.cs @@ -1,6 +1,7 @@ namespace MyOffice.Web.Models.Account { using Data.Models.Accounts; + using Services.Account.Domain; using User; public class AccessRightsViewModel @@ -13,7 +14,7 @@ public static class AccessRightsViewModelExtensions { - public static AccessRightsViewModel ToModel(this AccountAccess accountAccess) + public static AccessRightsViewModel ToModel(this AccountAccessDto accountAccess) { return new AccessRightsViewModel { diff --git a/MyOffice.Web/Models/Account/AccountDetailedViewModel.cs b/MyOffice.Web/Models/Account/AccountDetailedViewModel.cs index 2848b55..9ee9869 100644 --- a/MyOffice.Web/Models/Account/AccountDetailedViewModel.cs +++ b/MyOffice.Web/Models/Account/AccountDetailedViewModel.cs @@ -1,6 +1,7 @@ namespace MyOffice.Web.Models.Account; using Data.Models.Accounts; +using Services.Account.Domain; public class AccountDetailedViewModel { @@ -8,9 +9,9 @@ public class AccountDetailedViewModel public decimal Rest { get; set; } } -public static class AccountDetailedViewModelExtensions +/*public static class AccountDetailedViewModelExtensions { - public static AccountDetailedViewModel ToModel(this AccountDetailed input) + public static AccountDetailedViewModel ToModel(this AccountDetailedDto input) { return new AccountDetailedViewModel { @@ -18,4 +19,4 @@ public static class AccountDetailedViewModelExtensions Rest = input.Rest, }; } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/MyOffice.Web/Models/Account/AccountEditRequestModel.cs b/MyOffice.Web/Models/Account/AccountEditRequestModel.cs index 6c07a9a..07ee7c9 100644 --- a/MyOffice.Web/Models/Account/AccountEditRequestModel.cs +++ b/MyOffice.Web/Models/Account/AccountEditRequestModel.cs @@ -8,6 +8,7 @@ public class AccountEditRequestModel public string Name { get; set; } = null!; [Required] public string CurrencyId { get; set; } = null!; - public string? CategoryId { get; set; } = null!; - public string? UserId { get; set; } = null!; + public string? CategoryId { get; set; } + public string? UserId { get; set; } + public string? Type { get; set; } } \ No newline at end of file diff --git a/MyOffice.Web/Models/Account/AccountViewModel.cs b/MyOffice.Web/Models/Account/AccountViewModel.cs index 283c68b..ef62fa6 100644 --- a/MyOffice.Web/Models/Account/AccountViewModel.cs +++ b/MyOffice.Web/Models/Account/AccountViewModel.cs @@ -1,19 +1,25 @@ namespace MyOffice.Web.Models.Account { using System.ComponentModel.DataAnnotations; + using AutoMapper; using Core.Extensions; using Data.Models.Accounts; + using Services.Account.Domain; + using Services.Identity; + using User; public class AccountViewModel { public string? Id { get; set; } - [Required] + [Required] public string Name { get; set; } = null!; + public string Type { get; set; } = null!; - [Required] + [Required] public string CurrencyId { get; set; } = null!; public string? CurrencyName { get; set; } + public bool AllowDelete { get; set; } public List? Categories { get; set; } @@ -23,9 +29,48 @@ public List? AccessRights { get; set; } } - public static class AccountViewModelExtensions + public class ViewModelProfile : Profile { - public static AccountViewModel ToModel(this Account input) + public ViewModelProfile() + { + CreateMap().ConvertUsing(x => x.ToShort()); + } + } + + public class AccountViewModelProfile : Profile + { + public AccountViewModelProfile( + IContextProvider contextProvider + ) + { + + CreateMap() + .ForMember(x => x.Account, o => o.MapFrom(x => x.Account)) + ; + + CreateMap(); + + CreateMap(); + + CreateMap() + .ForMember(x => x.Type, o => o.MapFrom(x => x.AccessRights!.FirstOrDefault(a => a.UserId == contextProvider.UserId)!.Type.ToString())) + .ForMember(x => x.CurrencyId, o => o.MapFrom(x => x.CurrencyGlobalId)) + .ForMember(x => x.CurrencyName, o => o.MapFrom(x => x.Currency!.Name)) + .ForMember(x => x.AllowDelete, o => o.MapFrom(x => !x.HasMotions)) + ; + + CreateMap() + .ForMember(x => x.Id, o => o.MapFrom(x => x.CategoryId)) + .ForMember(x => x.Name, o => o.MapFrom(x => x.Category!.Name)) + ; + + CreateMap(); + } + } + + /*public static class AccountViewModelExtensions + { + public static AccountViewModel ToModel(this AccountDto input) { return new AccountViewModel { @@ -41,5 +86,5 @@ .ToList(), }; } - } + }*/ } diff --git a/MyOffice.Web/MyOffice.Web.csproj b/MyOffice.Web/MyOffice.Web.csproj index be0616e..16953c3 100644 --- a/MyOffice.Web/MyOffice.Web.csproj +++ b/MyOffice.Web/MyOffice.Web.csproj @@ -34,6 +34,8 @@ + + diff --git a/MyOffice.Web/Program.cs b/MyOffice.Web/Program.cs index 3630469..9c95e44 100644 --- a/MyOffice.Web/Program.cs +++ b/MyOffice.Web/Program.cs @@ -37,10 +37,14 @@ using Identity.Configure; using Infrastructure; using Microsoft.Extensions.Logging.Console; using IdentityServer4.Services; +using Models.Account; using MyOffice.Services.Currency; using Services.Account; using Services.Item; using MyOffice.Services.Dashboard; +using Services.Account.Domain; +using MyOffice.Services.Identity; +using AutoMapper; public class Program { @@ -92,6 +96,10 @@ public class Program AddIdentityServices(builder); + builder.Services.AddScoped(); + + AddMapping(builder); + AddRepositories(builder); AddBusinessServices(builder); @@ -205,6 +213,20 @@ public class Program } } + private static void AddMapping(WebApplicationBuilder builder) + { + builder.Services.AddSingleton(provider => new MapperConfiguration(cfg => + { + cfg.AddProfile(new AccountMappingProfile()); + 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)); + } + private static void AddRepositories(WebApplicationBuilder builder) { builder.Services.AddScoped(); @@ -216,6 +238,7 @@ public class Program builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); @@ -274,9 +297,20 @@ public class Program { _firstRequest = false; - // set real frontend host globalSettings = ctx.RequestServices.GetRequiredService(); - globalSettings.Host = GetFrontendHost(ctx, logger); + + var configuration = ctx.RequestServices.GetRequiredService(); + var frontEndHost = configuration.GetValue("FrontEnd:Host"); + var isDynamicFrontEndHost = frontEndHost.IsMissing(); + if (!isDynamicFrontEndHost) + { + globalSettings.Host = frontEndHost; + } + else + { + // set real frontend host + globalSettings.Host = GetFrontendHost(ctx, logger); + } // update identity server var options = ctx.RequestServices.GetRequiredService();