This commit is contained in:
2023-07-21 21:06:45 +03:00
parent 2f108bef4f
commit fa5a8a9001
37 changed files with 2319 additions and 28 deletions
+13
View File
@@ -8,6 +8,7 @@ public class Account
public string CurrencyGlobalId { get; set; } = null!; public string CurrencyGlobalId { get; set; } = null!;
public CurrencyGlobal? CurrencyGlobal { get; set; } public CurrencyGlobal? CurrencyGlobal { get; set; }
public string Name { get; set; } = null!; public string Name { get; set; } = null!;
//public bool IsRest { get; set; }
public IEnumerable<AccountAccess>? AccessRights { get; set; } public IEnumerable<AccountAccess>? AccessRights { get; set; }
public IEnumerable<Motion>? Motions { get; set; } public IEnumerable<Motion>? Motions { get; set; }
public IEnumerable<AccountAccountCategory>? Categories { get; set; } public IEnumerable<AccountAccountCategory>? Categories { get; set; }
@@ -20,3 +21,15 @@ public class AccountDetailed
public decimal TotalMinus { get; set; } public decimal TotalMinus { get; set; }
public decimal Rest => TotalPlus - TotalMinus; public decimal Rest => TotalPlus - TotalMinus;
} }
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; }
}
+1
View File
@@ -18,4 +18,5 @@ public class Motion
public string? Description { get; set; } public string? Description { get; set; }
public decimal AmountPlus { get; set; } public decimal AmountPlus { get; set; }
public decimal AmountMinus { get; set; } public decimal AmountMinus { get; set; }
public DateTime? DeletedOn { get; set; }
} }
@@ -13,4 +13,9 @@ public class Currency
public string Name { get; set; } = null!; public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!; public string ShortName { get; set; } = null!;
public IEnumerable<CurrencyRate>? Rates { get; set; } public IEnumerable<CurrencyRate>? Rates { get; set; }
public int? CurrentRateId { get; set; }
public CurrencyRate? CurrentRate { get; set; }
public bool IsPrimary { get; set; }
} }
@@ -2,6 +2,7 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Models.Accounts; using Models.Accounts;
using MyOffice.Data.Models.Currencies;
using MyOffice.Data.Repositories; using MyOffice.Data.Repositories;
public class AccountRepository : AppRepository<Account>, IAccountRepository public class AccountRepository : AppRepository<Account>, IAccountRepository
@@ -94,8 +95,49 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
public List<Account> FindAccounts(Guid userId, string term) public List<Account> FindAccounts(Guid userId, string term)
{ {
return _context.Accounts 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)) .Where(x => x.Name.Contains(term))
.ToList(); .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<AccountSimple> 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();
}
} }
@@ -13,4 +13,8 @@ public interface IAccountRepository
bool Update(Account account); bool Update(Account account);
bool Remove(Account account); bool Remove(Account account);
List<Account> FindAccounts(Guid userId, string term); List<Account> FindAccounts(Guid userId, string term);
decimal GetPeriodIncome(Guid userId, DateTime from, DateTime to);
decimal GetPeriodOutcome(Guid userId, DateTime from, DateTime to);
List<AccountSimple> GetRestAtDate(Guid userId, DateTime date);
} }
@@ -1,5 +1,6 @@
namespace MyOffice.Data.Repositories.Currency; namespace MyOffice.Data.Repositories.Currency;
using Microsoft.EntityFrameworkCore;
using Models.Currencies; using Models.Currencies;
public class CurrencyRateRepository : AppRepository<CurrencyRate>, ICurrencyRateRepository public class CurrencyRateRepository : AppRepository<CurrencyRate>, ICurrencyRateRepository
@@ -14,6 +15,20 @@ public class CurrencyRateRepository : AppRepository<CurrencyRate>, ICurrencyRate
.ToList(); .ToList();
} }
public List<CurrencyRate> GetLastRates(List<string> 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) public bool AddRate(CurrencyRate currencyRate)
{ {
return this.AddBase(currencyRate) > 0; return this.AddBase(currencyRate) > 0;
@@ -41,4 +41,9 @@ public class CurrencyRepository : AppRepository<Currency>, ICurrencyRepository
{ {
return RemoveBase(currency) > 0; return RemoveBase(currency) > 0;
} }
public List<Currency> GetPrimaries(Guid userId)
{
return _context.Currencies.Where(x => x.UserId == userId && x.IsPrimary).ToList();
}
} }
@@ -5,6 +5,7 @@ using Models.Currencies;
public interface ICurrencyRateRepository public interface ICurrencyRateRepository
{ {
List<CurrencyRate> GetLastRates(Guid currencyId, int count = 1); List<CurrencyRate> GetLastRates(Guid currencyId, int count = 1);
List<CurrencyRate> GetLastRates(List<string> currencyIds);
bool AddRate(CurrencyRate currencyRate); bool AddRate(CurrencyRate currencyRate);
List<CurrencyRate> GetAtDate(Guid currencyId, DateTime date); List<CurrencyRate> GetAtDate(Guid currencyId, DateTime date);
} }
@@ -10,4 +10,5 @@ public interface ICurrencyRepository
bool Add(Currency currency); bool Add(Currency currency);
bool Update(Currency currency); bool Update(Currency currency);
bool Remove(Currency currency); bool Remove(Currency currency);
List<Currency> GetPrimaries(Guid userId);
} }
+4
View File
@@ -115,6 +115,10 @@ public class AppDbContext : DbContext
.HasOne(x => x.Currency) .HasOne(x => x.Currency)
.WithMany(x => x.Rates) .WithMany(x => x.Rates)
.HasForeignKey(x => x.CurrencyId); .HasForeignKey(x => x.CurrencyId);
modelBuilder.Entity<Currency>()
.HasOne(x => x.CurrentRate)
.WithOne(x => x.Currency);
} }
private void AccountCreating(ModelBuilder modelBuilder) private void AccountCreating(ModelBuilder modelBuilder)
+27 -1
View File
@@ -17,9 +17,11 @@ public class RepositoryInitializer
ConnectionString = connectionString; ConnectionString = connectionString;
var db = AppDbContextFactory.Instance.CreateDbContext(); var db = AppDbContextFactory.Instance.CreateDbContext();
db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
db.Database.Migrate(); db.Database.Migrate();
Prefill(db); Prefill(db);
UpdateCurrentRates(db);
} }
public static ConnectionConfiguration ConnectionString { get; internal set; } = null!; public static ConnectionConfiguration ConnectionString { get; internal set; } = null!;
@@ -52,4 +54,28 @@ public class RepositoryInitializer
dbContext.SaveChanges(); 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();
}
} }
@@ -0,0 +1,617 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("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<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("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
}
}
}
@@ -0,0 +1,40 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class PrimaryCurrencyDeletedMotion : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "DeletedOn",
table: "Motions",
type: "timestamp with time zone",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsPrimary",
table: "Currencies",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "DeletedOn",
table: "Motions");
migrationBuilder.DropColumn(
name: "IsPrimary",
table: "Currencies");
}
}
}
@@ -0,0 +1,631 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<int?>("CurrentRateId1")
.HasColumnType("integer");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("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<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("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
}
}
}
@@ -0,0 +1,58 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class CurrentRate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "CurrentRateId",
table: "Currencies",
type: "integer",
nullable: true);
migrationBuilder.AddColumn<int>(
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");
}
/// <inheritdoc />
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");
}
}
}
@@ -0,0 +1,617 @@
// <auto-generated />
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
{
/// <inheritdoc />
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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("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<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("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<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("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<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("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
}
}
}
@@ -0,0 +1,58 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class CurrentRateRemove : Migration
{
/// <inheritdoc />
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");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "CurrentRateId",
table: "Currencies",
type: "integer",
nullable: true);
migrationBuilder.AddColumn<int>(
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");
}
}
}
@@ -142,6 +142,9 @@ namespace MyOffice.Migrations.Postgres.Migrations
b.Property<DateTime>("DateTime") b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description") b.Property<string>("Description")
.HasColumnType("text"); .HasColumnType("text");
@@ -172,6 +175,9 @@ namespace MyOffice.Migrations.Postgres.Migrations
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name") b.Property<string>("Name")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");
+2
View File
@@ -30,4 +30,6 @@ export class ApiRoutes {
static Motion = '/api/accounts/:id/motions/:motionId'; static Motion = '/api/accounts/:id/motions/:motionId';
static Items = '/api/items'; static Items = '/api/items';
static Dashboard = '/api/dashboard';
} }
@@ -15,7 +15,7 @@
<h5>Income</h5> <h5>Income</h5>
<p class="text-muted">Income last 7 days</p> <p class="text-muted">Income last 7 days</p>
</div> </div>
<h3 class="text-info">$170</h3> <h3 class="text-info">{{dashboardModel?.incomeLastWeek | number: '1.2-6'}}</h3>
</div> </div>
<div class="card-content mt-2"> <div class="card-content mt-2">
<div class="progress skill-progress m-b-5 w-100"> <div class="progress skill-progress m-b-5 w-100">
@@ -24,9 +24,9 @@
</div> </div>
</div> </div>
</div> </div>
<div class="d-flex justify-content-between mt-2"> <div class="d-flex justify-content-between mt-2" title="{{dashboardModel?.incomePreviousWeek}}">
<p class="text-muted mb-0">Change previous 7 days</p> <p class="text-muted mb-0">Change previous 7 days</p>
<p class="text-muted mb-0">75%</p> <p class="text-muted mb-0">{{dashboardModel?.incomeChange | number: '1.2'}}%</p>
</div> </div>
</div> </div>
</div> </div>
@@ -40,7 +40,7 @@
<h5>Outcome</h5> <h5>Outcome</h5>
<p class="text-muted">Outcome last 7 days</p> <p class="text-muted">Outcome last 7 days</p>
</div> </div>
<h3 class="text-success">$120</h3> <h3 class="text-success">{{dashboardModel?.outcomeLastWeek | number: '1.2-6'}}</h3>
</div> </div>
<div class="card-content mt-2"> <div class="card-content mt-2">
<div class="progress skill-progress m-b-5 w-100"> <div class="progress skill-progress m-b-5 w-100">
@@ -49,9 +49,9 @@
</div> </div>
</div> </div>
</div> </div>
<div class="d-flex justify-content-between mt-2"> <div class="d-flex justify-content-between mt-2" title="{{dashboardModel?.outcomePreviousWeek}}">
<p class="text-muted mb-0">Change previous 7 days</p> <p class="text-muted mb-0">Change previous 7 days</p>
<p class="text-muted mb-0">25%</p> <p class="text-muted mb-0">{{dashboardModel?.outcomeChange | number: '1.2'}}%</p>
</div> </div>
</div> </div>
</div> </div>
@@ -1,4 +1,8 @@
// angular
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// libs
import { import {
ApexAxisChartSeries, ApexAxisChartSeries,
ApexChart, ApexChart,
@@ -16,6 +20,10 @@ import {
ApexNonAxisChartSeries, ApexNonAxisChartSeries,
} from 'ng-apexcharts'; } from 'ng-apexcharts';
// app
import { ApiRoutes } from '../../api-routes';
import { DashboardModel } from '../../model/dashboard.model';
export type ChartOptions = { export type ChartOptions = {
series: ApexAxisChartSeries; series: ApexAxisChartSeries;
series2: ApexNonAxisChartSeries; series2: ApexNonAxisChartSeries;
@@ -43,15 +51,35 @@ export type ChartOptions = {
export class Dashboard2Component implements OnInit { export class Dashboard2Component implements OnInit {
lineChartOptions!: Partial<ChartOptions>; lineChartOptions!: Partial<ChartOptions>;
pieChartOptions!: Partial<ChartOptions>; pieChartOptions!: Partial<ChartOptions>;
dashboardModel?: DashboardModel;
// color: ["#3FA7DC", "#F6A025", "#9BC311"], // color: ["#3FA7DC", "#F6A025", "#9BC311"],
constructor() { constructor(private httpClient: HttpClient) {
//constructor
} }
ngOnInit() { ngOnInit() {
this.chart1(); this.chart1();
this.chart2(); this.chart2();
this.httpClient
.get<DashboardModel>(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() { private chart1() {
@@ -8,4 +8,5 @@ export interface CurrencyModel {
rate?: number, rate?: number,
rateDate?: Date, rateDate?: Date,
isConnected?: boolean, isConnected?: boolean,
isPrimary?: boolean,
} }
@@ -0,0 +1,8 @@
export interface DashboardModel {
incomeLastWeek: number;
incomePreviousWeek: number;
incomeChange: number;
outcomeLastWeek: number;
outcomePreviousWeek: number;
outcomeChange: number;
}
@@ -28,7 +28,7 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let item of myCurrencies"> <tr *ngFor="let item of myCurrencies" [ngClass]="item.isPrimary ? 'bg-purple' : ''">
<td>{{item.code}}</td> <td>{{item.code}}</td>
<td>{{item.name}}</td> <td>{{item.name}}</td>
<td>{{item.shortName}}</td> <td>{{item.shortName}}</td>
@@ -20,6 +20,7 @@ export class SettingsCurrencyComponent {
public currencies?: CurrencyModel[]; public currencies?: CurrencyModel[];
public myCurrencies?: CurrencyModel[]; public myCurrencies?: CurrencyModel[];
public primaryId?: string;
constructor( constructor(
private httpClient: HttpClient, private httpClient: HttpClient,
@@ -74,6 +75,7 @@ export class SettingsCurrencyComponent {
.subscribe(data => { .subscribe(data => {
this.myCurrencies = data.map(myCurrency => { this.myCurrencies = data.map(myCurrency => {
var globalCurrency = this.currencies?.find(x => x.id === myCurrency.code); var globalCurrency = this.currencies?.find(x => x.id === myCurrency.code);
return { return {
id: myCurrency.id, id: myCurrency.id,
code: myCurrency.code, code: myCurrency.code,
@@ -83,6 +85,7 @@ export class SettingsCurrencyComponent {
rateDate: myCurrency.rateDate, rateDate: myCurrency.rateDate,
shortName: myCurrency.shortName, shortName: myCurrency.shortName,
symbol: globalCurrency?.symbol, symbol: globalCurrency?.symbol,
isPrimary: myCurrency.isPrimary,
}; };
}); });
}); });
@@ -64,7 +64,7 @@
<mat-form-field class="example-full-width"> <mat-form-field class="example-full-width">
<mat-label>Rate Date</mat-label> <mat-label>Rate Date</mat-label>
<input matInput [matDatepicker]="picker3" (focus)="picker3.open()" value={{currency.rateDate}} formControlName="rateDate" required> <input matInput [matDatepicker]="picker3" (focus)="picker3.open()" value={{currency.rateDate}} formControlName="rateDate" required>
<mat-hint>YYYY/MM/DD</mat-hint> <mat-hint>DD/MM/YYYY</mat-hint>
<mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle> <mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle>
<mat-datepicker #picker3></mat-datepicker> <mat-datepicker #picker3></mat-datepicker>
<mat-error *ngIf="addForm.controls?.['rateDate']?.hasError('required')"> <mat-error *ngIf="addForm.controls?.['rateDate']?.hasError('required')">
@@ -74,6 +74,15 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row">
<div class="col-md-6">
<div class="text-inside">
<mat-checkbox class="example-margin" formControlName="isPrimary">
Primary currency
</mat-checkbox>
</div>
</div>
</div>
<mat-dialog-actions class="mat-dialog-actions"> <mat-dialog-actions class="mat-dialog-actions">
<div class="mat-dialog-left"> <div class="mat-dialog-left">
<div class="alert alert-danger mat-dialog-error" *ngIf="errorMessage"> <div class="alert alert-danger mat-dialog-error" *ngIf="errorMessage">
@@ -60,6 +60,9 @@ export class SettingsRateCurrencyComponent {
this.currency.rateDate, this.currency.rateDate,
[Validators.required], [Validators.required],
], ],
isPrimary: [
this.currency.isPrimary,
],
}); });
} }
@@ -73,7 +76,6 @@ export class SettingsRateCurrencyComponent {
this.httpClient this.httpClient
.put<CurrencyModel>(ApiRoutes.SettingsCurrency.replace(':id', this.addForm.value.id), this.addForm.value) .put<CurrencyModel>(ApiRoutes.SettingsCurrency.replace(':id', this.addForm.value.id), this.addForm.value)
.subscribe(response => { .subscribe(response => {
console.log(this.addForm.value);
this.httpClient this.httpClient
.post<CurrencyModel[]>(ApiRoutes.SettingsCurrenciesRate.replace(':id', this.addForm.value.id), this.addForm.value) .post<CurrencyModel[]>(ApiRoutes.SettingsCurrenciesRate.replace(':id', this.addForm.value.id), this.addForm.value)
.subscribe(response => { .subscribe(response => {
@@ -83,12 +83,26 @@ public class CurrencyService
exists.Name = currency.Name; exists.Name = currency.Name;
exists.ShortName = currency.ShortName; exists.ShortName = currency.ShortName;
exists.IsPrimary = currency.IsPrimary;
if (!_currencyRepository.Update(exists)) if (!_currencyRepository.Update(exists))
{ {
return result.Set(CurrencyEditStatus.failed); 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); return result.Set(exists);
} }
@@ -4,4 +4,5 @@ public class CurrencyEdit
{ {
public string Name { get; set; } = null!; public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!; public string ShortName { get; set; } = null!;
public bool IsPrimary { get; set; }
} }
@@ -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,
};
}
}
@@ -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<AccountSimple>? 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; }
}*/
@@ -11,8 +11,4 @@
<ProjectReference Include="..\MyOffice.Data.Repositories\MyOffice.Data.Repositories.csproj" /> <ProjectReference Include="..\MyOffice.Data.Repositories\MyOffice.Data.Repositories.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Dashboard\" />
</ItemGroup>
</Project> </Project>
@@ -75,7 +75,7 @@ public class CurrencyController : BaseApiController
var exec = _currencyService.CurrencyUpdate( var exec = _currencyService.CurrencyUpdate(
UserId, UserId,
id.AsGuid(), id.AsGuid(),
new CurrencyEdit { Name = currency.Name, ShortName = currency.ShortName } new CurrencyEdit { Name = currency.Name, ShortName = currency.ShortName, IsPrimary = currency.IsPrimary }
); );
switch (exec.Status) switch (exec.Status)
@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using MyOffice.Services.Account; using MyOffice.Services.Account;
using MyOffice.Services.Item; using MyOffice.Services.Item;
using Services.Dashboard;
[Authorize] [Authorize]
[ApiController] [ApiController]
@@ -11,24 +12,23 @@ using MyOffice.Services.Item;
public class DashboardController : BaseApiController public class DashboardController : BaseApiController
{ {
private readonly ILogger<DashboardController> _logger; private readonly ILogger<DashboardController> _logger;
private readonly DashboardService _dashboardService;
public DashboardController( public DashboardController(
ILogger<DashboardController> logger ILogger<DashboardController> logger,
DashboardService dashboardService
) )
{ {
_logger = logger; _logger = logger;
_dashboardService = dashboardService;
} }
[HttpGet("~/api/accounts")] [HttpGet("~/api/dashboard")]
public object Index() public object Index()
{ {
return new var data = _dashboardService.GetDashboardRestData(UserId);
{
IncomeLastWeek = 100m, return data;
IncomePreviousWeek = 100m,
OutcomeLastWeek = 100m,
OutcomePreviousWeek = 100m,
};
} }
} }
@@ -7,4 +7,5 @@ public class CurrencyEditModel
public int Quantity { get; set; } public int Quantity { get; set; }
public decimal Rate { get; set; } public decimal Rate { get; set; }
public DateTime RateDate { get; set; } public DateTime RateDate { get; set; }
public bool IsPrimary { get; set; }
} }
@@ -14,6 +14,7 @@
public decimal? Rate { get; set; } public decimal? Rate { get; set; }
public int? Quantity { get; set; } public int? Quantity { get; set; }
public DateTime? RateDate { get; set; } public DateTime? RateDate { get; set; }
public bool IsPrimary { get; set; }
} }
public static class CurrencyViewModelExtensions public static class CurrencyViewModelExtensions
@@ -30,6 +31,7 @@
Quantity = rate?.Quantity, Quantity = rate?.Quantity,
Rate = rate?.Rate, Rate = rate?.Rate,
RateDate = rate?.DateTime, RateDate = rate?.DateTime,
IsPrimary = input.IsPrimary,
}; };
} }
} }
+2
View File
@@ -40,6 +40,7 @@ using IdentityServer4.Services;
using MyOffice.Services.Currency; using MyOffice.Services.Currency;
using Services.Account; using Services.Account;
using Services.Item; using Services.Item;
using MyOffice.Services.Dashboard;
public class Program public class Program
{ {
@@ -229,6 +230,7 @@ public class Program
builder.Services.AddScoped<CurrencyService, CurrencyService>(); builder.Services.AddScoped<CurrencyService, CurrencyService>();
builder.Services.AddScoped<AccountService, AccountService>(); builder.Services.AddScoped<AccountService, AccountService>();
builder.Services.AddScoped<ItemService, ItemService>(); builder.Services.AddScoped<ItemService, ItemService>();
builder.Services.AddScoped<DashboardService, DashboardService>();
} }
private static readonly ConcurrentDictionary<string, PhysicalFileInfo> _staticFilesCache = new(); private static readonly ConcurrentDictionary<string, PhysicalFileInfo> _staticFilesCache = new();