From fa5a8a90010c9214c2e7ad55ede1ca5ef2ee3e30 Mon Sep 17 00:00:00 2001 From: Alexandr Sulimov Date: Fri, 21 Jul 2023 21:06:45 +0300 Subject: [PATCH] fix --- MyOffice.Data.Models/Accounts/Account.cs | 15 +- MyOffice.Data.Models/Accounts/Motion.cs | 1 + MyOffice.Data.Models/Currencies/Currency.cs | 5 + .../Account/AccountRepository.cs | 44 +- .../Account/IAccountyRepository.cs | 4 + .../Currency/CurrencyRateRepository.cs | 15 + .../Currency/CurrencyRepository.cs | 5 + .../Currency/ICurrencyRateRepository.cs | 1 + .../Currency/ICurrencyRepository.cs | 1 + MyOffice.DbContext/AppDbContext.cs | 4 + MyOffice.DbContext/RepositoryInitializer.cs | 28 +- ...3_PrimaryCurrencyDeletedMotion.Designer.cs | 617 +++++++++++++++++ ...0720190103_PrimaryCurrencyDeletedMotion.cs | 40 ++ .../20230721175243_CurrentRate.Designer.cs | 631 ++++++++++++++++++ .../Migrations/20230721175243_CurrentRate.cs | 58 ++ ...230721180304_CurrentRateRemove.Designer.cs | 617 +++++++++++++++++ .../20230721180304_CurrentRateRemove.cs | 58 ++ .../Migrations/AppDbContextModelSnapshot.cs | 6 + MyOffice.SPA/src/app/api-routes.ts | 2 + .../dashboard2/dashboard2.component.html | 12 +- .../dashboard2/dashboard2.component.ts | 32 +- MyOffice.SPA/src/app/model/currency.model.ts | 1 + MyOffice.SPA/src/app/model/dashboard.model.ts | 8 + .../settings/currency/currency.component.html | 2 +- .../settings/currency/currency.component.ts | 3 + .../currency/rate.currency.component.html | 11 +- .../currency/rate.currency.component.ts | 4 +- MyOffice.Services/Currency/CurrencyService.cs | 14 + .../Currency/Domain/CurrencyEdit.cs | 1 + .../Dashboard/DashboardService.cs | 55 ++ .../Dashboard/Domain/DashboardData.cs | 23 + MyOffice.Services/MyOffice.Services.csproj | 4 - .../Controllers/CurrencyController.cs | 2 +- .../Controllers/DashboardController.cs | 18 +- .../Models/Currency/CurrencyEditModel.cs | 1 + .../Models/Currency/CurrencyViewModel.cs | 2 + MyOffice.Web/Program.cs | 2 + 37 files changed, 2319 insertions(+), 28 deletions(-) create mode 100644 MyOffice.Migration.Postgres/Migrations/20230720190103_PrimaryCurrencyDeletedMotion.Designer.cs create mode 100644 MyOffice.Migration.Postgres/Migrations/20230720190103_PrimaryCurrencyDeletedMotion.cs create mode 100644 MyOffice.Migration.Postgres/Migrations/20230721175243_CurrentRate.Designer.cs create mode 100644 MyOffice.Migration.Postgres/Migrations/20230721175243_CurrentRate.cs create mode 100644 MyOffice.Migration.Postgres/Migrations/20230721180304_CurrentRateRemove.Designer.cs create mode 100644 MyOffice.Migration.Postgres/Migrations/20230721180304_CurrentRateRemove.cs create mode 100644 MyOffice.SPA/src/app/model/dashboard.model.ts create mode 100644 MyOffice.Services/Dashboard/DashboardService.cs create mode 100644 MyOffice.Services/Dashboard/Domain/DashboardData.cs diff --git a/MyOffice.Data.Models/Accounts/Account.cs b/MyOffice.Data.Models/Accounts/Account.cs index 5cd13b2..3340c81 100644 --- a/MyOffice.Data.Models/Accounts/Account.cs +++ b/MyOffice.Data.Models/Accounts/Account.cs @@ -8,6 +8,7 @@ public class Account public string CurrencyGlobalId { get; set; } = null!; public CurrencyGlobal? CurrencyGlobal { get; set; } public string Name { get; set; } = null!; + //public bool IsRest { get; set; } public IEnumerable? AccessRights { get; set; } public IEnumerable? Motions { get; set; } public IEnumerable? Categories { get; set; } @@ -19,4 +20,16 @@ public class AccountDetailed public decimal TotalPlus { get; set; } public decimal TotalMinus { get; set; } public decimal Rest => TotalPlus - TotalMinus; -} \ No newline at end of file +} + +public struct AccountSimple +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string CurrencyId { get; set; } + public string CurrencyShortName { get; set; } + public decimal CurrencyRate { get; set; } + public decimal? TotalPlus { get; set; } + public decimal? TotalMinus { get; set; } + public decimal? Rest { get; set; } +} diff --git a/MyOffice.Data.Models/Accounts/Motion.cs b/MyOffice.Data.Models/Accounts/Motion.cs index eb6c53f..1439e8d 100644 --- a/MyOffice.Data.Models/Accounts/Motion.cs +++ b/MyOffice.Data.Models/Accounts/Motion.cs @@ -18,4 +18,5 @@ public class Motion public string? Description { get; set; } public decimal AmountPlus { get; set; } public decimal AmountMinus { get; set; } + public DateTime? DeletedOn { get; set; } } diff --git a/MyOffice.Data.Models/Currencies/Currency.cs b/MyOffice.Data.Models/Currencies/Currency.cs index ce67776..c8cd254 100644 --- a/MyOffice.Data.Models/Currencies/Currency.cs +++ b/MyOffice.Data.Models/Currencies/Currency.cs @@ -13,4 +13,9 @@ public class Currency public string Name { get; set; } = null!; public string ShortName { get; set; } = null!; public IEnumerable? Rates { get; set; } + + public int? CurrentRateId { get; set; } + public CurrencyRate? CurrentRate { get; set; } + + public bool IsPrimary { get; set; } } \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Account/AccountRepository.cs b/MyOffice.Data.Repositories/Account/AccountRepository.cs index aec9ecb..311a4cc 100644 --- a/MyOffice.Data.Repositories/Account/AccountRepository.cs +++ b/MyOffice.Data.Repositories/Account/AccountRepository.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using Models.Accounts; +using MyOffice.Data.Models.Currencies; using MyOffice.Data.Repositories; public class AccountRepository : AppRepository, IAccountRepository @@ -94,8 +95,49 @@ public class AccountRepository : AppRepository, IAccountRepository public List FindAccounts(Guid userId, string term) { return _context.Accounts - .Where(x => x.AccessRights.Any(a => a.UserId == userId)) + .Where(x => x.AccessRights!.Any(a => a.UserId == userId)) .Where(x => x.Name.Contains(term)) .ToList(); } + + public decimal GetPeriodIncome(Guid userId, DateTime from, DateTime to) + { + return _context.Motions + .Where(x => !x.Item.Category!.IsInternal) + .Where(x => x.Account!.AccessRights!.Any(u => u.UserId == userId)) + .Where(x => x.DateTime >= from && x.DateTime <= to) + .Sum(x => x.AmountPlus); + } + + public decimal GetPeriodOutcome(Guid userId, DateTime from, DateTime to) + { + return _context.Motions + .Where(x => !x.Item.Category!.IsInternal) + .Where(x => x.Account!.AccessRights!.Any(u => u.UserId == userId)) + .Where(x => x.DateTime >= from && x.DateTime <= to) + .Sum(x => x.AmountMinus); + } + + public List GetRestAtDate(Guid userId, DateTime date) + { + return _context.Motions + .Where(x => x.Account!.AccessRights!.Any(u => u.UserId == userId)) + .Where(x => x.DateTime <= date) + .GroupBy(x => new + { + x.AccountId, + x.Account.Name, + CurrencyId = x.Account!.CurrencyGlobalId, + CurrencyName = x.Account!.CurrencyGlobal!.Name, + }) + .Select(x => new AccountSimple + { + Id = x.Key.AccountId, + Name = x.Key.Name, + CurrencyId = x.Key.CurrencyId, + CurrencyShortName = x.Key.CurrencyName, + Rest = x.Sum(g => (g.AmountPlus - g.AmountMinus)) + }) + .ToList(); + } } \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Account/IAccountyRepository.cs b/MyOffice.Data.Repositories/Account/IAccountyRepository.cs index e835ac0..8e0c2c5 100644 --- a/MyOffice.Data.Repositories/Account/IAccountyRepository.cs +++ b/MyOffice.Data.Repositories/Account/IAccountyRepository.cs @@ -13,4 +13,8 @@ public interface IAccountRepository bool Update(Account account); bool Remove(Account account); List FindAccounts(Guid userId, string term); + + decimal GetPeriodIncome(Guid userId, DateTime from, DateTime to); + decimal GetPeriodOutcome(Guid userId, DateTime from, DateTime to); + List GetRestAtDate(Guid userId, DateTime date); } \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Currency/CurrencyRateRepository.cs b/MyOffice.Data.Repositories/Currency/CurrencyRateRepository.cs index d937517..7f0fd0f 100644 --- a/MyOffice.Data.Repositories/Currency/CurrencyRateRepository.cs +++ b/MyOffice.Data.Repositories/Currency/CurrencyRateRepository.cs @@ -1,5 +1,6 @@ namespace MyOffice.Data.Repositories.Currency; +using Microsoft.EntityFrameworkCore; using Models.Currencies; public class CurrencyRateRepository : AppRepository, ICurrencyRateRepository @@ -14,6 +15,20 @@ public class CurrencyRateRepository : AppRepository, ICurrencyRate .ToList(); } + public List GetLastRates(List currencyIds) + { + return _context.CurrencyRates + .Include(x => x.Currency) + .Where(x => currencyIds.Contains(x.Currency!.CurrencyGlobalId)) + .GroupBy(x => new + { + x.CurrencyId, + //x.Currency!.Name, + //x.Currency!.CurrencyGlobalId, + }, (key, g) => g.OrderByDescending(x => x.DateTime).First()) + .ToList(); + } + public bool AddRate(CurrencyRate currencyRate) { return this.AddBase(currencyRate) > 0; diff --git a/MyOffice.Data.Repositories/Currency/CurrencyRepository.cs b/MyOffice.Data.Repositories/Currency/CurrencyRepository.cs index 3543516..09bddb5 100644 --- a/MyOffice.Data.Repositories/Currency/CurrencyRepository.cs +++ b/MyOffice.Data.Repositories/Currency/CurrencyRepository.cs @@ -41,4 +41,9 @@ public class CurrencyRepository : AppRepository, ICurrencyRepository { return RemoveBase(currency) > 0; } + + public List GetPrimaries(Guid userId) + { + return _context.Currencies.Where(x => x.UserId == userId && x.IsPrimary).ToList(); + } } \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Currency/ICurrencyRateRepository.cs b/MyOffice.Data.Repositories/Currency/ICurrencyRateRepository.cs index 144a9f8..b853e5b 100644 --- a/MyOffice.Data.Repositories/Currency/ICurrencyRateRepository.cs +++ b/MyOffice.Data.Repositories/Currency/ICurrencyRateRepository.cs @@ -5,6 +5,7 @@ using Models.Currencies; public interface ICurrencyRateRepository { List GetLastRates(Guid currencyId, int count = 1); + List GetLastRates(List currencyIds); bool AddRate(CurrencyRate currencyRate); List GetAtDate(Guid currencyId, DateTime date); } \ No newline at end of file diff --git a/MyOffice.Data.Repositories/Currency/ICurrencyRepository.cs b/MyOffice.Data.Repositories/Currency/ICurrencyRepository.cs index e7d4493..d66be24 100644 --- a/MyOffice.Data.Repositories/Currency/ICurrencyRepository.cs +++ b/MyOffice.Data.Repositories/Currency/ICurrencyRepository.cs @@ -10,4 +10,5 @@ public interface ICurrencyRepository bool Add(Currency currency); bool Update(Currency currency); bool Remove(Currency currency); + List GetPrimaries(Guid userId); } \ No newline at end of file diff --git a/MyOffice.DbContext/AppDbContext.cs b/MyOffice.DbContext/AppDbContext.cs index 2442b17..574ae2f 100644 --- a/MyOffice.DbContext/AppDbContext.cs +++ b/MyOffice.DbContext/AppDbContext.cs @@ -115,6 +115,10 @@ public class AppDbContext : DbContext .HasOne(x => x.Currency) .WithMany(x => x.Rates) .HasForeignKey(x => x.CurrencyId); + + modelBuilder.Entity() + .HasOne(x => x.CurrentRate) + .WithOne(x => x.Currency); } private void AccountCreating(ModelBuilder modelBuilder) diff --git a/MyOffice.DbContext/RepositoryInitializer.cs b/MyOffice.DbContext/RepositoryInitializer.cs index 526aafb..da7001a 100644 --- a/MyOffice.DbContext/RepositoryInitializer.cs +++ b/MyOffice.DbContext/RepositoryInitializer.cs @@ -17,9 +17,11 @@ public class RepositoryInitializer ConnectionString = connectionString; var db = AppDbContextFactory.Instance.CreateDbContext(); - db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; db.Database.Migrate(); + Prefill(db); + + UpdateCurrentRates(db); } public static ConnectionConfiguration ConnectionString { get; internal set; } = null!; @@ -52,4 +54,28 @@ public class RepositoryInitializer dbContext.SaveChanges(); } + + private static void UpdateCurrentRates(AppDbContext dbContext) + { + var lastrates = dbContext.CurrencyRates + .Include(x => x.Currency) + .GroupBy(x => new + { + x.CurrencyId, + }, (key, g) => g.OrderByDescending(x => x.DateTime).First()) + .ToList(); + + var currencies = dbContext.Currencies.ToList(); + foreach (var currency in currencies) + { + var rate = lastrates.FirstOrDefault(x => x.CurrencyId == currency.Id); + if (rate != null) + { + //currency.CurrentRateId = rate.Id; + dbContext.Attach(currency); + } + } + + dbContext.SaveChanges(); + } } \ No newline at end of file diff --git a/MyOffice.Migration.Postgres/Migrations/20230720190103_PrimaryCurrencyDeletedMotion.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230720190103_PrimaryCurrencyDeletedMotion.Designer.cs new file mode 100644 index 0000000..5a7e7a5 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230720190103_PrimaryCurrencyDeletedMotion.Designer.cs @@ -0,0 +1,617 @@ +// +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("20230720190103_PrimaryCurrencyDeletedMotion")] + partial class PrimaryCurrencyDeletedMotion + { + /// + 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("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("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("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.Users.User", "User") + .WithMany("Currencies") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CurrencyGlobal"); + + 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.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/20230720190103_PrimaryCurrencyDeletedMotion.cs b/MyOffice.Migration.Postgres/Migrations/20230720190103_PrimaryCurrencyDeletedMotion.cs new file mode 100644 index 0000000..8dbcb2d --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230720190103_PrimaryCurrencyDeletedMotion.cs @@ -0,0 +1,40 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class PrimaryCurrencyDeletedMotion : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "DeletedOn", + table: "Motions", + type: "timestamp with time zone", + nullable: true); + + migrationBuilder.AddColumn( + name: "IsPrimary", + table: "Currencies", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "DeletedOn", + table: "Motions"); + + migrationBuilder.DropColumn( + name: "IsPrimary", + table: "Currencies"); + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230721175243_CurrentRate.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230721175243_CurrentRate.Designer.cs new file mode 100644 index 0000000..70a3adf --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230721175243_CurrentRate.Designer.cs @@ -0,0 +1,631 @@ +// +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("20230721175243_CurrentRate")] + partial class CurrentRate + { + /// + 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("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("CurrentRateId1") + .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("CurrentRateId1"); + + 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() + .HasForeignKey("CurrentRateId1"); + + 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.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/20230721175243_CurrentRate.cs b/MyOffice.Migration.Postgres/Migrations/20230721175243_CurrentRate.cs new file mode 100644 index 0000000..c7aef90 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230721175243_CurrentRate.cs @@ -0,0 +1,58 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class CurrentRate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CurrentRateId", + table: "Currencies", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "CurrentRateId1", + table: "Currencies", + type: "integer", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Currencies_CurrentRateId1", + table: "Currencies", + column: "CurrentRateId1"); + + migrationBuilder.AddForeignKey( + name: "FK_Currencies_CurrencyRates_CurrentRateId1", + table: "Currencies", + column: "CurrentRateId1", + principalTable: "CurrencyRates", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Currencies_CurrencyRates_CurrentRateId1", + table: "Currencies"); + + migrationBuilder.DropIndex( + name: "IX_Currencies_CurrentRateId1", + table: "Currencies"); + + migrationBuilder.DropColumn( + name: "CurrentRateId", + table: "Currencies"); + + migrationBuilder.DropColumn( + name: "CurrentRateId1", + table: "Currencies"); + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/20230721180304_CurrentRateRemove.Designer.cs b/MyOffice.Migration.Postgres/Migrations/20230721180304_CurrentRateRemove.Designer.cs new file mode 100644 index 0000000..71d3381 --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230721180304_CurrentRateRemove.Designer.cs @@ -0,0 +1,617 @@ +// +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("20230721180304_CurrentRateRemove")] + partial class CurrentRateRemove + { + /// + 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("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("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("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.Users.User", "User") + .WithMany("Currencies") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CurrencyGlobal"); + + 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.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/20230721180304_CurrentRateRemove.cs b/MyOffice.Migration.Postgres/Migrations/20230721180304_CurrentRateRemove.cs new file mode 100644 index 0000000..30b99ec --- /dev/null +++ b/MyOffice.Migration.Postgres/Migrations/20230721180304_CurrentRateRemove.cs @@ -0,0 +1,58 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MyOffice.Migrations.Postgres.Migrations +{ + /// + public partial class CurrentRateRemove : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_Currencies_CurrencyRates_CurrentRateId1", + table: "Currencies"); + + migrationBuilder.DropIndex( + name: "IX_Currencies_CurrentRateId1", + table: "Currencies"); + + migrationBuilder.DropColumn( + name: "CurrentRateId", + table: "Currencies"); + + migrationBuilder.DropColumn( + name: "CurrentRateId1", + table: "Currencies"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CurrentRateId", + table: "Currencies", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "CurrentRateId1", + table: "Currencies", + type: "integer", + nullable: true); + + migrationBuilder.CreateIndex( + name: "IX_Currencies_CurrentRateId1", + table: "Currencies", + column: "CurrentRateId1"); + + migrationBuilder.AddForeignKey( + name: "FK_Currencies_CurrencyRates_CurrentRateId1", + table: "Currencies", + column: "CurrentRateId1", + principalTable: "CurrencyRates", + principalColumn: "Id"); + } + } +} diff --git a/MyOffice.Migration.Postgres/Migrations/AppDbContextModelSnapshot.cs b/MyOffice.Migration.Postgres/Migrations/AppDbContextModelSnapshot.cs index b829960..bb7b45b 100644 --- a/MyOffice.Migration.Postgres/Migrations/AppDbContextModelSnapshot.cs +++ b/MyOffice.Migration.Postgres/Migrations/AppDbContextModelSnapshot.cs @@ -142,6 +142,9 @@ namespace MyOffice.Migrations.Postgres.Migrations b.Property("DateTime") .HasColumnType("timestamp with time zone"); + b.Property("DeletedOn") + .HasColumnType("timestamp with time zone"); + b.Property("Description") .HasColumnType("text"); @@ -172,6 +175,9 @@ namespace MyOffice.Migrations.Postgres.Migrations .IsRequired() .HasColumnType("text"); + b.Property("IsPrimary") + .HasColumnType("boolean"); + b.Property("Name") .IsRequired() .HasColumnType("text"); diff --git a/MyOffice.SPA/src/app/api-routes.ts b/MyOffice.SPA/src/app/api-routes.ts index 59a65bd..15fb899 100644 --- a/MyOffice.SPA/src/app/api-routes.ts +++ b/MyOffice.SPA/src/app/api-routes.ts @@ -30,4 +30,6 @@ export class ApiRoutes { static Motion = '/api/accounts/:id/motions/:motionId'; static Items = '/api/items'; + + static Dashboard = '/api/dashboard'; } diff --git a/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.html b/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.html index aa5cb94..9562a7b 100644 --- a/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.html +++ b/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.html @@ -15,7 +15,7 @@
Income

Income last 7 days

-

$170

+

{{dashboardModel?.incomeLastWeek | number: '1.2-6'}}

@@ -24,9 +24,9 @@
-
+

Change previous 7 days

-

75%

+

{{dashboardModel?.incomeChange | number: '1.2'}}%

@@ -40,7 +40,7 @@
Outcome

Outcome last 7 days

-

$120

+

{{dashboardModel?.outcomeLastWeek | number: '1.2-6'}}

@@ -49,9 +49,9 @@
-
+

Change previous 7 days

-

25%

+

{{dashboardModel?.outcomeChange | 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 0aad829..fe03afa 100644 --- a/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.ts +++ b/MyOffice.SPA/src/app/dashboard/dashboard2/dashboard2.component.ts @@ -1,4 +1,8 @@ +// angular import { Component, OnInit } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +// libs import { ApexAxisChartSeries, ApexChart, @@ -16,6 +20,10 @@ import { ApexNonAxisChartSeries, } from 'ng-apexcharts'; +// app +import { ApiRoutes } from '../../api-routes'; +import { DashboardModel } from '../../model/dashboard.model'; + export type ChartOptions = { series: ApexAxisChartSeries; series2: ApexNonAxisChartSeries; @@ -43,15 +51,35 @@ export type ChartOptions = { export class Dashboard2Component implements OnInit { lineChartOptions!: Partial; pieChartOptions!: Partial; + dashboardModel?: DashboardModel; // color: ["#3FA7DC", "#F6A025", "#9BC311"], - constructor() { - //constructor + constructor(private httpClient: HttpClient) { + } ngOnInit() { this.chart1(); this.chart2(); + + this.httpClient + .get(ApiRoutes.Dashboard) + .subscribe(data => { + data.incomeChange = this.calcChanges(data.incomeLastWeek, data.incomePreviousWeek); + data.outcomeChange = this.calcChanges(data.outcomeLastWeek, data.outcomePreviousWeek); + this.dashboardModel = data; + }); + } + + private calcChanges(newValue: number, oldValue: number): number { + if (newValue > oldValue) { + return (newValue - oldValue) / oldValue * 100; + } + else if (newValue < oldValue) { + return (oldValue - newValue) / oldValue * 100; + } + + return 0; } private chart1() { diff --git a/MyOffice.SPA/src/app/model/currency.model.ts b/MyOffice.SPA/src/app/model/currency.model.ts index bb912d8..5ad985a 100644 --- a/MyOffice.SPA/src/app/model/currency.model.ts +++ b/MyOffice.SPA/src/app/model/currency.model.ts @@ -8,4 +8,5 @@ export interface CurrencyModel { rate?: number, rateDate?: Date, isConnected?: boolean, + isPrimary?: boolean, } diff --git a/MyOffice.SPA/src/app/model/dashboard.model.ts b/MyOffice.SPA/src/app/model/dashboard.model.ts new file mode 100644 index 0000000..304d339 --- /dev/null +++ b/MyOffice.SPA/src/app/model/dashboard.model.ts @@ -0,0 +1,8 @@ +export interface DashboardModel { + incomeLastWeek: number; + incomePreviousWeek: number; + incomeChange: number; + outcomeLastWeek: number; + outcomePreviousWeek: number; + outcomeChange: number; +} diff --git a/MyOffice.SPA/src/app/pages/settings/currency/currency.component.html b/MyOffice.SPA/src/app/pages/settings/currency/currency.component.html index 45daa8a..513d7d8 100644 --- a/MyOffice.SPA/src/app/pages/settings/currency/currency.component.html +++ b/MyOffice.SPA/src/app/pages/settings/currency/currency.component.html @@ -28,7 +28,7 @@ - + {{item.code}} {{item.name}} {{item.shortName}} diff --git a/MyOffice.SPA/src/app/pages/settings/currency/currency.component.ts b/MyOffice.SPA/src/app/pages/settings/currency/currency.component.ts index a667d03..d976782 100644 --- a/MyOffice.SPA/src/app/pages/settings/currency/currency.component.ts +++ b/MyOffice.SPA/src/app/pages/settings/currency/currency.component.ts @@ -20,6 +20,7 @@ export class SettingsCurrencyComponent { public currencies?: CurrencyModel[]; public myCurrencies?: CurrencyModel[]; + public primaryId?: string; constructor( private httpClient: HttpClient, @@ -74,6 +75,7 @@ export class SettingsCurrencyComponent { .subscribe(data => { this.myCurrencies = data.map(myCurrency => { var globalCurrency = this.currencies?.find(x => x.id === myCurrency.code); + return { id: myCurrency.id, code: myCurrency.code, @@ -83,6 +85,7 @@ export class SettingsCurrencyComponent { rateDate: myCurrency.rateDate, shortName: myCurrency.shortName, symbol: globalCurrency?.symbol, + isPrimary: myCurrency.isPrimary, }; }); }); diff --git a/MyOffice.SPA/src/app/pages/settings/currency/rate.currency.component.html b/MyOffice.SPA/src/app/pages/settings/currency/rate.currency.component.html index 447a364..2c75d88 100644 --- a/MyOffice.SPA/src/app/pages/settings/currency/rate.currency.component.html +++ b/MyOffice.SPA/src/app/pages/settings/currency/rate.currency.component.html @@ -64,7 +64,7 @@ Rate Date - YYYY/MM/DD + DD/MM/YYYY @@ -74,6 +74,15 @@ +
+
+
+ + Primary currency + +
+
+
diff --git a/MyOffice.SPA/src/app/pages/settings/currency/rate.currency.component.ts b/MyOffice.SPA/src/app/pages/settings/currency/rate.currency.component.ts index fada566..03233e7 100644 --- a/MyOffice.SPA/src/app/pages/settings/currency/rate.currency.component.ts +++ b/MyOffice.SPA/src/app/pages/settings/currency/rate.currency.component.ts @@ -60,6 +60,9 @@ export class SettingsRateCurrencyComponent { this.currency.rateDate, [Validators.required], ], + isPrimary: [ + this.currency.isPrimary, + ], }); } @@ -73,7 +76,6 @@ export class SettingsRateCurrencyComponent { this.httpClient .put(ApiRoutes.SettingsCurrency.replace(':id', this.addForm.value.id), this.addForm.value) .subscribe(response => { - console.log(this.addForm.value); this.httpClient .post(ApiRoutes.SettingsCurrenciesRate.replace(':id', this.addForm.value.id), this.addForm.value) .subscribe(response => { diff --git a/MyOffice.Services/Currency/CurrencyService.cs b/MyOffice.Services/Currency/CurrencyService.cs index 78c9f4a..e8175bb 100644 --- a/MyOffice.Services/Currency/CurrencyService.cs +++ b/MyOffice.Services/Currency/CurrencyService.cs @@ -83,12 +83,26 @@ public class CurrencyService exists.Name = currency.Name; exists.ShortName = currency.ShortName; + exists.IsPrimary = currency.IsPrimary; if (!_currencyRepository.Update(exists)) { return result.Set(CurrencyEditStatus.failed); } + if (exists.IsPrimary) + { + var primaries = _currencyRepository.GetPrimaries(userId); + foreach (var primary in primaries) + { + if (primary.Id != exists.Id) + { + primary.IsPrimary = false; + _currencyRepository.Update(primary); + } + } + } + return result.Set(exists); } diff --git a/MyOffice.Services/Currency/Domain/CurrencyEdit.cs b/MyOffice.Services/Currency/Domain/CurrencyEdit.cs index 98d589b..ddbdad7 100644 --- a/MyOffice.Services/Currency/Domain/CurrencyEdit.cs +++ b/MyOffice.Services/Currency/Domain/CurrencyEdit.cs @@ -4,4 +4,5 @@ public class CurrencyEdit { public string Name { get; set; } = null!; public string ShortName { get; set; } = null!; + public bool IsPrimary { get; set; } } \ No newline at end of file diff --git a/MyOffice.Services/Dashboard/DashboardService.cs b/MyOffice.Services/Dashboard/DashboardService.cs new file mode 100644 index 0000000..f5d85e4 --- /dev/null +++ b/MyOffice.Services/Dashboard/DashboardService.cs @@ -0,0 +1,55 @@ +namespace MyOffice.Services.Dashboard; + +using MyOffice.Services.Dashboard.Domain; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Core.Extensions; +using Data.Repositories.Account; +using Data.Repositories.Currency; + +public class DashboardService +{ + private readonly IAccountRepository _accountRepository; + private readonly ICurrencyRateRepository _currencyRateRepository; + + public DashboardService( + IAccountRepository accountRepository, + ICurrencyRateRepository currencyRateRepository + ) + { + _accountRepository = accountRepository; + _currencyRateRepository = currencyRateRepository; + } + + public DashboardData GetDashboardRestData(Guid userId) + { + var lastDaysStart = DateTime.UtcNow.AddDays(-7).StartOfDay(); + var lastDaysEnd = lastDaysStart.AddDays(7).EndOfDay(); + var previousDaysStart = lastDaysStart.AddDays(-7).StartOfDay(); + var previousDaysEnd = previousDaysStart.AddDays(7).EndOfDay(); + var rests = _accountRepository.GetRestAtDate(userId, DateTime.UtcNow); + + var currencyIds = rests + .Select(x => x.CurrencyId) + .Distinct() + .ToList(); + + var lastrates = _currencyRateRepository.GetLastRates(currencyIds); + foreach (var rest in rests) + { + //var rate = lastrates.FirstOrDefault(x => x.CurrencyId == rest.CurrencyId) + } + + return new DashboardData + { + IncomeLastWeek = _accountRepository.GetPeriodIncome(userId, lastDaysStart, lastDaysEnd), + IncomePreviousWeek = _accountRepository.GetPeriodIncome(userId, previousDaysStart, previousDaysEnd), + OutcomeLastWeek = _accountRepository.GetPeriodOutcome(userId, lastDaysStart, lastDaysEnd), + OutcomePreviousWeek = _accountRepository.GetPeriodOutcome(userId, previousDaysStart, previousDaysEnd), + Rests = rests, + }; + } +} diff --git a/MyOffice.Services/Dashboard/Domain/DashboardData.cs b/MyOffice.Services/Dashboard/Domain/DashboardData.cs new file mode 100644 index 0000000..01e2595 --- /dev/null +++ b/MyOffice.Services/Dashboard/Domain/DashboardData.cs @@ -0,0 +1,23 @@ +namespace MyOffice.Services.Dashboard.Domain; + +using System.Collections.Generic; +using Data.Models.Accounts; + +public class DashboardData +{ + public decimal IncomeLastWeek { get; set; } + public decimal IncomePreviousWeek { get; set; } + public decimal OutcomeLastWeek { get; set; } + public decimal OutcomePreviousWeek { get; set; } + public List? Rests { get; set; } + public decimal? RestTotal => Rests?.Sum(x => x.Rest); + public decimal? RestTotalPlus => Rests?.Where(x => x.Rest > 0).Sum(x => x.Rest); + public decimal? RestTotalMinus => Rests?.Where(x => x.Rest < 0).Sum(x => x.Rest); +} + +/*public class DashboardRestData +{ + public string AccountId { get; set; } + public string AccountName { get; set; } + public decimal Rest { get; set; } +}*/ \ No newline at end of file diff --git a/MyOffice.Services/MyOffice.Services.csproj b/MyOffice.Services/MyOffice.Services.csproj index f47d6de..7349330 100644 --- a/MyOffice.Services/MyOffice.Services.csproj +++ b/MyOffice.Services/MyOffice.Services.csproj @@ -11,8 +11,4 @@ - - - - diff --git a/MyOffice.Web/Controllers/CurrencyController.cs b/MyOffice.Web/Controllers/CurrencyController.cs index fdc40af..d8222af 100644 --- a/MyOffice.Web/Controllers/CurrencyController.cs +++ b/MyOffice.Web/Controllers/CurrencyController.cs @@ -75,7 +75,7 @@ public class CurrencyController : BaseApiController var exec = _currencyService.CurrencyUpdate( UserId, id.AsGuid(), - new CurrencyEdit { Name = currency.Name, ShortName = currency.ShortName } + new CurrencyEdit { Name = currency.Name, ShortName = currency.ShortName, IsPrimary = currency.IsPrimary } ); switch (exec.Status) diff --git a/MyOffice.Web/Controllers/DashboardController.cs b/MyOffice.Web/Controllers/DashboardController.cs index 6f29678..cc2d315 100644 --- a/MyOffice.Web/Controllers/DashboardController.cs +++ b/MyOffice.Web/Controllers/DashboardController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using MyOffice.Services.Account; using MyOffice.Services.Item; +using Services.Dashboard; [Authorize] [ApiController] @@ -11,24 +12,23 @@ using MyOffice.Services.Item; public class DashboardController : BaseApiController { private readonly ILogger _logger; + private readonly DashboardService _dashboardService; public DashboardController( - ILogger logger + ILogger logger, + DashboardService dashboardService ) { _logger = logger; + _dashboardService = dashboardService; } - [HttpGet("~/api/accounts")] + [HttpGet("~/api/dashboard")] public object Index() { - return new - { - IncomeLastWeek = 100m, - IncomePreviousWeek = 100m, - OutcomeLastWeek = 100m, - OutcomePreviousWeek = 100m, - }; + var data = _dashboardService.GetDashboardRestData(UserId); + + return data; } } diff --git a/MyOffice.Web/Models/Currency/CurrencyEditModel.cs b/MyOffice.Web/Models/Currency/CurrencyEditModel.cs index e8a5d34..412607a 100644 --- a/MyOffice.Web/Models/Currency/CurrencyEditModel.cs +++ b/MyOffice.Web/Models/Currency/CurrencyEditModel.cs @@ -7,4 +7,5 @@ public class CurrencyEditModel public int Quantity { get; set; } public decimal Rate { get; set; } public DateTime RateDate { get; set; } + public bool IsPrimary { get; set; } } \ No newline at end of file diff --git a/MyOffice.Web/Models/Currency/CurrencyViewModel.cs b/MyOffice.Web/Models/Currency/CurrencyViewModel.cs index 2d34d58..0e5fcf2 100644 --- a/MyOffice.Web/Models/Currency/CurrencyViewModel.cs +++ b/MyOffice.Web/Models/Currency/CurrencyViewModel.cs @@ -14,6 +14,7 @@ public decimal? Rate { get; set; } public int? Quantity { get; set; } public DateTime? RateDate { get; set; } + public bool IsPrimary { get; set; } } public static class CurrencyViewModelExtensions @@ -30,6 +31,7 @@ Quantity = rate?.Quantity, Rate = rate?.Rate, RateDate = rate?.DateTime, + IsPrimary = input.IsPrimary, }; } } diff --git a/MyOffice.Web/Program.cs b/MyOffice.Web/Program.cs index 57aca2b..3630469 100644 --- a/MyOffice.Web/Program.cs +++ b/MyOffice.Web/Program.cs @@ -40,6 +40,7 @@ using IdentityServer4.Services; using MyOffice.Services.Currency; using Services.Account; using Services.Item; +using MyOffice.Services.Dashboard; public class Program { @@ -229,6 +230,7 @@ public class Program builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); } private static readonly ConcurrentDictionary _staticFilesCache = new();