This commit is contained in:
2023-08-04 20:10:57 +03:00
parent 70edf34cf6
commit 0d45061d81
14 changed files with 866 additions and 35 deletions
+2 -2
View File
@@ -30,8 +30,8 @@ public class AccountSimple
public Guid Id { get; set; }
public string Name { get; set; }
public AccountAccessTypeEnum Type { get; set; }
public string CurrencyName { get; set; }
public string CurrencyShortName { get; set; }
public string? CurrencyName { get; set; }
public string? CurrencyShortName { get; set; }
public decimal? CurrencyRate { get; set; }
public int? CurrencyQuantity { get; set; }
public decimal? TotalPlus { get; set; }
@@ -204,16 +204,17 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
.Where(x => !x.Item.Category!.IsInternal)
.GroupBy(x => new
{
ItemId = x.Item.CategoryId,
ItemName = x.Item.Category!.Name,
Id = x.Item.CategoryId,
Name = x.Item.Category!.Name,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.Select(x => new MotionTotalSimple
{
Id = x.Key.Id,
Name = x.Key.Name,
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Name = x.Key.ItemName,
Amount = x.Sum(a => a.AmountPlus),
}).ToList();
}
@@ -227,8 +228,8 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
.Where(x => x.Item.Category!.UserId == userId)
.GroupBy(x => new
{
ItemId = x.Item.ItemGlobalId,
ItemName = x.Item.ItemGlobal!.Name,
Id = x.Item.ItemGlobalId,
Name = x.Item.ItemGlobal!.Name,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
@@ -236,9 +237,10 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
{
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Name = x.Key.ItemName,
Name = x.Key.Name,
Amount = x.Sum(a => a.AmountPlus),
}).ToList();
})
.ToList();
}
@@ -250,18 +252,18 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
.Where(x => !x.Item.Category!.IsInternal)
.GroupBy(x => new
{
ItemId = x.Item.CategoryId,
ItemName = x.Item.Category!.Name,
Id = x.Item.CategoryId,
Name = x.Item.Category!.Name,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.Select(x => new MotionTotalSimple
{
Id = x.Key.ItemId,
Name = x.Key.ItemName,
Id = x.Key.Id,
Name = x.Key.Name,
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Amount = x.Sum(a => a.AmountPlus),
Amount = x.Sum(a => a.AmountMinus),
}).ToList();
}
@@ -273,11 +275,20 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
.Where(x => x.Item.CategoryId == categoryId)
.Where(x => !x.Item.Category!.IsInternal)
.Where(x => x.Item.Category!.UserId == userId)
.GroupBy(x => new { Id = x.Item.ItemGlobalId, x.Item.ItemGlobal.Name })
.GroupBy(x => new
{
Id = x.Item.ItemGlobalId,
Name = x.Item.ItemGlobal!.Name,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.Select(x => new MotionTotalSimple
{
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Name = x.Key.Name,
Amount = x.Sum(a => a.AmountMinus)
}).ToList();
Amount = x.Sum(a => a.AmountMinus),
})
.ToList();
}
}
+3
View File
@@ -205,6 +205,9 @@ public class AppDbContext : DbContext
.Entity<AccountAccess>()
.Property(d => d.Type)
.HasConversion(new EnumToStringConverter<AccountAccessTypeEnum>());
modelBuilder.Entity<AccountAccess>()
.HasIndex(p => new { p.AccountId, p.UserId}).IsUnique();
}
private void MotionsCreating(ModelBuilder modelBuilder)
@@ -0,0 +1,729 @@
// <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("20230804145453_AccountAccesUnique")]
partial class AccountAccesUnique
{
/// <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.Property<Guid?>("OwnerId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("OwnerId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<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<string>("Name")
.HasColumnType("text");
b.Property<Guid>("OwnerId")
.HasColumnType("uuid");
b.Property<string>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("OwnerId");
b.HasIndex("UserId");
b.HasIndex("AccountId", "UserId")
.IsUnique();
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccessInvite", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime?>("AcceptedOn")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<DateTime?>("RejectedOn")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccessInvites");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("CurrentRateId");
b.HasIndex("UserId");
b.ToTable("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("ItemGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ItemGlobalId");
b.ToTable("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("Users");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Accounts")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "Owner")
.WithMany("Accounts")
.HasForeignKey("OwnerId");
b.Navigation("CurrencyGlobal");
b.Navigation("Owner");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "Owner")
.WithMany("AccountAccessOwners")
.HasForeignKey("OwnerId")
.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("Owner");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccessInvite", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Invites")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccessInvites")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany("Currencies")
.HasForeignKey("CurrentRateId");
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("Currencies")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
b.Navigation("CurrentRate");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency")
.WithMany("Rates")
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category")
.WithMany("Items")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal")
.WithMany("Items")
.HasForeignKey("ItemGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("ItemGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("ItemCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("UserClaims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Navigation("AccessRights");
b.Navigation("Categories");
b.Navigation("Invites");
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Navigation("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Navigation("Rates");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Navigation("Accounts");
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountAccessInvites");
b.Navigation("AccountAccessOwners");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Accounts");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,37 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class AccountAccesUnique : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_AccountAccesses_AccountId",
table: "AccountAccesses");
migrationBuilder.CreateIndex(
name: "IX_AccountAccesses_AccountId_UserId",
table: "AccountAccesses",
columns: new[] { "AccountId", "UserId" },
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropIndex(
name: "IX_AccountAccesses_AccountId_UserId",
table: "AccountAccesses");
migrationBuilder.CreateIndex(
name: "IX_AccountAccesses_AccountId",
table: "AccountAccesses",
column: "AccountId");
}
}
}
@@ -84,12 +84,13 @@ namespace MyOffice.Migrations.Postgres.Migrations
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("OwnerId");
b.HasIndex("UserId");
b.HasIndex("AccountId", "UserId")
.IsUnique();
b.ToTable("AccountAccesses");
});
@@ -37,7 +37,7 @@
</div>
<div class="body">
<div id="chart">
<apx-chart #chart *ngIf="chartOptions" class="apex-pie-center"
<apx-chart #chart *ngIf="chartOptions" class="apex-pie-center" (contextmenu)="onRightClick($event)"
[series]="chartOptions.series!"
[chart]="chartOptions.chart!"
[dataLabels]="chartOptions.dataLabels!"
@@ -90,10 +90,22 @@ export class DashboardIncomeComponent implements OnInit {
color: this.colors[this.colors.length - i - 1],
});
}
if (update) {
this.chart.updateSeries([{
data: series
}]);
} else {
this.setChartOptions(series, ranges);
}
});
}
onRightClick(event?: Event) {
event?.preventDefault();
this.loadData(true);
}
private setChartOptions(data: any[], ranges: any[]) {
var self = this;
@@ -105,6 +117,12 @@ export class DashboardIncomeComponent implements OnInit {
type: 'treemap',
width: 600,
height: 600,
events: {
click: function (event, chartContext, config) {
var data = self.dashboardModel!.data[config.dataPointIndex];
self.loadData(true, data.id);
}
}
},
plotOptions: {
treemap: {
@@ -38,7 +38,7 @@
-->
</div>
<div class="body">
<apx-chart #chart *ngIf="chartOptions" class="apex-pie-center"
<apx-chart #chart *ngIf="chartOptions" class="apex-pie-center" (contextmenu)="onRightClick($event)"
[series]="chartOptions.series!"
[chart]="chartOptions.chart!"
[dataLabels]="chartOptions.dataLabels!"
@@ -46,12 +46,12 @@
[title]="chartOptions.title!"
[legend]="chartOptions.legend!">
</apx-chart>
<div class="table-responsive m-t-15" *ngIf="dashboardModel!.details">
<div class="table-responsive m-t-15" *ngIf="dashboardModel">
<table class="table align-items-center">
<tbody>
<tr *ngFor="let item of dashboardModel!.details!">
<td><i class="fa fa-circle col-cyan msr-2"></i> {{item.name}}</td>
<td [ngClass]="{ 'col-green': item.value != 0, 'col-red': item.value == 0}" style="text-align: right;">{{item.value | number: '1.2'}} ({{item.currency}})</td>
<tr *ngFor="let item of dashboardModel!.details">
<td><i class="fa fa-circle col-cyan msr-2"></i> {{item.currency}}</td>
<td [ngClass]="{ 'col-green': item.value != 0, 'col-red': item.value == 0}" style="text-align: right;">{{item.value | number: '1.2'}} ({{item.valueRaw}})</td>
</tr>
</tbody>
</table>
@@ -64,6 +64,11 @@ export class DashboardOutcomeComponent implements OnInit {
this.loadData();
}
onRightClick(event?: Event) {
event?.preventDefault();
this.loadData(true);
}
private loadData(update?: boolean, category?: string) {
let params = new HttpParams()
.set('from', moment(this.dateFrom).format('YYYY-MM-DD'))
@@ -91,6 +96,7 @@ export class DashboardOutcomeComponent implements OnInit {
color: this.colors[this.colors.length - i - 1],
});
}
if (update) {
this.chart.updateSeries([{
data: series
+2 -1
View File
@@ -103,5 +103,6 @@
"OTHER": "Інші",
"TOTAL": "Всього",
"INCOME": "Надходження",
"OUTCOME": "Витрати"
"OUTCOME": "Витрати",
"PERIOD": "Період"
}
@@ -119,19 +119,44 @@ public class DashboardService
? _accountRepository.GetOutcomeByCategory(userId, category.Value, from.ToUtc(), to.ToUtc())
: _accountRepository.GetOutcomeByCategories(userId, from.ToUtc(), to.ToUtc());
data = data
.Where(x => x.Amount != 0)
.ToList();
var currencies = data
.Where(x => x.Amount != 0)
.Select(x => x.CurrencyId)
.Distinct()
.ToList();
var rates = _currencyRateRepository
.GetLastRates(userId, currencies, to.ToUtc())
.ToDictionary(x => x.Key, x => x.Value.Rate * x.Value.Quantity);
return new DashboardIncomeData
{
Data = data.Select(x => new DashboardIncomeDataItem
Data = data.Select(x => new
{
Id = x.Id?.ToShort(),
Id = x.Id.ToShort(),
Name = x.Name,
Value = x.Amount,
Value = (x.Amount * rates.FirstOrDefault(r => r.Key == x.CurrencyId).Value),
})
.GroupBy(x => new { x.Id, x.Name })
.Select(x => new DashboardIncomeDataItem
{
Id = x.Key.Id,
Name = x.Key.Name,
Value = x.Sum(s => s.Value),
})
.ToList(),
Details = data.Select(x => new DashboardIncomeDataItem
{
Id = x.Id.ToShort(),
Currency = x.CurrencyId,
Name = x.Name,
ValueRaw = x.Amount,
Value = (x.Amount * rates.FirstOrDefault(r => r.Key == x.CurrencyId).Value),
}).ToList()
};
}
@@ -50,7 +50,7 @@ public class UserStore :
return Task.FromResult(0);
}
public async Task<IdentityResult> CreateAsync(ApplicationUser<Guid> user, CancellationToken cancellationToken)
public Task<IdentityResult> CreateAsync(ApplicationUser<Guid> user, CancellationToken cancellationToken)
{
var result = _userRepository.AddUser(new User
{
@@ -65,10 +65,10 @@ public class UserStore :
IsEmailConfirmed = user.IsEmailConfirmed
});
return result == 1 ? IdentityResult.Success : IdentityResult.Failed();
return Task.FromResult(result == 1 ? IdentityResult.Success : IdentityResult.Failed());
}
public async Task<IdentityResult> UpdateAsync(ApplicationUser<Guid> user, CancellationToken cancellationToken)
public Task<IdentityResult> UpdateAsync(ApplicationUser<Guid> user, CancellationToken cancellationToken)
{
var userDb = new User
{
@@ -84,7 +84,7 @@ public class UserStore :
};
var result = _userRepository.UpdateUser(userDb);
return result == 1 ? IdentityResult.Success : IdentityResult.Failed();
return Task.FromResult(result == 1 ? IdentityResult.Success : IdentityResult.Failed());
}
public Task<IdentityResult> DeleteAsync(ApplicationUser<Guid> user, CancellationToken cancellationToken)
@@ -2,7 +2,7 @@
public class CurrencyRateViewModel: BaseViewModel
{
public string Currency { get; set; }
public string Currency { get; set; } = null!;
public DateTime DateTime { get; set; }
public int Quantity { get; set; }
public decimal Rate { get; set; }