This commit is contained in:
2023-06-21 17:56:00 +03:00
parent fa8852a32a
commit e9d4053e65
55 changed files with 3883 additions and 262 deletions
@@ -0,0 +1,19 @@
namespace MyOffice.Core.Extensions;
public static class DateTimeExtensions
{
public static DateTime StartOfDay(this DateTime dateTime)
{
return dateTime.Date;
}
public static DateTime EndOfDay(this DateTime dateTime)
{
return dateTime.AddDays(1).AddTicks(-1);
}
public static DateTime ToUtc(this DateTime dateTime)
{
return new DateTime(dateTime.Ticks, DateTimeKind.Utc);
}
}
@@ -1,5 +1,6 @@
namespace MyOffice.Data.Repositories.Account; namespace MyOffice.Data.Repositories.Account;
using Microsoft.EntityFrameworkCore;
using Models.Accounts; using Models.Accounts;
public class AccountMotionRepository : AppRepository<AccountMotion>, IAccountMotionRepository public class AccountMotionRepository : AppRepository<AccountMotion>, IAccountMotionRepository
@@ -8,4 +9,16 @@ public class AccountMotionRepository : AppRepository<AccountMotion>, IAccountMot
{ {
return AddBase(accountMotion) > 0; return AddBase(accountMotion) > 0;
} }
public List<AccountMotion> GetByAccount(Guid accountId, DateTime dateFrom, DateTime dateTo)
{
return _context
.AccountMotions
.Include(x => x.Motion)
.ThenInclude(x => x.MotionGlobal)
.Where(x => x.AccountId == accountId && x.DateTime >= dateFrom && x.DateTime <= dateTo)
.OrderByDescending(x => x.DateTime)
.ThenByDescending(x => x.CreatedOn)
.ToList();
}
} }
@@ -43,11 +43,29 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
{ {
Account = x, Account = x,
TotalPlus = x.Motions!.Sum(m => m.AmountPlus), TotalPlus = x.Motions!.Sum(m => m.AmountPlus),
TotalMinus = x.Motions!.Sum(m => m.AmountPlus), TotalMinus = x.Motions!.Sum(m => m.AmountMinus),
}) })
.ToList(); .ToList();
} }
public AccountDetailed? GetByIdDetailed(Guid userId, Guid id)
{
return _context.Accounts!
.Include(x => x.CurrencyGlobal)
.Include(x => x.Categories)!
.ThenInclude(x => x.Category)
.Include(x => x.AccessRights)!
.ThenInclude(x => x.User)
.Where(x => x.Id == id && x.AccessRights!.Any(a => a.UserId == userId))
.Select(x => new AccountDetailed
{
Account = x,
TotalPlus = x.Motions!.Sum(m => m.AmountPlus),
TotalMinus = x.Motions!.Sum(m => m.AmountMinus),
})
.FirstOrDefault();
}
public bool Add(Account account) public bool Add(Account account)
{ {
return AddBase(account) > 0; return AddBase(account) > 0;
@@ -5,4 +5,5 @@ using Models.Accounts;
public interface IAccountMotionRepository public interface IAccountMotionRepository
{ {
bool Add(AccountMotion accountMotion); bool Add(AccountMotion accountMotion);
List<AccountMotion> GetByAccount(Guid accountId, DateTime dateFrom, DateTime dateTo);
} }
@@ -7,6 +7,7 @@ public interface IAccountRepository
List<Account> GetAll(Guid userId); List<Account> GetAll(Guid userId);
List<Account> GetByCategory(Guid userId, Guid categoryId); List<Account> GetByCategory(Guid userId, Guid categoryId);
List<AccountDetailed> GetByCategoryDetailed(Guid userId, Guid categoryId); List<AccountDetailed> GetByCategoryDetailed(Guid userId, Guid categoryId);
AccountDetailed? GetByIdDetailed(Guid userId, Guid id);
bool Add(Account account); bool Add(Account account);
Account? Get(Guid userId, Guid id); Account? Get(Guid userId, Guid id);
bool Update(Account account); bool Update(Account account);
@@ -16,7 +16,10 @@ public class CurrencyRepository : AppRepository<Currency>, ICurrencyRepository
public Currency? Get(Guid userId, Guid id) public Currency? Get(Guid userId, Guid id)
{ {
return _context.Currencies.FirstOrDefault(x => x.Id == id && x.UserId == userId); return _context
.Currencies
.Include(x => x.CurrencyGlobal)
.FirstOrDefault(x => x.Id == id && x.UserId == userId);
} }
public Currency? GetByGlobalCurrency(Guid userId, string globalCurrencyId) public Currency? GetByGlobalCurrency(Guid userId, string globalCurrencyId)
+8
View File
@@ -205,5 +205,13 @@ public class AppDbContext : DbContext
.HasOne(x => x.Account) .HasOne(x => x.Account)
.WithMany(x => x.Motions) .WithMany(x => x.Motions)
.HasForeignKey(x => x.AccountId); .HasForeignKey(x => x.AccountId);
modelBuilder.Entity<AccountMotion>()
.Property(x => x.AmountMinus)
.HasPrecision(18, 6);
modelBuilder.Entity<AccountMotion>()
.Property(x => x.AmountPlus)
.HasPrecision(18, 6);
} }
} }
@@ -35,6 +35,10 @@ public class RepositoryInitializer
new() { Id = "EUR", DefaultQuantity = 1, Symbol = "€", Name = "Euros" }, new() { Id = "EUR", DefaultQuantity = 1, Symbol = "€", Name = "Euros" },
new() { Id = "GBP", DefaultQuantity = 1, Symbol = "£", Name = "British pounds sterling" }, new() { Id = "GBP", DefaultQuantity = 1, Symbol = "£", Name = "British pounds sterling" },
new() { Id = "RUB", DefaultQuantity = 10, Symbol = "₽", Name = "Russia Ruble" }, new() { Id = "RUB", DefaultQuantity = 10, Symbol = "₽", Name = "Russia Ruble" },
new() { Id = "BTC", DefaultQuantity = 10, Symbol = "btc", Name = "Bitcoin" },
new() { Id = "ETH", DefaultQuantity = 10, Symbol = "eth", Name = "Ethereum" },
new() { Id = "TON", DefaultQuantity = 10, Symbol = "ton", Name = "TON" },
new() { Id = "OTHER", DefaultQuantity = 1, Symbol = "₽", Name = "Other" },
}; };
var currencyGlobals = dbContext.CurrencyGlobals.ToList(); var currencyGlobals = dbContext.CurrencyGlobals.ToList();
@@ -0,0 +1,533 @@
// <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("20230617113630_MotionAccountFix")]
partial class MotionAccountFix
{
/// <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.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
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.Motions.MotionAccount", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("MotionGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("MotionGlobalId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", 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("MotionCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("GlobalMotions");
});
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.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.Motions.MotionAccount", b =>
{
b.HasOne("MyOffice.Data.Models.Motions.MotionCategory", "Category")
.WithMany("Motions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionGlobal", "MotionGlobal")
.WithMany("Motions")
.HasForeignKey("MotionGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("MotionGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("MotionCategories")
.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");
});
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.Motions.MotionCategory", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("Currencies");
b.Navigation("MotionCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,75 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class MotionAccountFix : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AccountMotions");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AccountMotions",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
MotionId = table.Column<int>(type: "integer", nullable: false),
AmountMinus = table.Column<decimal>(type: "numeric", nullable: false),
AmountPlus = table.Column<decimal>(type: "numeric", nullable: false),
CreatedOn = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DateTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Description = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AccountMotions", x => x.Id);
table.ForeignKey(
name: "FK_AccountMotions_Accounts_AccountId",
column: x => x.AccountId,
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AccountMotions_Motions_MotionId",
column: x => x.MotionId,
principalTable: "Motions",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AccountMotions_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_AccountMotions_AccountId",
table: "AccountMotions",
column: "AccountId");
migrationBuilder.CreateIndex(
name: "IX_AccountMotions_MotionId",
table: "AccountMotions",
column: "MotionId");
migrationBuilder.CreateIndex(
name: "IX_AccountMotions_UserId",
table: "AccountMotions",
column: "UserId");
}
}
}
@@ -0,0 +1,606 @@
// <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("20230617114210_MotionAccountFix2")]
partial class MotionAccountFix2
{
/// <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.AccountMotion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasColumnType("numeric");
b.Property<decimal>("AmountPlus")
.HasColumnType("numeric");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("MotionId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("MotionId");
b.HasIndex("UserId");
b.ToTable("AccountMotions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
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.Motions.MotionAccount", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("MotionGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("MotionGlobalId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", 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("MotionCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("GlobalMotions");
});
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.AccountMotion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionAccount", "Motion")
.WithMany("Motions")
.HasForeignKey("MotionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Motion");
});
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.Motions.MotionAccount", b =>
{
b.HasOne("MyOffice.Data.Models.Motions.MotionCategory", "Category")
.WithMany("Motions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionGlobal", "MotionGlobal")
.WithMany("Motions")
.HasForeignKey("MotionGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("MotionGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("MotionCategories")
.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.Motions.MotionAccount", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("MotionCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,73 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class MotionAccountFix2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AccountMotions",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CreatedOn = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DateTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
MotionId = table.Column<int>(type: "integer", nullable: false),
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
Description = table.Column<string>(type: "text", nullable: true),
AmountPlus = table.Column<decimal>(type: "numeric", nullable: false),
AmountMinus = table.Column<decimal>(type: "numeric", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AccountMotions", x => x.Id);
table.ForeignKey(
name: "FK_AccountMotions_Accounts_AccountId",
column: x => x.AccountId,
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AccountMotions_Motions_MotionId",
column: x => x.MotionId,
principalTable: "Motions",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AccountMotions_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_AccountMotions_AccountId",
table: "AccountMotions",
column: "AccountId");
migrationBuilder.CreateIndex(
name: "IX_AccountMotions_MotionId",
table: "AccountMotions",
column: "MotionId");
migrationBuilder.CreateIndex(
name: "IX_AccountMotions_UserId",
table: "AccountMotions",
column: "UserId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AccountMotions");
}
}
}
@@ -0,0 +1,607 @@
// <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("20230621082718_MotionPrec")]
partial class MotionPrec
{
/// <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.AccountMotion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(6)
.HasColumnType("numeric(6)");
b.Property<decimal>("AmountPlus")
.HasColumnType("numeric");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("MotionId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("MotionId");
b.HasIndex("UserId");
b.ToTable("AccountMotions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
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.Motions.MotionAccount", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("MotionGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("MotionGlobalId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", 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("MotionCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("GlobalMotions");
});
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.AccountMotion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionAccount", "Motion")
.WithMany("Motions")
.HasForeignKey("MotionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Motion");
});
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.Motions.MotionAccount", b =>
{
b.HasOne("MyOffice.Data.Models.Motions.MotionCategory", "Category")
.WithMany("Motions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionGlobal", "MotionGlobal")
.WithMany("Motions")
.HasForeignKey("MotionGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("MotionGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("MotionCategories")
.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.Motions.MotionAccount", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("MotionCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,36 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class MotionPrec : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<decimal>(
name: "AmountMinus",
table: "AccountMotions",
type: "numeric(6)",
precision: 6,
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<decimal>(
name: "AmountMinus",
table: "AccountMotions",
type: "numeric",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(6)",
oldPrecision: 6);
}
}
}
@@ -0,0 +1,607 @@
// <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("20230621083359_MotionPrec2")]
partial class MotionPrec2
{
/// <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.AccountMotion", 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")
.HasColumnType("numeric");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("MotionId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("MotionId");
b.HasIndex("UserId");
b.ToTable("AccountMotions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
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.Motions.MotionAccount", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("MotionGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("MotionGlobalId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", 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("MotionCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("GlobalMotions");
});
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.AccountMotion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionAccount", "Motion")
.WithMany("Motions")
.HasForeignKey("MotionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Motion");
});
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.Motions.MotionAccount", b =>
{
b.HasOne("MyOffice.Data.Models.Motions.MotionCategory", "Category")
.WithMany("Motions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionGlobal", "MotionGlobal")
.WithMany("Motions")
.HasForeignKey("MotionGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("MotionGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("MotionCategories")
.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.Motions.MotionAccount", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("MotionCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class MotionPrec2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<decimal>(
name: "AmountMinus",
table: "AccountMotions",
type: "numeric(18,6)",
precision: 18,
scale: 6,
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(6,0)",
oldPrecision: 6);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<decimal>(
name: "AmountMinus",
table: "AccountMotions",
type: "numeric(6,0)",
precision: 6,
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(18,6)",
oldPrecision: 18,
oldScale: 6);
}
}
}
@@ -0,0 +1,608 @@
// <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("20230621083446_MotionPrec3")]
partial class MotionPrec3
{
/// <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.AccountMotion", 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<string>("Description")
.HasColumnType("text");
b.Property<int>("MotionId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("MotionId");
b.HasIndex("UserId");
b.ToTable("AccountMotions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
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.Motions.MotionAccount", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("MotionGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("MotionGlobalId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", 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("MotionCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("GlobalMotions");
});
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.AccountMotion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionAccount", "Motion")
.WithMany("Motions")
.HasForeignKey("MotionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Motion");
});
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.Motions.MotionAccount", b =>
{
b.HasOne("MyOffice.Data.Models.Motions.MotionCategory", "Category")
.WithMany("Motions")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.MotionGlobal", "MotionGlobal")
.WithMany("Motions")
.HasForeignKey("MotionGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("MotionGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("MotionCategories")
.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.Motions.MotionAccount", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionCategory", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.MotionGlobal", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("MotionCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class MotionPrec3 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<decimal>(
name: "AmountPlus",
table: "AccountMotions",
type: "numeric(18,6)",
precision: 18,
scale: 6,
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<decimal>(
name: "AmountPlus",
table: "AccountMotions",
type: "numeric",
nullable: false,
oldClrType: typeof(decimal),
oldType: "numeric(18,6)",
oldPrecision: 18,
oldScale: 6);
}
}
}
@@ -121,20 +121,20 @@ namespace MyOffice.Migrations.Postgres.Migrations
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountMotion", b => modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountMotion", b =>
{ {
b.Property<long>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint"); .HasColumnType("uuid");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<Guid>("AccountId") b.Property<Guid>("AccountId")
.HasColumnType("uuid"); .HasColumnType("uuid");
b.Property<decimal>("AmountMinus") b.Property<decimal>("AmountMinus")
.HasColumnType("numeric"); .HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus") b.Property<decimal>("AmountPlus")
.HasColumnType("numeric"); .HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn") b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
+1
View File
@@ -7,6 +7,7 @@ export class ApiRoutes {
static GeneralCurrencies = '/api/general/currencies'; static GeneralCurrencies = '/api/general/currencies';
static SettingsCurrencies = '/api/settings/currencies'; static SettingsCurrencies = '/api/settings/currencies';
static SettingsCurrency = '/api/settings/currencies/:id';
static SettingsCurrenciesRate = '/api/settings/currencies/:id/rate'; static SettingsCurrenciesRate = '/api/settings/currencies/:id/rate';
static SettingsAccountCategories = '/api/settings/account-categories'; static SettingsAccountCategories = '/api/settings/account-categories';
@@ -24,10 +24,10 @@ export class ErrorInterceptor implements HttpInterceptor {
this.authenticationService.logout(); this.authenticationService.logout();
location.reload(); location.reload();
} }
console.log(err);
const error = err.error.message || err.statusText; const error = err.message || err.error.message || err.statusText;
//return throwError(error); return throwError(error);
return throwError(err.error || err); //return throwError(err.error || err);
}) })
); );
} }
@@ -1,3 +1,4 @@
// angular
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { HttpInterceptor } from '@angular/common/http'; import { HttpInterceptor } from '@angular/common/http';
@@ -5,6 +6,9 @@ import { HttpRequest } from '@angular/common/http';
import { HttpHandler } from '@angular/common/http'; import { HttpHandler } from '@angular/common/http';
import { HttpEvent } from '@angular/common/http'; import { HttpEvent } from '@angular/common/http';
// libs
import * as moment from 'moment';
@Injectable() @Injectable()
export class UpdateDateHttpInterceptor implements HttpInterceptor { export class UpdateDateHttpInterceptor implements HttpInterceptor {
@@ -29,12 +33,7 @@ export class UpdateDateHttpInterceptor implements HttpInterceptor {
for (const key of Object.keys(body)) { for (const key of Object.keys(body)) {
const value = body[key]; const value = body[key];
if (value instanceof Date) { if (value instanceof Date) {
body[key] = new Date(Date.UTC(value.getFullYear(), body[key] = moment(value).utcOffset(0, true).format();
value.getMonth(),
value.getDate(),
value.getHours(),
value.getMinutes(),
value.getSeconds()));
} else if (typeof value === 'object') { } else if (typeof value === 'object') {
this.shiftDates(value); this.shiftDates(value);
} }
@@ -86,6 +86,7 @@ export class SidebarComponent implements OnInit, OnDestroy {
.getCategories() .getCategories()
.subscribe(categories => { .subscribe(categories => {
var accounts = this.sidebarItems.filter(x => x.id === 'accounts'); var accounts = this.sidebarItems.filter(x => x.id === 'accounts');
accounts[0].submenu = [];
for (var category of categories) { for (var category of categories) {
accounts[0].submenu.push({ accounts[0].submenu.push({
path: '/account-category/' + category.id, path: '/account-category/' + category.id,
@@ -1,30 +1,44 @@
<section class="content"> <mat-expansion-panel [expanded]="expanded">
<div class="content-block"> <mat-expansion-panel-header>
<div class="block-header"> <mat-panel-description>
<!-- breadcrumb --> <h4>{{account.account.name}}</h4>
<app-breadcrumb [title]="'Blank'" [items]="['Home','Settings']" [active_item]="'Accounts'"> <h4>
</app-breadcrumb> {{account.rest | number: '1.2-6'}}
</div> ({{account.account.currencyId}})
<div class="row clearfix"> </h4>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12"> </mat-panel-description>
<mat-accordion class="main-headers-align" multi> </mat-expansion-panel-header>
<mat-expansion-panel *ngFor="let account of accounts; let i = index" [expanded]="i === 0" > <form [formGroup]="form!" (ngSubmit)="onSubmitClick()">
<mat-expansion-panel-header> <div class="row">
<mat-panel-description> <div class="col-md-6">
<div>{{account.account.name}}</div> <mat-form-field class="example-full-width" appearance="fill">
<div> <mat-label>From</mat-label>
{{account.rest}} <input matInput [matDatepicker]="pickerFrom" (focus)="pickerFrom.open()" formControlName="dateFrom" required>
({{account.account.currencyId}}) <mat-hint>YYYY/MM/DD</mat-hint>
</div> <mat-datepicker-toggle tabindex="-1" matSuffix [for]="pickerFrom"></mat-datepicker-toggle>
</mat-panel-description> <mat-datepicker #pickerFrom></mat-datepicker>
</mat-expansion-panel-header> <mat-error *ngIf="form.controls?.['dateFrom']?.hasError('required')">
<account-motion [motion]="newMotion"> Please enter rate date
</account-motion> </mat-error>
<account-motion *ngFor="let motion of motions" [motion]="motion"> </mat-form-field>
</account-motion> </div>
</mat-expansion-panel> <div class="col-md-6">
</mat-accordion> <mat-form-field class="example-full-width" appearance="fill">
<mat-label>To</mat-label>
<input matInput [matDatepicker]="pickerTo" (focus)="pickerTo.open()" formControlName="dateTo" required>
<mat-hint>YYYY/MM/DD</mat-hint>
<mat-datepicker-toggle tabindex="-1" matSuffix [for]="pickerTo"></mat-datepicker-toggle>
<mat-datepicker #pickerTo></mat-datepicker>
<mat-error *ngIf="form.controls?.['dateTo']?.hasError('required')">
Please enter rate date
</mat-error>
</mat-form-field>
</div> </div>
</div> </div>
</div> </form>
</section> <hr/>
<account-motion [motion]="newMotion" [account]="account.account" (onAdd)="handlerOnAdd($event)">
</account-motion>
<account-motion *ngFor="let motion of motions" [motion]="motion" [account]="account.account">
</account-motion>
</mat-expansion-panel>
@@ -1,91 +1,99 @@
// angular // angular
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Input } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { UntypedFormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';
import { UntypedFormBuilder } from '@angular/forms';
import { Output } from '@angular/core';
import { EventEmitter } from '@angular/core';
// libs // libs
import Swal from 'sweetalert2'; import * as moment from 'moment';
import { MatDialog } from '@angular/material/dialog';
// app // app
import { AccountCategoryService } from '../../services/account.category.service';
import { ApiRoutes } from '../../api-routes'; import { ApiRoutes } from '../../api-routes';
import { AccountCategoryModel } from '../../model/account.category.model';
import { SettingsAccountAddComponent } from '../settings/account/add.account.component';
import { SettingsAccountEditComponent } from '../settings/account/edit.account.component';
import { AccountModel } from '../../model/account.model';
import { AccountDetailedModel } from '../../model/account.detailed.model'; import { AccountDetailedModel } from '../../model/account.detailed.model';
import { AccountMotionModel } from '../../model/account.motion'; import { AccountMotionModel } from '../../model/account.motion';
@Component({ @Component({
templateUrl: './account.component.html', templateUrl: './account.component.html',
styleUrls: ['./account.component.scss'], styleUrls: ['./account.component.scss'],
selector: 'account'
}) })
export class AccountComponent { export class AccountComponent {
public accounts?: AccountDetailedModel[];
public motions?: AccountMotionModel[]; public motions?: AccountMotionModel[];
public newMotion: AccountMotionModel; public newMotion: AccountMotionModel;
public form!: UntypedFormGroup;
@Input('account') account!: AccountDetailedModel;
@Input('expanded') expanded!: boolean;
@Output() onUpdate: EventEmitter<AccountMotionModel> = new EventEmitter<AccountMotionModel>();
constructor( constructor(
private fb: UntypedFormBuilder,
private httpClient: HttpClient, private httpClient: HttpClient,
private dialogModel: MatDialog,
private activatedRoute: ActivatedRoute private activatedRoute: ActivatedRoute
) { ) {
this.newMotion = { this.newMotion = {
date: new Date(), date: new Date(),
plus: 0,
minus: 0,
}; };
} }
ngOnInit(): void { ngOnInit(): void {
this.form = this.fb.group({
dateFrom: [
moment(new Date).add(-7, 'days').toDate(),
[Validators.required],
],
dateTo: [
new Date,
[Validators.required],
],
});
this.loadMotions();
}
onSubmitClick() {
}
handlerOnAdd(accountMotion: AccountMotionModel) {
this.loadMotions();
this.httpClient
.get<AccountDetailedModel>(ApiRoutes.Account.replace(':id', this.account.account!.id!))
.subscribe(data => {
this.account = data;
});
/*var md = moment(accountMotion.date);
var mdf = moment(this.form.value.dateFrom);
var mdt = moment(this.form.value.dateTo);
if (md.isBetween(mdf, mdt, 'days', '[]')) {
this.motions?.push(accountMotion);
//this.motions?.sort((a, b) => (b.date!.getMilliseconds() - a.date!.getMilliseconds()));
this.motions?.sort((a, b) => {
var aa = moment(a.date).toDate();
var bb = moment(b.date).toDate();
return (bb.getMilliseconds() - aa.getMilliseconds());
});
}*/
}
private loadMotions() {
var url = ApiRoutes.Motions.replace(':id', this.account.account.id!);
url += '?from=' + moment(this.form.value.dateFrom).format('yyyy-MM-DD');
url += '&to=' + moment(this.form.value.dateTo).format('yyyy-MM-DD');
this.activatedRoute.params.subscribe(params => { this.activatedRoute.params.subscribe(params => {
this.httpClient this.httpClient
.get<AccountDetailedModel[]>(ApiRoutes.Accounts + "?category=" + params['id']) .get<AccountMotionModel[]>(url)
.subscribe(data => { .subscribe(data => {
this.accounts = data; this.motions = data;
}); });
}); });
} }
/*private loadAccounts() {
}*/
/*private loadCategories() {
this.accountCategoryService
.getCategories()
.subscribe(x => {
this.accountCategories = x;
this.loadAccounts();
});
}*/
/*public accountInCategory(category?: AccountCategoryModel) {
if (this.accounts) {
return this.accounts.filter(acc => (!category && (!acc.categories || acc.categories.length === 0)) || (category && acc.categories && acc.categories.filter(cat => cat.id === category.id).length > 0));
}
return null;
}*/
/*public add() {
this.dialogModel.open(SettingsAccountAddComponent, {
width: '640px',
disableClose: true,
data: this.accounts,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
this.loadAccounts();
}
});
}*/
/*public edit(account: AccountModel) {
this.dialogModel.open(SettingsAccountEditComponent, {
width: '640px',
disableClose: true,
data: account,
}).afterClosed().subscribe(x => {
if (x && x.refresh) {
this.loadAccounts();
}
});
}*/
} }
@@ -0,0 +1,18 @@
<section class="content">
<div class="content-block">
<div class="block-header">
<!-- breadcrumb -->
<app-breadcrumb [title]="'Blank'" [items]="['Home', 'Accounts']" [active_item]="category">
</app-breadcrumb>
</div>
<div class="row clearfix">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<mat-accordion class="main-headers-align" multi>
<div *ngFor="let account of accounts; let i = index" >
<account [account]="account" />
</div>
</mat-accordion>
</div>
</div>
</div>
</section>
@@ -0,0 +1,51 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
// libs
import Swal from 'sweetalert2';
import { MatDialog } from '@angular/material/dialog';
// app
import { AccountCategoryService } from '../../services/account.category.service';
import { ApiRoutes } from '../../api-routes';
import { AccountCategoryModel } from '../../model/account.category.model';
import { SettingsAccountAddComponent } from '../settings/account/add.account.component';
import { SettingsAccountEditComponent } from '../settings/account/edit.account.component';
import { AccountModel } from '../../model/account.model';
import { AccountDetailedModel } from '../../model/account.detailed.model';
import { AccountMotionModel } from '../../model/account.motion';
@Component({
templateUrl: './account.list.component.html',
styleUrls: ['./account.list.component.scss'],
})
export class AccountListComponent {
public accounts?: AccountDetailedModel[];
public category = '';
constructor(
private httpClient: HttpClient,
private activatedRoute: ActivatedRoute,
private accountCategoryService: AccountCategoryService,
) {
}
ngOnInit(): void {
this.activatedRoute.params.subscribe(params => {
var categoryId = params['id'];
this.httpClient
.get<AccountDetailedModel[]>(ApiRoutes.Accounts + '?category=' + categoryId)
.subscribe(data => {
this.accounts = data;
});
this.accountCategoryService
.getCategory(categoryId)
.subscribe(data => {
this.category = data.name!;
});
});
}
}
@@ -1,6 +1,6 @@
<form [formGroup]="form!" (ngSubmit)="onSubmitClick()"> <form [formGroup]="form" (ngSubmit)="onSubmitClick()" novalidate autocomplete="off">
<div class="row"> <div class="" style="display: flex;">
<div class="col-md-4"> <div class="" style="width: 310px; min-width: 310px;">
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center;">
<a href="javascript:void(0)" matSuffix (click)="addDay(-1)"> <a href="javascript:void(0)" matSuffix (click)="addDay(-1)">
<i class="material-icons font-40">arrow_back</i> <i class="material-icons font-40">arrow_back</i>
@@ -21,15 +21,19 @@
</a> </a>
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="" style="flex-grow: 1;">
<mat-form-field class="example-full-width" appearance="fill"> <mat-form-field class="example-full-width" appearance="fill">
<input matInput formControlName="motion"> <mat-label>Motion</mat-label>
<input #motionInput matInput formControlName="motion" required>
<mat-error *ngIf="form.controls['motion'].hasError('required')">
Please enter motion
</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="example-full-width" appearance="fill"> <mat-form-field class="example-full-width" appearance="fill">
<input matInput formControlName="description"> <input matInput formControlName="description">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-md-2"> <div class="" style="width: 100px; min-width: 100px;">
<mat-form-field class="example-full-width" appearance="fill"> <mat-form-field class="example-full-width" appearance="fill">
<input matInput [value]="motion.plus | number:'0.2-2'" formControlName="plus" currencyMask [options]="{ prefix: '', precision: 4, inputMode: 1 }"> <input matInput [value]="motion.plus | number:'0.2-2'" formControlName="plus" currencyMask [options]="{ prefix: '', precision: 4, inputMode: 1 }">
</mat-form-field> </mat-form-field>
@@ -37,19 +41,20 @@
<input matInput [value]="motion.minus | number:'0.2-2'" formControlName="minus" currencyMask [options]="{ prefix: '', precision: 4, inputMode: 1 }"> <input matInput [value]="motion.minus | number:'0.2-2'" formControlName="minus" currencyMask [options]="{ prefix: '', precision: 4, inputMode: 1 }">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-md-2 mb-2"> <div class="" style="display: inline-block; width: 150px; min-width: 150px;">
<a *ngIf="!motion.id" href="javascript:void(0)" (click)="onSubmitClick()"> <button type="button" mat-stroked-button color="primary" *ngIf="!motion.id" (click)="onSubmitClick()">
<i class="material-icons font-40">add</i> <i class="material-icons font-40">add</i>
</a> </button>
<a *ngIf="!motion.id" href="javascript:void(0)" (click)="onSubmitClick()"> <button mat-stroked-button color="primary" *ngIf="!motion.id" (click)="onSubmitClick()">
<i class="material-icons font-40">import_export</i> <i class="material-icons font-40">import_export</i>
</a> </button>
<a *ngIf="motion.id" href="javascript:void(0)" (click)="onSubmitClick()"> <button mat-stroked-button color="primary" *ngIf="motion.id" (click)="onSubmitClick()">
<i class="material-icons font-40">save</i> <i class="material-icons font-40">save</i>
</a> </button>
<a *ngIf="motion.id" href="javascript:void(0)" (click)="onSubmitClick()"> <button mat-stroked-button color="primary" *ngIf="motion.id" (click)="onSubmitClick()">
<i class="material-icons font-40">delete</i> <i class="material-icons font-40">delete</i>
</a> </button>
</div> </div>
</div> </div>
<hr/>
</form> </form>
@@ -1,29 +1,22 @@
// angular // angular
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router'; import { FormBuilder } from '@angular/forms';
import { UntypedFormBuilder } from '@angular/forms'; import { FormGroup } from '@angular/forms';
import { Validators } from '@angular/forms'; import { Validators } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { Input } from '@angular/core'; import { Input } from '@angular/core';
import { Output } from '@angular/core'; import { Output } from '@angular/core';
import { EventEmitter } from '@angular/core'; import { EventEmitter } from '@angular/core';
import { ViewChild } from '@angular/core';
import { ElementRef } from '@angular/core';
// libs // libs
import Swal from 'sweetalert2';
import { MatDialog } from '@angular/material/dialog';
import * as moment from 'moment'; import * as moment from 'moment';
// app // app
import { AccountCategoryService } from '../../services/account.category.service';
import { ApiRoutes } from '../../api-routes'; import { ApiRoutes } from '../../api-routes';
import { AccountCategoryModel } from '../../model/account.category.model';
import { SettingsAccountAddComponent } from '../settings/account/add.account.component';
import { SettingsAccountEditComponent } from '../settings/account/edit.account.component';
import { AccountModel } from '../../model/account.model'; import { AccountModel } from '../../model/account.model';
import { AccountDetailedModel } from '../../model/account.detailed.model';
import { AccountMotionModel } from '../../model/account.motion'; import { AccountMotionModel } from '../../model/account.motion';
import { atLeastOne } from '../../core/validators/atleastone.validator';
import { atLeastOneNumber } from '../../core/validators/atleastonenumber.validator'; import { atLeastOneNumber } from '../../core/validators/atleastonenumber.validator';
@Component({ @Component({
@@ -32,16 +25,19 @@ import { atLeastOneNumber } from '../../core/validators/atleastonenumber.validat
styleUrls: ['./motion.component.scss'], styleUrls: ['./motion.component.scss'],
}) })
export class MotionComponent { export class MotionComponent {
public form!: UntypedFormGroup; public form!: FormGroup;
public errorMessage?: string; public errorMessage?: string;
@Input() motion!: AccountMotionModel; @Input('motion') motion!: AccountMotionModel;
@Input('account') account!: AccountModel;
@Output() onAdd: EventEmitter<AccountMotionModel> = new EventEmitter<AccountMotionModel>();
@ViewChild('motionInput') motionInput?: ElementRef;
constructor( constructor(
private fb: UntypedFormBuilder, private fb: FormBuilder,
private httpClient: HttpClient, private httpClient: HttpClient,
private dialogModel: MatDialog,
private activatedRoute: ActivatedRoute
) { ) {
} }
@@ -67,14 +63,29 @@ export class MotionComponent {
minus: [ minus: [
this.motion.minus, this.motion.minus,
], ],
}, { validator: atLeastOneNumber(Validators.required, ['plus', 'minus']) }); }, {
validator: atLeastOneNumber(Validators.required, ['plus', 'minus'])
});
} }
onSubmitClick() { onSubmitClick() {
this.form.markAllAsTouched();
if (this.form.valid) { if (this.form.valid) {
this.httpClient this.httpClient
.post<AccountMotionModel[]>(ApiRoutes.SettingsCurrencies, this.form.value) .post<AccountMotionModel>(ApiRoutes.Motions.replace(':id', this.account.id!), this.form.value)
.subscribe(response => { .subscribe(response => {
if (!this.form.value.id) {
this.onAdd?.emit(response);
this.form.patchValue({
motion: '',
plus: 0,
minus: 0,
});
this.form.markAsUntouched();
this.motionInput?.nativeElement.focus();
}
}, error => { }, error => {
this.errorMessage = error.detail; this.errorMessage = error.detail;
}); });
@@ -6,7 +6,7 @@ import { SettingsAccountCategoryComponent } from './settings/account/account.cat
import { SettingsAccountComponent } from './settings/account/account.component'; import { SettingsAccountComponent } from './settings/account/account.component';
import { SettingsMotionCategoryComponent } from './settings/motion/motion.category.component'; import { SettingsMotionCategoryComponent } from './settings/motion/motion.category.component';
import { SettingsMotionComponent } from './settings/motion/motion.component'; import { SettingsMotionComponent } from './settings/motion/motion.component';
import { AccountComponent } from './accounts/account.component'; import { AccountListComponent as AccountComponent } from './accounts/account.list.component';
const routes: Routes = [ const routes: Routes = [
{ {
@@ -36,6 +36,7 @@ import { MotionService } from '../services/motion.service';
import { SettingsMotionCategoryComponent } from './settings/motion/motion.category.component'; import { SettingsMotionCategoryComponent } from './settings/motion/motion.category.component';
import { SettingsMotionComponent } from './settings/motion/motion.component'; import { SettingsMotionComponent } from './settings/motion/motion.component';
import { SettingsMotionEditComponent } from './settings/motion/edit.motion.component'; import { SettingsMotionEditComponent } from './settings/motion/edit.motion.component';
import { AccountListComponent } from './accounts/account.list.component';
import { AccountComponent } from './accounts/account.component'; import { AccountComponent } from './accounts/account.component';
import { MotionComponent } from './accounts/motion.component'; import { MotionComponent } from './accounts/motion.component';
@@ -56,6 +57,7 @@ import { MotionComponent } from './accounts/motion.component';
SettingsMotionComponent, SettingsMotionComponent,
SettingsMotionEditComponent, SettingsMotionEditComponent,
AccountListComponent,
AccountComponent, AccountComponent,
MotionComponent, MotionComponent,
], ],
@@ -16,10 +16,22 @@
<mat-tab label="My currencies"> <mat-tab label="My currencies">
<div class="body table-responsive"> <div class="body table-responsive">
<table class="table"> <table class="table">
<thead>
<tr>
<th>Code</th>
<th>Name</th>
<th>Short Name</th>
<th>Quantity</th>
<th>Rate</th>
<th>Rate Date</th>
<th></th>
</tr>
</thead>
<tbody> <tbody>
<tr *ngFor="let item of myCurrencies"> <tr *ngFor="let item of myCurrencies">
<td>{{item.code}}</td> <td>{{item.code}}</td>
<td>{{item.name}}</td> <td>{{item.name}}</td>
<td>{{item.shortName}}</td>
<td style="text-align: end"> <td style="text-align: end">
{{item.quantity}} {{item.quantity}}
</td> </td>
@@ -27,10 +39,10 @@
{{item.rate | number: '1.2-6'}} {{item.rate | number: '1.2-6'}}
{{item.symbol}} {{item.symbol}}
</td> </td>
<td>{{item.rateDate | date:'yyyy-MM-dd'}}</td> <td>{{item.rateDate | date:'yyyy-MM-dd'}}</td>
<td> <td>
<button class="btn-space" (click)="setRate(item)" mat-raised-button color="primary"> <button class="btn-space" (click)="setRate(item)" mat-raised-button color="primary">
Rate Edit
</button> </button>
</td> </td>
</tr> </tr>
@@ -74,16 +74,16 @@ 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,
name: myCurrency.name, name: myCurrency.name,
quantity: myCurrency.quantity, quantity: myCurrency.quantity,
rate: myCurrency.rate, rate: myCurrency.rate,
rateDate: myCurrency.rateDate, rateDate: myCurrency.rateDate,
shortName: globalCurrency?.name, shortName: myCurrency.shortName,
symbol: globalCurrency?.symbol, symbol: globalCurrency?.symbol,
}); };
}); });
}); });
} }
@@ -1,9 +1,9 @@
<div> <div>
<h2 mat-dialog-title>Add currency</h2> <h2 mat-dialog-title>Edit currency</h2>
<div mat-dialog-content> <div mat-dialog-content>
<form [formGroup]="addForm!" (ngSubmit)="onSubmitClick()"> <form [formGroup]="addForm!" (ngSubmit)="onSubmitClick()">
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-3">
<div class="text-inside"> <div class="text-inside">
<mat-form-field class="example-full-width"> <mat-form-field class="example-full-width">
<mat-label>Symbol</mat-label> <mat-label>Symbol</mat-label>
@@ -11,7 +11,7 @@
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="col-md-3">
<div class="text-inside"> <div class="text-inside">
<mat-form-field class="example-full-width"> <mat-form-field class="example-full-width">
<mat-label>Code</mat-label> <mat-label>Code</mat-label>
@@ -19,11 +19,19 @@
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
<div class="col-md-4"> <div class="col-md-3">
<div class="text-inside"> <div class="text-inside">
<mat-form-field class="example-full-width"> <mat-form-field class="example-full-width">
<mat-label>Name</mat-label> <mat-label>Name</mat-label>
<input matInput value={{currency.name}} formControlName="name" readonly=""> <input matInput value={{currency.name}} formControlName="name">
</mat-form-field>
</div>
</div>
<div class="col-md-3">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Short name</mat-label>
<input matInput value={{currency.shortName}} formControlName="shortName">
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@@ -45,6 +45,9 @@ export class SettingsRateCurrencyComponent {
name: [ name: [
this.currency.name, this.currency.name,
], ],
shortName: [
this.currency.shortName,
],
quantity: [ quantity: [
this.currency.quantity || 1, this.currency.quantity || 1,
[Validators.required], [Validators.required],
@@ -68,9 +71,16 @@ export class SettingsRateCurrencyComponent {
if (this.addForm.valid) { if (this.addForm.valid) {
this.errorMessage = undefined; this.errorMessage = undefined;
this.httpClient this.httpClient
.post<CurrencyModel[]>(ApiRoutes.SettingsCurrenciesRate.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 => {
this.dialogRef.close({ refresh: true }); console.log(this.addForm.value);
this.httpClient
.post<CurrencyModel[]>(ApiRoutes.SettingsCurrenciesRate.replace(':id', this.addForm.value.id), this.addForm.value)
.subscribe(response => {
this.dialogRef.close({ refresh: true });
}, error => {
this.errorMessage = error.detail;
});
}, error => { }, error => {
this.errorMessage = error.detail; this.errorMessage = error.detail;
}); });
@@ -21,4 +21,9 @@ export class AccountCategoryService {
return this.httpClient return this.httpClient
.get<AccountCategoryModel[]>(ApiRoutes.SettingsAccountCategories); .get<AccountCategoryModel[]>(ApiRoutes.SettingsAccountCategories);
} }
public getCategory(id: string): Observable<AccountCategoryModel> {
return this.httpClient
.get<AccountCategoryModel>(ApiRoutes.SettingsAccountCategory.replace(':id', id));
}
} }
+59 -7
View File
@@ -1,6 +1,7 @@
namespace MyOffice.Services.Account namespace MyOffice.Services.Account
{ {
using Core; using Core;
using Core.Extensions;
using Core.Helpers; using Core.Helpers;
using Data.Models.Accounts; using Data.Models.Accounts;
using Data.Models.Motions; using Data.Models.Motions;
@@ -47,6 +48,20 @@
return _accountCategoryRepository.GetAll(userId); return _accountCategoryRepository.GetAll(userId);
} }
public Exec<AccountCategory, GeneralExecStatus> GetCategory(Guid userId, Guid id)
{
var result = new Exec<AccountCategory, GeneralExecStatus>(GeneralExecStatus.success);
var category = _accountCategoryRepository.Get(userId, id);
if (category == null)
{
return result.Set(GeneralExecStatus.not_found);
}
return result.Set(category);
}
public Exec<AccountCategory, GeneralExecStatus> CategoryAdd(Guid userId, AccountCategory category) public Exec<AccountCategory, GeneralExecStatus> CategoryAdd(Guid userId, AccountCategory category)
{ {
if (category == null) if (category == null)
@@ -125,6 +140,19 @@
return _accountRepository.GetByCategoryDetailed(userId, categoryId); return _accountRepository.GetByCategoryDetailed(userId, categoryId);
} }
public Exec<AccountDetailed, GeneralExecStatus> GetByIdDetailed(Guid userId, Guid id)
{
var result = new Exec<AccountDetailed, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.GetByIdDetailed(userId, id);
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
return result.Set(account);
}
public Exec<Account, AccountAddResult> AccountAdd(Guid userId, AccountAdd input) public Exec<Account, AccountAddResult> AccountAdd(Guid userId, AccountAdd input)
{ {
if (input == null) if (input == null)
@@ -270,33 +298,36 @@
return result.Set(AccountMotionAddResult.account_not_found); return result.Set(AccountMotionAddResult.account_not_found);
} }
var motion = _motionGlobalRepository.GetByName(accountMotion.Motion); var motionGlobal = _motionGlobalRepository.GetByName(accountMotion.Motion);
if (motion == null) if (motionGlobal == null)
{ {
motion = new MotionGlobal // add global motion
motionGlobal = new MotionGlobal
{ {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
Name = accountMotion.Motion.Trim(), Name = accountMotion.Motion.Trim(),
}; };
if (_motionGlobalRepository.Add(motion)) if (!_motionGlobalRepository.Add(motionGlobal))
{ {
return result.Set(AccountMotionAddResult.failure); return result.Set(AccountMotionAddResult.failure);
} }
} }
var motionAccount = _motionRepository.GetByGlobal(userId, motion.Id); var motionAccount = _motionRepository.GetByGlobal(userId, motionGlobal.Id);
if (motionAccount == null) if (motionAccount == null)
{ {
// add motion account
motionAccount = new MotionAccount motionAccount = new MotionAccount
{ {
CategoryId = userId, CategoryId = userId,
MotionGlobalId = motion.Id, MotionGlobalId = motionGlobal.Id,
}; };
_motionRepository.Add(motionAccount); _motionRepository.Add(motionAccount);
} }
var accountMotionDb = new AccountMotion var accountMotionDb = new AccountMotion
{ {
Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow, CreatedOn = DateTime.UtcNow,
DateTime = accountMotion.Date, DateTime = accountMotion.Date,
AccountId = account.Id, AccountId = account.Id,
@@ -312,7 +343,28 @@
} }
return result; motionAccount.MotionGlobal = motionGlobal;
accountMotionDb.Motion = motionAccount;
return result.Set(accountMotionDb);
}
public Exec<List<AccountMotion>, GeneralExecStatus> GetAccountMotion(
Guid userId,
Guid accountId,
DateTime dateFrom,
DateTime dateTo
)
{
var result = new Exec<List<AccountMotion>, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
return result.Set(_accountMotionRepository.GetByAccount(accountId, dateFrom.ToUtc(), dateTo.ToUtc()));
} }
} }
} }
+41 -10
View File
@@ -41,30 +41,58 @@ public class CurrencyService
); );
} }
public Exec<Currency, AddCurrencyStatus> AddCurrency(Guid userId, Currency currency) public Exec<Currency, CurrencyAddStatus> CurrencyAdd(Guid userId, Currency currency)
{ {
if (currency == null) if (currency == null)
throw new ArgumentNullException(nameof(currency)); throw new ArgumentNullException(nameof(currency));
var result = new Exec<Currency, AddCurrencyStatus>(AddCurrencyStatus.success); var result = new Exec<Currency, CurrencyAddStatus>(CurrencyAddStatus.success);
var exists = _currencyRepository.GetByGlobalCurrency(userId, currency.CurrencyGlobalId); var exists = _currencyRepository.GetByGlobalCurrency(userId, currency.CurrencyGlobalId);
if (exists != null) if (exists != null)
{ {
return result.Set(exists, AddCurrencyStatus.exists); return result.Set(exists, CurrencyAddStatus.exists);
} }
currency.Id = Guid.NewGuid(); currency.Id = Guid.NewGuid();
currency.UserId = userId; currency.UserId = userId;
if (!_currencyRepository.Add(currency)) if (!_currencyRepository.Add(currency))
{ {
return result.Set(AddCurrencyStatus.failed); return result.Set(CurrencyAddStatus.failed);
} }
return result.Set(currency); return result.Set(currency);
} }
public Exec<CurrencyRate, CurrencyAddRateStatus> AddCurrencyRate(Guid userId, Guid currencyId, CurrencyRate currencyRate) public Exec<Currency, CurrencyEditStatus> CurrencyUpdate(
Guid userId,
Guid currencyId,
CurrencyEdit currency
)
{
if (currency == null)
throw new ArgumentNullException(nameof(currency));
var result = new Exec<Currency, CurrencyEditStatus>(CurrencyEditStatus.success);
var exists = _currencyRepository.Get(userId, currencyId);
if (exists == null)
{
return result.Set(CurrencyEditStatus.not_found);
}
exists.Name = currency.Name;
exists.ShortName = currency.ShortName;
if (!_currencyRepository.Update(exists))
{
return result.Set(CurrencyEditStatus.failed);
}
return result.Set(exists);
}
public Exec<CurrencyRate, CurrencyAddRateStatus> CurrencyRateAdd(Guid userId, Guid currencyId, CurrencyRate currencyRate)
{ {
if (currencyRate == null) if (currencyRate == null)
throw new ArgumentNullException(nameof(currencyRate)); throw new ArgumentNullException(nameof(currencyRate));
@@ -80,15 +108,18 @@ public class CurrencyService
currencyRate.CurrencyId = exists.Id; currencyRate.CurrencyId = exists.Id;
currencyRate.DateTime = currencyRate.DateTime.Date; currencyRate.DateTime = currencyRate.DateTime.Date;
var rate = _currencyRateRepository.GetAtDate(currencyRate.CurrencyId, currencyRate.DateTime); var rates = _currencyRateRepository.GetAtDate(currencyRate.CurrencyId, currencyRate.DateTime);
if (rate.All(x => x.Rate != currencyRate.Rate)) var rate = rates.Find(x => x.Rate == currencyRate.Rate);
if (rate == null)
{ {
if (_currencyRateRepository.AddRate(currencyRate)) if (!_currencyRateRepository.AddRate(currencyRate))
{ {
return result.Set(currencyRate); return result.Set(CurrencyAddRateStatus.failed);
} }
rate = currencyRate;
} }
return result.Set(CurrencyAddRateStatus.failed); return result.Set(rate);
} }
} }
@@ -1,16 +0,0 @@
namespace MyOffice.Services.Currency.Domain
{
public enum AddCurrencyStatus
{
success,
failed,
exists,
}
public enum CurrencyAddRateStatus
{
not_found,
success,
failed,
}
}
@@ -0,0 +1,8 @@
namespace MyOffice.Services.Currency.Domain;
public enum CurrencyAddRateStatus
{
not_found,
success,
failed,
}
@@ -0,0 +1,9 @@
namespace MyOffice.Services.Currency.Domain
{
public enum CurrencyAddStatus
{
success,
failed,
exists,
}
}
@@ -0,0 +1,7 @@
namespace MyOffice.Services.Currency.Domain;
public class CurrencyEdit
{
public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
}
@@ -0,0 +1,8 @@
namespace MyOffice.Services.Currency.Domain;
public enum CurrencyEditStatus
{
success,
not_found,
failed,
}
+42 -6
View File
@@ -1,9 +1,12 @@
namespace MyOffice.Web.Controllers; namespace MyOffice.Web.Controllers;
using Core;
using Core.Extensions; using Core.Extensions;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Models.Account; using Models.Account;
using Models.Motion;
using MyOffice.Data.Models.Accounts; using MyOffice.Data.Models.Accounts;
using MyOffice.Web.Models.AccountMotion; using MyOffice.Web.Models.AccountMotion;
using Services.Account; using Services.Account;
@@ -31,29 +34,62 @@ public class AccountController : BaseApiController
{ {
var list = _accountService.GetByCategoryDetailed(UserId, category!.AsGuid()); var list = _accountService.GetByCategoryDetailed(UserId, category!.AsGuid());
return list.Select(x => x.ToModel()); return list
.OrderBy(x => x.Account.Name)
.Select(x => x.ToModel());
}
[HttpGet("~/api/accounts/{id}")]
public object AccountGet(string id)
{
var exec = _accountService.GetByIdDetailed(UserId, id!.AsGuid());
switch (exec.Status)
{
case GeneralExecStatus.not_found:
case GeneralExecStatus.failure:
return ProblemBadRequest("Account not found.");
case GeneralExecStatus.success:
return exec.Result!.ToModel();
default:
throw new NotSupportedException(exec.Status.ToString());
}
} }
[HttpGet("~/api/accounts/{id}/motions")] [HttpGet("~/api/accounts/{id}/motions")]
public object AccountsMotionsGet(string category) public object AccountMotionsGet(string id, [FromQuery] AccountMotionsGetModel request)
{ {
var list = _accountService.GetByCategoryDetailed(UserId, category!.AsGuid()); var exec = _accountService.GetAccountMotion(UserId, id!.AsGuid(), request.From.StartOfDay(), request.To.EndOfDay());
return list.Select(x => x.ToModel()); switch (exec.Status)
{
case GeneralExecStatus.not_found:
case GeneralExecStatus.failure:
return ProblemBadRequest("Account not found.");
case GeneralExecStatus.success:
return exec.Result!.Select(x => x.ToModel());
default:
throw new NotSupportedException(exec.Status.ToString());
}
} }
[HttpPost("~/api/accounts/{id}/motions")] [HttpPost("~/api/accounts/{id}/motions")]
public object AccountsMotionsPost(string id, AccountMotionRequest accountMotion) public object AccountsMotionsPost(string id, AccountMotionRequest accountMotion)
{ {
var exec = _accountService.AccountMotionAdd(UserId, id.AsGuid(), accountMotion.FromModel()); var exec = _accountService.AccountMotionAdd(UserId, id.AsGuid(), accountMotion.FromModel());
switch (exec.Status) switch (exec.Status)
{ {
case AccountMotionAddResult.account_not_found: case AccountMotionAddResult.account_not_found:
return ProblemBadRequest("Account failed."); return ProblemBadRequest("Account not found.");
case AccountMotionAddResult.failure: case AccountMotionAddResult.failure:
return ProblemBadRequest("Adding motion failed."); return ProblemBadRequest("Adding motion failed.");
case AccountMotionAddResult.success: case AccountMotionAddResult.success:
return exec.Result!; return exec.Result!.ToModel();
default: default:
throw new NotSupportedException(exec.Status.ToString()); throw new NotSupportedException(exec.Status.ToString());
+32 -7
View File
@@ -32,13 +32,15 @@ public class CurrencyController : BaseApiController
{ {
var list = _currencyService.GetAllWithRates(UserId); var list = _currencyService.GetAllWithRates(UserId);
return list.Select(x => x.Key.ToModel(x.Value)); return list
.OrderBy(x => x.Key.CurrencyGlobalId)
.Select(x => x.Key.ToModel(x.Value));
} }
[HttpPost("~/api/settings/currencies")] [HttpPost("~/api/settings/currencies")]
public object Post(CurrencyAddModel currency) public object Post(CurrencyAddModel currency)
{ {
var exec = _currencyService.AddCurrency(UserId, new Currency var exec = _currencyService.CurrencyAdd(UserId, new Currency
{ {
UserId = UserId, UserId = UserId,
CurrencyGlobalId = currency.Id, CurrencyGlobalId = currency.Id,
@@ -48,9 +50,9 @@ public class CurrencyController : BaseApiController
switch (exec.Status) switch (exec.Status)
{ {
case AddCurrencyStatus.success: case CurrencyAddStatus.success:
case AddCurrencyStatus.exists: case CurrencyAddStatus.exists:
_currencyService.AddCurrencyRate(UserId, exec.Result!.Id, new CurrencyRate() _currencyService.CurrencyRateAdd(UserId, exec.Result!.Id, new CurrencyRate()
{ {
CurrencyId = exec.Result!.Id, CurrencyId = exec.Result!.Id,
Rate = currency.Rate, Rate = currency.Rate,
@@ -59,7 +61,7 @@ public class CurrencyController : BaseApiController
}); });
return currency; return currency;
case AddCurrencyStatus.failed: case CurrencyAddStatus.failed:
return ProblemBadRequest("Adding currency failed."); return ProblemBadRequest("Adding currency failed.");
default: default:
@@ -67,10 +69,33 @@ public class CurrencyController : BaseApiController
} }
} }
[HttpPut("~/api/settings/currencies/{id}")]
public object Put(string id, CurrencyEditModel currency)
{
var exec = _currencyService.CurrencyUpdate(
UserId,
id.AsGuid(),
new CurrencyEdit { Name = currency.Name, ShortName = currency.ShortName }
);
switch (exec.Status)
{
case CurrencyEditStatus.success:
return exec.Result!.ToModel();
case CurrencyEditStatus.not_found:
case CurrencyEditStatus.failed:
return ProblemBadRequest("Currency not found.");
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpPost("~/api/settings/currencies/{id}/rate")] [HttpPost("~/api/settings/currencies/{id}/rate")]
public object Post(string id, CurrencyRateModel currencyRate) public object Post(string id, CurrencyRateModel currencyRate)
{ {
var exec = _currencyService.AddCurrencyRate(UserId, id.AsGuid(), new CurrencyRate() var exec = _currencyService.CurrencyRateAdd(UserId, id.AsGuid(), new CurrencyRate()
{ {
CurrencyId = id.AsGuid(), CurrencyId = id.AsGuid(),
Quantity = currencyRate.Quantity, Quantity = currencyRate.Quantity,
+10 -5
View File
@@ -32,7 +32,10 @@ public class SettingsMotionController : BaseApiController
{ {
var list = _motionService.GetAllCategories(UserId); var list = _motionService.GetAllCategories(UserId);
return list.Select(x => x.ToModel()).OrderByDescending(x => x.SortOrder); return list
.Select(x => x.ToModel())
.OrderByDescending(x => x.SortOrder)
.ThenBy(x => x.Name);
} }
[HttpPost("~/api/settings/motion-categories")] [HttpPost("~/api/settings/motion-categories")]
@@ -42,7 +45,7 @@ public class SettingsMotionController : BaseApiController
switch (exec.Status) switch (exec.Status)
{ {
case GeneralExecStatus.success: case GeneralExecStatus.success:
return exec.Result!; return exec.Result!.ToModel();
case GeneralExecStatus.failure: case GeneralExecStatus.failure:
case GeneralExecStatus.not_found: case GeneralExecStatus.not_found:
@@ -60,7 +63,7 @@ public class SettingsMotionController : BaseApiController
switch (exec.Status) switch (exec.Status)
{ {
case GeneralExecStatus.success: case GeneralExecStatus.success:
return exec.Result!; return exec.Result!.ToModel();
case GeneralExecStatus.failure: case GeneralExecStatus.failure:
case GeneralExecStatus.not_found: case GeneralExecStatus.not_found:
@@ -97,9 +100,11 @@ public class SettingsMotionController : BaseApiController
{ {
var list = category.IsMissing() var list = category.IsMissing()
? _motionService.GetAll(UserId) ? _motionService.GetAll(UserId)
: _motionService.GetByCategory(UserId, category.AsGuid()); : _motionService.GetByCategory(UserId, category!.AsGuid());
return list.Select(x => x.ToModel()); return list
.OrderBy(x => x.MotionGlobal.Name)
.Select(x => x.ToModel());
} }
[HttpPut("~/api/settings/motions/{id}")] [HttpPut("~/api/settings/motions/{id}")]
@@ -31,7 +31,26 @@ public class SettingsAccountController : BaseApiController
{ {
var list = _accountService.GetAllCategories(UserId); var list = _accountService.GetAllCategories(UserId);
return list.Select(x => x.ToModel()); return list.OrderBy(x => x.Name).Select(x => x.ToModel());
}
[HttpGet("~/api/settings/account-categories/{id}")]
public object AccountCategory(string id)
{
var exec = _accountService.GetCategory(UserId, id.AsGuid());
switch (exec.Status)
{
case GeneralExecStatus.not_found:
case GeneralExecStatus.failure:
return ProblemBadRequest("Account category not found.");
case GeneralExecStatus.success:
return exec.Result!.ToModel();
default:
throw new NotSupportedException(exec.Status.ToString());
}
} }
[HttpPost("~/api/settings/account-categories")] [HttpPost("~/api/settings/account-categories")]
@@ -98,7 +117,9 @@ public class SettingsAccountController : BaseApiController
? _accountService.GetByCategory(UserId, category!.AsGuid()) ? _accountService.GetByCategory(UserId, category!.AsGuid())
: _accountService.GetAllAccounts(UserId); : _accountService.GetAllAccounts(UserId);
return list.Select(x => x.ToModel()); return list
.OrderBy(x => x.Name)
.Select(x => x.ToModel());
} }
[HttpPost("~/api/settings/accounts")] [HttpPost("~/api/settings/accounts")]
@@ -1,47 +0,0 @@
namespace MyOffice.Web.Controllers;
using Models.WeatherForecast;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet("~/api/weatherforecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
[HttpGet("~/api/weatherforecast/auth")]
[Authorize]
public IEnumerable<WeatherForecast> GetAuth()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
@@ -18,8 +18,8 @@ public class AccountMotionRequest
public DateTime Date { get; set; } public DateTime Date { get; set; }
public string Motion { get; set; } = null!; public string Motion { get; set; } = null!;
public string? Description { get; set; } public string? Description { get; set; }
public decimal Plus { get; set; } public decimal? Plus { get; set; }
public decimal Minus { get; set; } public decimal? Minus { get; set; }
} }
public static class AccountMotionViewModelExtension public static class AccountMotionViewModelExtension
@@ -34,8 +34,8 @@ public static class AccountMotionRequestExtension
{ {
Date = input.Date, Date = input.Date,
Motion = input.Motion, Motion = input.Motion,
Minus = input.Minus, Minus = input.Minus ?? 0,
Plus = input.Plus, Plus = input.Plus ?? 0,
Description = input.Description, Description = input.Description,
}; };
} }
@@ -0,0 +1,10 @@
namespace MyOffice.Web.Models.Currency;
public class CurrencyEditModel
{
public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
public int Quantity { get; set; }
public decimal Rate { get; set; }
public DateTime RateDate { get; set; }
}
@@ -8,7 +8,9 @@
{ {
public string Id { get; set; } = null!; public string Id { get; set; } = null!;
public string Code { get; set; } = null!; public string Code { get; set; } = null!;
public string Symbol { get; set; } = null!;
public string Name { get; set; } = null!; public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
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; }
@@ -22,7 +24,9 @@
{ {
Id = input.Id.ToShort(), Id = input.Id.ToShort(),
Code = input.CurrencyGlobal!.Id, Code = input.CurrencyGlobal!.Id,
Symbol = input.CurrencyGlobal!.Symbol,
Name = input.Name, Name = input.Name,
ShortName = input.ShortName,
Quantity = rate?.Quantity, Quantity = rate?.Quantity,
Rate = rate?.Rate, Rate = rate?.Rate,
RateDate = rate?.DateTime, RateDate = rate?.DateTime,
@@ -0,0 +1,33 @@
namespace MyOffice.Web.Models.Motion
{
using System.ComponentModel.DataAnnotations;
using Core.Extensions;
using Data.Models.Accounts;
using MyOffice.Data.Models.Motions;
public class AccountMotionViewModel
{
public string Id { get; set; } = null!;
public DateTime Date { get; set; }
public string Motion { get; set; } = null!;
public string? Description { get; set; }
public decimal Plus { get; set; }
public decimal Minus { get; set; }
}
public static class AccountMotionViewModelExtensions
{
public static AccountMotionViewModel ToModel(this AccountMotion input)
{
return new AccountMotionViewModel
{
Id = input.Id.ToShort(),
Date = input.DateTime,
Motion = input.Motion.MotionGlobal.Name,
Description = input.Description,
Plus = input.AmountPlus,
Minus = input.AmountMinus,
};
}
}
}
@@ -0,0 +1,12 @@
namespace MyOffice.Web.Models.Motion
{
using System.ComponentModel.DataAnnotations;
public class AccountMotionsGetModel
{
[Required]
public DateTime From { get; set; }
[Required]
public DateTime To { get; set; }
}
}
@@ -1,12 +0,0 @@
namespace MyOffice.Web.Models.WeatherForecast;
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}