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;
using Microsoft.EntityFrameworkCore;
using Models.Accounts;
public class AccountMotionRepository : AppRepository<AccountMotion>, IAccountMotionRepository
@@ -8,4 +9,16 @@ public class AccountMotionRepository : AppRepository<AccountMotion>, IAccountMot
{
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,
TotalPlus = x.Motions!.Sum(m => m.AmountPlus),
TotalMinus = x.Motions!.Sum(m => m.AmountPlus),
TotalMinus = x.Motions!.Sum(m => m.AmountMinus),
})
.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)
{
return AddBase(account) > 0;
@@ -5,4 +5,5 @@ using Models.Accounts;
public interface IAccountMotionRepository
{
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> GetByCategory(Guid userId, Guid categoryId);
List<AccountDetailed> GetByCategoryDetailed(Guid userId, Guid categoryId);
AccountDetailed? GetByIdDetailed(Guid userId, Guid id);
bool Add(Account account);
Account? Get(Guid userId, Guid id);
bool Update(Account account);
@@ -16,7 +16,10 @@ public class CurrencyRepository : AppRepository<Currency>, ICurrencyRepository
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)
+8
View File
@@ -205,5 +205,13 @@ public class AppDbContext : DbContext
.HasOne(x => x.Account)
.WithMany(x => x.Motions)
.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 = "GBP", DefaultQuantity = 1, Symbol = "£", Name = "British pounds sterling" },
new() { Id = "RUB", DefaultQuantity = 10, Symbol = "₽", Name = "Russia Ruble" },
new() { Id = "BTC", DefaultQuantity = 10, Symbol = "btc", Name = "Bitcoin" },
new() { Id = "ETH", DefaultQuantity = 10, Symbol = "eth", Name = "Ethereum" },
new() { Id = "TON", DefaultQuantity = 10, Symbol = "ton", Name = "TON" },
new() { Id = "OTHER", DefaultQuantity = 1, Symbol = "₽", Name = "Other" },
};
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 =>
{
b.Property<long>("Id")
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasColumnType("numeric");
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasColumnType("numeric");
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
+1
View File
@@ -7,6 +7,7 @@ export class ApiRoutes {
static GeneralCurrencies = '/api/general/currencies';
static SettingsCurrencies = '/api/settings/currencies';
static SettingsCurrency = '/api/settings/currencies/:id';
static SettingsCurrenciesRate = '/api/settings/currencies/:id/rate';
static SettingsAccountCategories = '/api/settings/account-categories';
@@ -24,10 +24,10 @@ export class ErrorInterceptor implements HttpInterceptor {
this.authenticationService.logout();
location.reload();
}
const error = err.error.message || err.statusText;
//return throwError(error);
return throwError(err.error || err);
console.log(err);
const error = err.message || err.error.message || err.statusText;
return throwError(error);
//return throwError(err.error || err);
})
);
}
@@ -1,3 +1,4 @@
// angular
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpInterceptor } from '@angular/common/http';
@@ -5,6 +6,9 @@ import { HttpRequest } from '@angular/common/http';
import { HttpHandler } from '@angular/common/http';
import { HttpEvent } from '@angular/common/http';
// libs
import * as moment from 'moment';
@Injectable()
export class UpdateDateHttpInterceptor implements HttpInterceptor {
@@ -29,12 +33,7 @@ export class UpdateDateHttpInterceptor implements HttpInterceptor {
for (const key of Object.keys(body)) {
const value = body[key];
if (value instanceof Date) {
body[key] = new Date(Date.UTC(value.getFullYear(),
value.getMonth(),
value.getDate(),
value.getHours(),
value.getMinutes(),
value.getSeconds()));
body[key] = moment(value).utcOffset(0, true).format();
} else if (typeof value === 'object') {
this.shiftDates(value);
}
@@ -86,6 +86,7 @@ export class SidebarComponent implements OnInit, OnDestroy {
.getCategories()
.subscribe(categories => {
var accounts = this.sidebarItems.filter(x => x.id === 'accounts');
accounts[0].submenu = [];
for (var category of categories) {
accounts[0].submenu.push({
path: '/account-category/' + category.id,
@@ -1,30 +1,44 @@
<section class="content">
<div class="content-block">
<div class="block-header">
<!-- breadcrumb -->
<app-breadcrumb [title]="'Blank'" [items]="['Home','Settings']" [active_item]="'Accounts'">
</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>
<mat-expansion-panel *ngFor="let account of accounts; let i = index" [expanded]="i === 0" >
<mat-expansion-panel [expanded]="expanded">
<mat-expansion-panel-header>
<mat-panel-description>
<div>{{account.account.name}}</div>
<div>
{{account.rest}}
<h4>{{account.account.name}}</h4>
<h4>
{{account.rest | number: '1.2-6'}}
({{account.account.currencyId}})
</div>
</h4>
</mat-panel-description>
</mat-expansion-panel-header>
<account-motion [motion]="newMotion">
<form [formGroup]="form!" (ngSubmit)="onSubmitClick()">
<div class="row">
<div class="col-md-6">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>From</mat-label>
<input matInput [matDatepicker]="pickerFrom" (focus)="pickerFrom.open()" formControlName="dateFrom" required>
<mat-hint>YYYY/MM/DD</mat-hint>
<mat-datepicker-toggle tabindex="-1" matSuffix [for]="pickerFrom"></mat-datepicker-toggle>
<mat-datepicker #pickerFrom></mat-datepicker>
<mat-error *ngIf="form.controls?.['dateFrom']?.hasError('required')">
Please enter rate date
</mat-error>
</mat-form-field>
</div>
<div class="col-md-6">
<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>
</form>
<hr/>
<account-motion [motion]="newMotion" [account]="account.account" (onAdd)="handlerOnAdd($event)">
</account-motion>
<account-motion *ngFor="let motion of motions" [motion]="motion">
<account-motion *ngFor="let motion of motions" [motion]="motion" [account]="account.account">
</account-motion>
</mat-expansion-panel>
</mat-accordion>
</div>
</div>
</div>
</section>
</mat-expansion-panel>
@@ -1,91 +1,99 @@
// angular
import { Component } from '@angular/core';
import { Input } from '@angular/core';
import { HttpClient } from '@angular/common/http';
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
import Swal from 'sweetalert2';
import { MatDialog } from '@angular/material/dialog';
import * as moment from 'moment';
// 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.component.html',
styleUrls: ['./account.component.scss'],
selector: 'account'
})
export class AccountComponent {
public accounts?: AccountDetailedModel[];
public motions?: AccountMotionModel[];
public newMotion: AccountMotionModel;
public form!: UntypedFormGroup;
@Input('account') account!: AccountDetailedModel;
@Input('expanded') expanded!: boolean;
@Output() onUpdate: EventEmitter<AccountMotionModel> = new EventEmitter<AccountMotionModel>();
constructor(
private fb: UntypedFormBuilder,
private httpClient: HttpClient,
private dialogModel: MatDialog,
private activatedRoute: ActivatedRoute
) {
this.newMotion = {
date: new Date(),
plus: 0,
minus: 0,
};
}
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.httpClient
.get<AccountDetailedModel[]>(ApiRoutes.Accounts + "?category=" + params['id'])
.get<AccountMotionModel[]>(url)
.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()">
<div class="row">
<div class="col-md-4">
<form [formGroup]="form" (ngSubmit)="onSubmitClick()" novalidate autocomplete="off">
<div class="" style="display: flex;">
<div class="" style="width: 310px; min-width: 310px;">
<div style="display: flex; align-items: center;">
<a href="javascript:void(0)" matSuffix (click)="addDay(-1)">
<i class="material-icons font-40">arrow_back</i>
@@ -21,15 +21,19 @@
</a>
</div>
</div>
<div class="col-md-4">
<div class="" style="flex-grow: 1;">
<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 class="example-full-width" appearance="fill">
<input matInput formControlName="description">
</mat-form-field>
</div>
<div class="col-md-2">
<div class="" style="width: 100px; min-width: 100px;">
<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 }">
</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 }">
</mat-form-field>
</div>
<div class="col-md-2 mb-2">
<a *ngIf="!motion.id" href="javascript:void(0)" (click)="onSubmitClick()">
<div class="" style="display: inline-block; width: 150px; min-width: 150px;">
<button type="button" mat-stroked-button color="primary" *ngIf="!motion.id" (click)="onSubmitClick()">
<i class="material-icons font-40">add</i>
</a>
<a *ngIf="!motion.id" href="javascript:void(0)" (click)="onSubmitClick()">
</button>
<button mat-stroked-button color="primary" *ngIf="!motion.id" (click)="onSubmitClick()">
<i class="material-icons font-40">import_export</i>
</a>
<a *ngIf="motion.id" href="javascript:void(0)" (click)="onSubmitClick()">
</button>
<button mat-stroked-button color="primary" *ngIf="motion.id" (click)="onSubmitClick()">
<i class="material-icons font-40">save</i>
</a>
<a *ngIf="motion.id" href="javascript:void(0)" (click)="onSubmitClick()">
</button>
<button mat-stroked-button color="primary" *ngIf="motion.id" (click)="onSubmitClick()">
<i class="material-icons font-40">delete</i>
</a>
</button>
</div>
</div>
<hr/>
</form>
@@ -1,29 +1,22 @@
// angular
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute } from '@angular/router';
import { UntypedFormBuilder } from '@angular/forms';
import { FormBuilder } from '@angular/forms';
import { FormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';
import { UntypedFormGroup } from '@angular/forms';
import { Input } from '@angular/core';
import { Output } from '@angular/core';
import { EventEmitter } from '@angular/core';
import { ViewChild } from '@angular/core';
import { ElementRef } from '@angular/core';
// libs
import Swal from 'sweetalert2';
import { MatDialog } from '@angular/material/dialog';
import * as moment from 'moment';
// 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';
import { atLeastOne } from '../../core/validators/atleastone.validator';
import { atLeastOneNumber } from '../../core/validators/atleastonenumber.validator';
@Component({
@@ -32,16 +25,19 @@ import { atLeastOneNumber } from '../../core/validators/atleastonenumber.validat
styleUrls: ['./motion.component.scss'],
})
export class MotionComponent {
public form!: UntypedFormGroup;
public form!: FormGroup;
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(
private fb: UntypedFormBuilder,
private fb: FormBuilder,
private httpClient: HttpClient,
private dialogModel: MatDialog,
private activatedRoute: ActivatedRoute
) {
}
@@ -67,14 +63,29 @@ export class MotionComponent {
minus: [
this.motion.minus,
],
}, { validator: atLeastOneNumber(Validators.required, ['plus', 'minus']) });
}, {
validator: atLeastOneNumber(Validators.required, ['plus', 'minus'])
});
}
onSubmitClick() {
this.form.markAllAsTouched();
if (this.form.valid) {
this.httpClient
.post<AccountMotionModel[]>(ApiRoutes.SettingsCurrencies, this.form.value)
.post<AccountMotionModel>(ApiRoutes.Motions.replace(':id', this.account.id!), this.form.value)
.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 => {
this.errorMessage = error.detail;
});
@@ -6,7 +6,7 @@ import { SettingsAccountCategoryComponent } from './settings/account/account.cat
import { SettingsAccountComponent } from './settings/account/account.component';
import { SettingsMotionCategoryComponent } from './settings/motion/motion.category.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 = [
{
@@ -36,6 +36,7 @@ import { MotionService } from '../services/motion.service';
import { SettingsMotionCategoryComponent } from './settings/motion/motion.category.component';
import { SettingsMotionComponent } from './settings/motion/motion.component';
import { SettingsMotionEditComponent } from './settings/motion/edit.motion.component';
import { AccountListComponent } from './accounts/account.list.component';
import { AccountComponent } from './accounts/account.component';
import { MotionComponent } from './accounts/motion.component';
@@ -56,6 +57,7 @@ import { MotionComponent } from './accounts/motion.component';
SettingsMotionComponent,
SettingsMotionEditComponent,
AccountListComponent,
AccountComponent,
MotionComponent,
],
@@ -16,10 +16,22 @@
<mat-tab label="My currencies">
<div class="body table-responsive">
<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>
<tr *ngFor="let item of myCurrencies">
<td>{{item.code}}</td>
<td>{{item.name}}</td>
<td>{{item.shortName}}</td>
<td style="text-align: end">
{{item.quantity}}
</td>
@@ -30,7 +42,7 @@
<td>{{item.rateDate | date:'yyyy-MM-dd'}}</td>
<td>
<button class="btn-space" (click)="setRate(item)" mat-raised-button color="primary">
Rate
Edit
</button>
</td>
</tr>
@@ -74,16 +74,16 @@ export class SettingsCurrencyComponent {
.subscribe(data => {
this.myCurrencies = data.map(myCurrency => {
var globalCurrency = this.currencies?.find(x => x.id === myCurrency.code);
return ({
return {
id: myCurrency.id,
code: myCurrency.code,
name: myCurrency.name,
quantity: myCurrency.quantity,
rate: myCurrency.rate,
rateDate: myCurrency.rateDate,
shortName: globalCurrency?.name,
shortName: myCurrency.shortName,
symbol: globalCurrency?.symbol,
});
};
});
});
}
@@ -1,9 +1,9 @@
<div>
<h2 mat-dialog-title>Add currency</h2>
<h2 mat-dialog-title>Edit currency</h2>
<div mat-dialog-content>
<form [formGroup]="addForm!" (ngSubmit)="onSubmitClick()">
<div class="row">
<div class="col-md-4">
<div class="col-md-3">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Symbol</mat-label>
@@ -11,7 +11,7 @@
</mat-form-field>
</div>
</div>
<div class="col-md-4">
<div class="col-md-3">
<div class="text-inside">
<mat-form-field class="example-full-width">
<mat-label>Code</mat-label>
@@ -19,11 +19,19 @@
</mat-form-field>
</div>
</div>
<div class="col-md-4">
<div class="col-md-3">
<div class="text-inside">
<mat-form-field class="example-full-width">
<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>
</div>
</div>
@@ -45,6 +45,9 @@ export class SettingsRateCurrencyComponent {
name: [
this.currency.name,
],
shortName: [
this.currency.shortName,
],
quantity: [
this.currency.quantity || 1,
[Validators.required],
@@ -67,6 +70,10 @@ export class SettingsRateCurrencyComponent {
onSubmitClick() {
if (this.addForm.valid) {
this.errorMessage = undefined;
this.httpClient
.put<CurrencyModel>(ApiRoutes.SettingsCurrency.replace(':id', this.addForm.value.id), this.addForm.value)
.subscribe(response => {
console.log(this.addForm.value);
this.httpClient
.post<CurrencyModel[]>(ApiRoutes.SettingsCurrenciesRate.replace(':id', this.addForm.value.id), this.addForm.value)
.subscribe(response => {
@@ -74,6 +81,9 @@ export class SettingsRateCurrencyComponent {
}, error => {
this.errorMessage = error.detail;
});
}, error => {
this.errorMessage = error.detail;
});
}
}
}
@@ -21,4 +21,9 @@ export class AccountCategoryService {
return this.httpClient
.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
{
using Core;
using Core.Extensions;
using Core.Helpers;
using Data.Models.Accounts;
using Data.Models.Motions;
@@ -47,6 +48,20 @@
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)
{
if (category == null)
@@ -125,6 +140,19 @@
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)
{
if (input == null)
@@ -270,33 +298,36 @@
return result.Set(AccountMotionAddResult.account_not_found);
}
var motion = _motionGlobalRepository.GetByName(accountMotion.Motion);
if (motion == null)
var motionGlobal = _motionGlobalRepository.GetByName(accountMotion.Motion);
if (motionGlobal == null)
{
motion = new MotionGlobal
// add global motion
motionGlobal = new MotionGlobal
{
Id = Guid.NewGuid(),
Name = accountMotion.Motion.Trim(),
};
if (_motionGlobalRepository.Add(motion))
if (!_motionGlobalRepository.Add(motionGlobal))
{
return result.Set(AccountMotionAddResult.failure);
}
}
var motionAccount = _motionRepository.GetByGlobal(userId, motion.Id);
var motionAccount = _motionRepository.GetByGlobal(userId, motionGlobal.Id);
if (motionAccount == null)
{
// add motion account
motionAccount = new MotionAccount
{
CategoryId = userId,
MotionGlobalId = motion.Id,
MotionGlobalId = motionGlobal.Id,
};
_motionRepository.Add(motionAccount);
}
var accountMotionDb = new AccountMotion
{
Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow,
DateTime = accountMotion.Date,
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()));
}
}
}
+43 -12
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)
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);
if (exists != null)
{
return result.Set(exists, AddCurrencyStatus.exists);
return result.Set(exists, CurrencyAddStatus.exists);
}
currency.Id = Guid.NewGuid();
currency.UserId = userId;
if (!_currencyRepository.Add(currency))
{
return result.Set(AddCurrencyStatus.failed);
return result.Set(CurrencyAddStatus.failed);
}
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)
throw new ArgumentNullException(nameof(currencyRate));
@@ -80,15 +108,18 @@ public class CurrencyService
currencyRate.CurrencyId = exists.Id;
currencyRate.DateTime = currencyRate.DateTime.Date;
var rate = _currencyRateRepository.GetAtDate(currencyRate.CurrencyId, currencyRate.DateTime);
if (rate.All(x => x.Rate != currencyRate.Rate))
var rates = _currencyRateRepository.GetAtDate(currencyRate.CurrencyId, currencyRate.DateTime);
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(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;
using Core;
using Core.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Models.Account;
using Models.Motion;
using MyOffice.Data.Models.Accounts;
using MyOffice.Web.Models.AccountMotion;
using Services.Account;
@@ -31,29 +34,62 @@ public class AccountController : BaseApiController
{
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")]
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")]
public object AccountsMotionsPost(string id, AccountMotionRequest accountMotion)
{
var exec = _accountService.AccountMotionAdd(UserId, id.AsGuid(), accountMotion.FromModel());
switch (exec.Status)
{
case AccountMotionAddResult.account_not_found:
return ProblemBadRequest("Account failed.");
return ProblemBadRequest("Account not found.");
case AccountMotionAddResult.failure:
return ProblemBadRequest("Adding motion failed.");
case AccountMotionAddResult.success:
return exec.Result!;
return exec.Result!.ToModel();
default:
throw new NotSupportedException(exec.Status.ToString());
+32 -7
View File
@@ -32,13 +32,15 @@ public class CurrencyController : BaseApiController
{
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")]
public object Post(CurrencyAddModel currency)
{
var exec = _currencyService.AddCurrency(UserId, new Currency
var exec = _currencyService.CurrencyAdd(UserId, new Currency
{
UserId = UserId,
CurrencyGlobalId = currency.Id,
@@ -48,9 +50,9 @@ public class CurrencyController : BaseApiController
switch (exec.Status)
{
case AddCurrencyStatus.success:
case AddCurrencyStatus.exists:
_currencyService.AddCurrencyRate(UserId, exec.Result!.Id, new CurrencyRate()
case CurrencyAddStatus.success:
case CurrencyAddStatus.exists:
_currencyService.CurrencyRateAdd(UserId, exec.Result!.Id, new CurrencyRate()
{
CurrencyId = exec.Result!.Id,
Rate = currency.Rate,
@@ -59,7 +61,7 @@ public class CurrencyController : BaseApiController
});
return currency;
case AddCurrencyStatus.failed:
case CurrencyAddStatus.failed:
return ProblemBadRequest("Adding currency failed.");
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")]
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(),
Quantity = currencyRate.Quantity,
+10 -5
View File
@@ -32,7 +32,10 @@ public class SettingsMotionController : BaseApiController
{
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")]
@@ -42,7 +45,7 @@ public class SettingsMotionController : BaseApiController
switch (exec.Status)
{
case GeneralExecStatus.success:
return exec.Result!;
return exec.Result!.ToModel();
case GeneralExecStatus.failure:
case GeneralExecStatus.not_found:
@@ -60,7 +63,7 @@ public class SettingsMotionController : BaseApiController
switch (exec.Status)
{
case GeneralExecStatus.success:
return exec.Result!;
return exec.Result!.ToModel();
case GeneralExecStatus.failure:
case GeneralExecStatus.not_found:
@@ -97,9 +100,11 @@ public class SettingsMotionController : BaseApiController
{
var list = category.IsMissing()
? _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}")]
@@ -31,7 +31,26 @@ public class SettingsAccountController : BaseApiController
{
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")]
@@ -98,7 +117,9 @@ public class SettingsAccountController : BaseApiController
? _accountService.GetByCategory(UserId, category!.AsGuid())
: _accountService.GetAllAccounts(UserId);
return list.Select(x => x.ToModel());
return list
.OrderBy(x => x.Name)
.Select(x => x.ToModel());
}
[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 string Motion { get; set; } = null!;
public string? Description { get; set; }
public decimal Plus { get; set; }
public decimal Minus { get; set; }
public decimal? Plus { get; set; }
public decimal? Minus { get; set; }
}
public static class AccountMotionViewModelExtension
@@ -34,8 +34,8 @@ public static class AccountMotionRequestExtension
{
Date = input.Date,
Motion = input.Motion,
Minus = input.Minus,
Plus = input.Plus,
Minus = input.Minus ?? 0,
Plus = input.Plus ?? 0,
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 Code { get; set; } = null!;
public string Symbol { get; set; } = null!;
public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
public decimal? Rate { get; set; }
public int? Quantity { get; set; }
public DateTime? RateDate { get; set; }
@@ -22,7 +24,9 @@
{
Id = input.Id.ToShort(),
Code = input.CurrencyGlobal!.Id,
Symbol = input.CurrencyGlobal!.Symbol,
Name = input.Name,
ShortName = input.ShortName,
Quantity = rate?.Quantity,
Rate = rate?.Rate,
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; }
}