sync full source from private myoffice

This commit is contained in:
myoffice-sync
2026-08-05 10:55:09 +00:00
parent 874796c860
commit 405abdfe69
714 changed files with 70352 additions and 234 deletions
+18
View File
@@ -0,0 +1,18 @@
**/.git
**/.vs
**/bin
**/obj
**/node_modules
**/dist
**/_Published
**/TestResults
**/logs
**/*.user
**/*.db
**/*.db-shm
**/*.db-wal
Docker/data
.cursor
agent-transcripts
**/Coverage
**/.angular
+16
View File
@@ -0,0 +1,16 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = tabs
indent_size = 4
insert_final_newline = false
trim_trailing_whitespace = true
[*.ts]
quote_type = single
[*.md]
max_line_length = off
trim_trailing_whitespace = false
+67
View File
@@ -0,0 +1,67 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
# Shell scripts used inside Linux containers must stay LF (CRLF breaks `set -eu`).
Docker/**/*.sh text eol=lf
*.sh text eol=lf
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain
+394
View File
@@ -0,0 +1,394 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
.vscode/
/MyOffice.SPA/.vscode
/MyOffice.SPA/dist/
/MyOffice.SPA/src/environments/environment.ts
/MyOffice.SPA/src/environments/environment.prod.ts
/MyOffice.Web/.config
/MyOffice.Web/appsettings.Production.json
/MyOffice.Web/appsettings.Development.json
/MyOffice.Web/tempkey.jwk
/MyOffice.Web/rsa_key.pem
/MyOffice.Web/**/*.pem
/MyOffice.Web/keys/
*.pem
/MyOffice.Web/AppDbContext.Dev.db
/MyOffice.Web/AppDbContext.db
/MyOffice.Web/AppDbContext.Dev.db-shm
/MyOffice.Web/AppDbContext.Dev.db-wal
/_Published
package-lock.json
!MyOffice.SPA/package-lock.json
.angular
/.template.config/template.json
/MyOffice.Shared/appsettings.shared.Development.json
/MyOffice.Shared/appsettings.shared.Production.json
/linux_deploy_mybank.bat
/linux_deploy_office.bat
linux_deploy_office_public.bat
/Docker/data
/MyOffice.SPA/package-lock.json
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+23
View File
@@ -0,0 +1,23 @@
namespace MyOffice.Core;
public class Error
{
private Exception? _exception;
public Error(string message)
{
Message = message;
}
public Error(Exception exception): this(exception.GetType().Name)
{
_exception = exception;
}
public Error(string message, Exception exception): this(message)
{
_exception = exception;
}
public string Message { get; private set;}
}
+106
View File
@@ -0,0 +1,106 @@
namespace MyOffice.Core;
public enum GeneralExecStatus
{
success,
failure,
not_found,
forbidden
}
public class Exec<TResult> : Exec<TResult, GeneralExecStatus>
where TResult : class
{
public Exec(TResult result, GeneralExecStatus status) : base(result, status)
{
}
public Exec(GeneralExecStatus status) : base(status)
{
}
public Exec() : base(GeneralExecStatus.success)
{
}
public new Exec<TResult> Set(GeneralExecStatus status)
{
Status = status;
return this;
}
public new Exec<TResult> Set(TResult? result)
{
Result = result;
Status = result == null ? GeneralExecStatus.failure : GeneralExecStatus.success;
return this;
}
}
public class Exec<TResult, TStatus>
where TResult : class
where TStatus : Enum
{
public static Exec<TResult, TStatus> Start(TResult result, TStatus status)
{
return new Exec<TResult, TStatus>(result, status);
}
public static Exec<TResult, TStatus> Start(TStatus status)
{
return new Exec<TResult, TStatus>(status);
}
public static Exec<TResult, GeneralExecStatus> StartSuccess()
{
return new Exec<TResult, GeneralExecStatus>(GeneralExecStatus.success);
}
public static Exec<TResult, GeneralExecStatus> StartFailure()
{
return new Exec<TResult, GeneralExecStatus>(GeneralExecStatus.failure);
}
public static Exec<TResult, GeneralExecStatus> StartNotFound()
{
return new Exec<TResult, GeneralExecStatus>(GeneralExecStatus.not_found);
}
public Exec(TResult result, TStatus status)
{
Result = result;
Status = status;
}
public Exec(TStatus status)
{
Status = status;
}
public TResult? Result { get; internal set; }
public TStatus Status { get; internal set; }
public Exec<TResult, TStatus> Set(TResult result, TStatus status)
{
Result = result;
Status = status;
return this;
}
public Exec<TResult, TStatus> Set(TStatus status)
{
Status = status;
return this;
}
public Exec<TResult, TStatus> Set(TResult result)
{
Result = result;
return this;
}
}
@@ -0,0 +1,14 @@
namespace MyOffice.Core.Extensions;
public static class BoolExtensions
{
public static string ToLowerCase(this bool value)
{
return value.ToString().ToLower();
}
public static string? ToLowerCase(this bool? value)
{
return value == null ? null : value.ToString()?.ToLower();
}
}
@@ -0,0 +1,31 @@
namespace MyOffice.Core.Extensions;
using System.Security.Claims;
public static class ClaimsExtensions
{
public static string? GetValue(this IEnumerable<Claim> claims, string type)
{
return claims.FirstOrDefault(x => x.Type.Equals(type, StringComparison.OrdinalIgnoreCase))?.Value;
}
public static string? GetValue(this IEnumerable<Claim> claims, string[] types)
{
return claims.FirstOrDefault(x => types.Any(z => x.Type.Equals(z, StringComparison.OrdinalIgnoreCase)))?.Value;
}
public static string? GetEmail(this IEnumerable<Claim> claims)
{
return GetValue(claims, new[] { ClaimTypes.Email, "email" });
}
public static string? GetNameIdentifier(this IEnumerable<Claim> claims)
{
return GetValue(claims, ClaimTypes.NameIdentifier);
}
public static string? GetSID(this IEnumerable<Claim> claims)
{
return GetValue(claims, "sid");
}
}
@@ -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);
}
}
@@ -0,0 +1,19 @@
namespace MyOffice.Core.Extensions;
public static class GuidExtensions
{
public static bool EqualsString(this Guid guid, string str)
{
return guid.ToString().EqualsIgnoreCase(str);
}
public static string ToShort(this Guid guid)
{
return guid.ToString("N");
}
public static string? ToShort(this Guid? guid)
{
return guid?.ToString("N");
}
}
@@ -0,0 +1,65 @@
namespace MyOffice.Core.Extensions;
using Microsoft.Extensions.Logging;
public static class StringExtensions
{
public static bool IsMissing(this string? str)
{
return str == null || string.IsNullOrEmpty(str) || string.IsNullOrEmpty(str.Trim());
}
public static bool IsPresent(this string? str)
{
return !IsMissing(str);
}
public static string? NullIfEmpty(this string? str)
{
return IsMissing(str) ? null : str;
}
public static bool EqualsIgnoreCase(this string? str, string? value)
{
return str != null && str.Equals(value, StringComparison.OrdinalIgnoreCase);
}
public static string? SafeTrim(this string? str)
{
return str == null ? str : str!.Trim();
}
public static string? MaxOf(this string? str, int maxLength)
{
if (str == null)
{
return null;
}
if (str.Length < maxLength)
{
return str;
}
return str.Substring(0, maxLength);
}
public static bool AsBool(this string? str, bool defaultValue = false)
{
return true.ToString().Equals(str, StringComparison.OrdinalIgnoreCase) || defaultValue;
}
public static Guid AsGuid(this string str)
{
return Guid.Parse(str);
}
public static Guid? AsGuidNull(this string? str)
{
if (Guid.TryParse(str, out var guid))
{
return guid;
}
return null;
}
}
+31
View File
@@ -0,0 +1,31 @@
namespace MyOffice.Core.Helpers
{
using System.Text.Json;
using System.Text.Json.Serialization;
public static class JsonHelper
{
public static string ToJson(this object entity, JsonSerializerOptions? options = null)
{
options ??= new JsonSerializerOptions
{
MaxDepth = 0,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
ReferenceHandler = ReferenceHandler.IgnoreCycles,
WriteIndented = true,
};
return JsonSerializer.Serialize(entity, options);
}
}
/*public class CustomIgnoreReferenceHandler : ReferenceHandler
{
//public CustomIgnoreReferenceHandler() => HandlingStrategy = ReferenceHandlingStrategy.IgnoreCycles;
public CustomIgnoreReferenceHandler()
{
new HandlingStrategy { } = true;
}
public override ReferenceResolver CreateResolver() => new IgnoreReferenceResolver();
}*/
}
@@ -0,0 +1,18 @@
namespace MyOffice.Core.Helpers;
using MyOffice.Core.Extensions;
public class RandomizationHelper
{
public static string Generate(int length)
{
var result = "";
while(result.Length < length)
{
result += Guid.NewGuid().ToShort();
}
return result.Substring(0, length);
}
}
@@ -0,0 +1,47 @@
namespace MyOffice.Core.Identity;
using System;
using System.Diagnostics.Contracts;
public interface IExternalProviderValidator
{
string Provider { get; }
public bool IsConfigured { get; }
Task<ExternalProviderValidatorResult> ValidateAsync(string token);
}
public class ExternalProviderValidatorResult
{
public static ExternalProviderValidatorResult Failed()
{
return new ExternalProviderValidatorResult();
}
public static ExternalProviderValidatorResult Success(string email, bool emailVerified, string externalId,
string? fullName)
{
return new ExternalProviderValidatorResult(email, emailVerified, externalId, fullName);
}
public ExternalProviderValidatorResult()
{
IsSuccessed = false;
}
public ExternalProviderValidatorResult(string email, bool emailVerified, string externalId, string? fullName) :
this()
{
Email = email;
EmailVerified = emailVerified;
IsSuccessed = true;
ExternalId = externalId;
FullName = fullName;
}
public bool IsSuccessed { get; }
public string? Email { get; }
public bool EmailVerified { get; }
public string? ExternalId { get; }
public string? FullName { get; }
}
+6
View File
@@ -0,0 +1,6 @@
namespace MyOffice.Core;
public interface IDataModel
{
}
@@ -0,0 +1,6 @@
namespace MyOffice.Core;
public interface IDataModelDto<TSource> where TSource : IDataModel
{
}
+13
View File
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
</ItemGroup>
</Project>
+51
View File
@@ -0,0 +1,51 @@
namespace MyOffice.Data.Models.Accounts;
using Currencies;
using MyOffice.Core;
using MyOffice.Data.Models.Users;
public class Account: IDataModel
{
public Guid Id { get; set; }
public string CurrencyGlobalId { get; set; } = null!;
public CurrencyGlobal? CurrencyGlobal { get; set; }
public Guid? OwnerId { get; set; }
public User? Owner { get; set; }
public string Name { get; set; } = null!;
public IEnumerable<AccountAccess>? AccessRights { get; set; }
public IEnumerable<Motion>? Motions { get; set; }
public IEnumerable<AccountAccountCategory>? Categories { get; set; }
public IEnumerable<AccountAccessInvite>? Invites { get; set; }
}
public class AccountDetailed: IDataModel
{
public Account Account { get; set; } = null!;
public decimal TotalPlus { get; set; }
public decimal TotalMinus { get; set; }
public decimal Rest => TotalPlus - TotalMinus;
}
public class AccountSimple
{
public Guid Id { get; set; }
public string Name { get; set; } = null!;
public AccountAccessTypeEnum Type { 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; }
public decimal? TotalMinus { get; set; }
public decimal? Balance { get; set; }
}
public class MotionTotalSimple
{
public Guid? Id { get; set; }
public string Name { get; set; } = null!;
public string CurrencyId { get; set; } = null!;
public string CurrencyName { get; set; } = null!;
public decimal CurrencyRate { get; set; }
public decimal Amount { get; set; }
}
@@ -0,0 +1,28 @@
namespace MyOffice.Data.Models.Accounts;
using MyOffice.Data.Models.Users;
public enum AccountAccessTypeEnum
{
balance,
credit,
external,
other,
}
public class AccountAccess
{
public int Id { get; set; }
public Guid AccountId { get; set; }
public Account? Account { get; set; }
public Guid UserId { get; set; }
public User? User { get; set; }
public Guid OwnerId { get; set; }
public User? Owner { get; set; }
public bool IsAllowRead { get; set; }
public bool IsAllowWrite { get; set; }
public bool IsAllowManage { get; set; }
public AccountAccessTypeEnum Type { get; set; }
public string? Name { get; set; }
}
@@ -0,0 +1,17 @@
namespace MyOffice.Data.Models.Accounts;
using Users;
public class AccountAccessInvite
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public User? User { get; set; }
public Guid AccountId { get; set; }
public Account? Account { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime? AcceptedOn { get; set; }
public DateTime? RejectedOn { get; set; }
public string Email { get; set; } = null!;
public bool IsAllowWrite { get; set; }
}
@@ -0,0 +1,10 @@
namespace MyOffice.Data.Models.Accounts;
public class AccountAccountCategory
{
public int Id { get; set; }
public Guid AccountId { get; set; }
public Account Account { get; set; } = null!;
public Guid CategoryId { get; set; }
public AccountCategory Category { get; set; } = null!;
}
@@ -0,0 +1,12 @@
namespace MyOffice.Data.Models.Accounts;
using MyOffice.Data.Models.Users;
public class AccountCategory
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public User? User { get; set; }
public string Name { get; set; } = null!;
public IEnumerable<AccountAccountCategory>? Accounts { get; set; }
}
@@ -0,0 +1,10 @@
namespace MyOffice.Data.Models.Accounts.Domain;
using Currencies;
public class AccountWithRate
{
public Account Account { get; set; } = null!;
public Currency? Currency { get; set; }
public CurrencyRate? Rate { get; set; }
}
+22
View File
@@ -0,0 +1,22 @@
namespace MyOffice.Data.Models.Accounts;
using Items;
/// <summary>
/// Account motion
/// DateTime: 2023-01-01, Account: 'Debit card', Item.ItemGlobal: 'Primary salary', AmountPlus: 5000
/// </summary>
public class Motion
{
public Guid Id { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime DateTime { get; set; }
public Guid AccountId { get; set; }
public Account Account { get; set; } = null!;
public int ItemId { get; set; }
public Item Item { get; set; } = null!;
public string? Description { get; set; }
public decimal AmountPlus { get; set; }
public decimal AmountMinus { get; set; }
public DateTime? DeletedOn { get; set; }
}
@@ -0,0 +1,21 @@
namespace MyOffice.Data.Models.Currencies;
using MyOffice.Data.Models.Users;
public class Currency
{
public Guid Id { get; set; }
public string CurrencyGlobalId { get; set; } = null!;
public CurrencyGlobal? CurrencyGlobal { get; set; }
public Guid UserId { get; set; }
public User? User { get; set; }
public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
public IEnumerable<CurrencyRate>? Rates { get; set; }
public int? CurrentRateId { get; set; }
public CurrencyRate? CurrentRate { get; set; }
public bool IsPrimary { get; set; }
}
@@ -0,0 +1,26 @@
namespace MyOffice.Data.Models.Currencies;
using MyOffice.Data.Models.Accounts;
public enum CurrencyGlobalIdEnum
{
UAH,
USD,
EUR,
GBP,
RUB,
BTC,
ETH,
TON,
OTHER,
}
public class CurrencyGlobal
{
public string Id { get; set; } = null!;
public string Name { get; set; } = null!;
public string Symbol { get; set; } = null!;
public int DefaultQuantity { get; set; }
public IEnumerable<Currency>? Currencies { get; set; }
public IEnumerable<Account>? Accounts { get; set; }
}
@@ -0,0 +1,12 @@
namespace MyOffice.Data.Models.Currencies;
public class CurrencyRate
{
public int Id { get; set; }
public Guid CurrencyId { get; set; }
public Currency? Currency { get; set; }
public DateTime DateTime { get; set; }
public int Quantity { get; set; }
public decimal Rate { get; set; }
public IEnumerable<Currency>? Currencies { get; set; }
}
+20
View File
@@ -0,0 +1,20 @@
namespace MyOffice.Data.Models.Items;
using MyOffice.Data.Models.Accounts;
/// <summary>
/// User 'Item' linked to global item
/// ItemGlobal: 'Primary salary', ItemCategory: 'Incomes'
/// </summary>
public class Item
{
public int Id { get; set; }
/// <summary>
/// UnCategorized category is CategoryId = UserId
/// </summary>
public Guid CategoryId { get; set; }
public ItemCategory? Category { get; set; }
public Guid ItemGlobalId { get; set; }
public ItemGlobal ItemGlobal { get; set; } = null!;
public List<Motion>? Motions { get; set; }
}
@@ -0,0 +1,13 @@
namespace MyOffice.Data.Models.Items;
using MyOffice.Data.Models.Users;
public class ItemCategory
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public User User { get; set; } = null!;
public string Name { get; set; } = null!;
public List<Item> Items { get; set; } = null!;
public bool IsInternal { get; set; }
}
+8
View File
@@ -0,0 +1,8 @@
namespace MyOffice.Data.Models.Items;
public class ItemGlobal
{
public Guid Id { get; set; }
public string Name { get; set; } = null!;
public IEnumerable<Item> Items { get; set; } = null!;
}
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MyOffice.Core\MyOffice.Core.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
namespace MyOffice.Data.Models.Notifications;
public enum EmailTemplateEnum
{
PasswordRestore,
}
public class EmailTemplate
{
public string Id { get; set; }
public DateTime CreatedOn { get; set; }
public string Description { get; set; }
public string Subject { get; set; }
public string Sender { get; set; }
public string SenderName { get; set; }
public string Template { get; set; }
}
+35
View File
@@ -0,0 +1,35 @@
namespace MyOffice.Data.Models.Users;
using Accounts;
using Currencies;
using Items;
public class User
{
public User()
{
CurrencyId = "USD";
}
public Guid Id { get; set; }
public string UserName { get; set; } = null!;
public string Email { get; set; } = null!;
public string PasswordHash { get; set; } = null!;
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? FullName { get; set; }
public string? Phone { get; set; }
public bool IsEmailConfirmed { get; set; }
public IEnumerable<UserExternal>? UserClaims { get; set; }
public string CurrencyId { get; set; }
public CurrencyGlobal? Currency { get; set; }
public IEnumerable<Currency>? Currencies { get; set; }
public IEnumerable<AccountAccess>? AccountAccess { get; set; }
public IEnumerable<Motion>? AccountMotions { get; set; }
public IEnumerable<AccountCategory>? AccountCategories { get; set; }
public IEnumerable<ItemCategory>? ItemCategories { get; set; }
public IEnumerable<Account>? Accounts { get; set; }
public IEnumerable<AccountAccess>? AccountAccessOwners { get; set; }
public IEnumerable<AccountAccessInvite>? AccountAccessInvites { get; set; }
}
@@ -0,0 +1,12 @@
namespace MyOffice.Data.Models.Users;
public class UserExternal
{
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public Guid UserId { get; set; }
public User User { get; set; } = null!;
public string ExternalId { get; set; } = null!;
public string Email { get; set; } = null!;
public string Provider { get; set; } = null!;
}
@@ -0,0 +1,18 @@
namespace MyOffice.Data.Models.Verifications;
using MyOffice.Data.Models.Users;
public class VerificationCode
{
public int Id { get; set; }
public Guid UserId { get; set; }
public User? User { get; set; }
public string Code { get; set; } = null!;
public string DestinationType { get; set; } = null!;
public string Destination { get; set; } = null!;
public DateTime CreatedOn { get; set; }
public DateTime ExpiresOn { get; set; }
public DateTime? VerifiedOn { get; set; }
public string Template { get; set; } = null!;
public string? Metadata { get; set; }
}
@@ -0,0 +1,7 @@
namespace MyOffice.Data.Models.Verifications;
public enum VerificationCodeTemplateEnum
{
password_restore,
email_confirm,
}
@@ -0,0 +1,7 @@
namespace MyOffice.Data.Models.Verifications;
public enum VerificationCodeTypeEnum
{
email,
phone,
}
@@ -0,0 +1,81 @@
namespace MyOffice.Data.Repositories.Account;
using Microsoft.EntityFrameworkCore;
using Models.Accounts;
using MyOffice.Data.Repositories;
using MyOffice.DbContext;
public class AccountAccessInviteRepository : AppRepository<AccountAccessInvite>, IAccountAccessInviteRepository
{
public AccountAccessInviteRepository(AppDbContext context) : base(context)
{
}
public AccountAccessInvite? Get(Guid userId, string email)
{
return _context.AccountAccessInvites
.FirstOrDefault(x => x.UserId == userId
&& x.Email == email
&& !x.AcceptedOn.HasValue
&& !x.RejectedOn.HasValue
);
}
public async Task<AccountAccessInvite?> GetAsync(Guid userId, string email, CancellationToken cancellationToken = default)
{
return await _context.AccountAccessInvites
.FirstOrDefaultAsync(x => x.UserId == userId
&& x.Email == email
&& !x.AcceptedOn.HasValue
&& !x.RejectedOn.HasValue,
cancellationToken);
}
public bool Add(AccountAccessInvite invite)
{
return AddBase(invite) > 0;
}
public async Task<bool> AddAsync(AccountAccessInvite invite, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(invite, cancellationToken) > 0;
}
public bool Update(AccountAccessInvite invite)
{
return UpdateBase(invite) > 0;
}
public async Task<bool> UpdateAsync(AccountAccessInvite invite, CancellationToken cancellationToken = default)
{
return await UpdateBaseAsync(invite, cancellationToken) > 0;
}
public IEnumerable<AccountAccessInvite> GetActive(string email)
{
return _context
.AccountAccessInvites
.Include(x => x.Account)
.Where(x => x.Email == email && !x.AcceptedOn.HasValue && !x.RejectedOn.HasValue);
}
public async Task<List<AccountAccessInvite>> GetActiveAsync(string email, CancellationToken cancellationToken = default)
{
return await _context
.AccountAccessInvites
.Include(x => x.Account)
.Where(x => x.Email == email && !x.AcceptedOn.HasValue && !x.RejectedOn.HasValue)
.ToListAsync(cancellationToken);
}
public AccountAccessInvite? Get(Guid id)
{
return _context.AccountAccessInvites.FirstOrDefault(x => x.Id == id);
}
public async Task<AccountAccessInvite?> GetAsync(Guid id, CancellationToken cancellationToken = default)
{
return await _context.AccountAccessInvites.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
}
}
@@ -0,0 +1,42 @@
namespace MyOffice.Data.Repositories.Account;
using Models.Accounts;
using MyOffice.Data.Repositories;
using MyOffice.DbContext;
public class AccountAccessRepository : AppRepository<AccountAccess>, IAccountAccessRepository
{
public AccountAccessRepository(AppDbContext context) : base(context)
{
}
public bool Add(AccountAccess accountAccess)
{
return AddBase(accountAccess) > 0;
}
public async Task<bool> AddAsync(AccountAccess accountAccess, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(accountAccess, cancellationToken) > 0;
}
public bool Update(AccountAccess accountAccess)
{
return UpdateBase(accountAccess) > 0;
}
public async Task<bool> UpdateAsync(AccountAccess accountAccess, CancellationToken cancellationToken = default)
{
return await UpdateBaseAsync(accountAccess, cancellationToken) > 0;
}
public bool Delete(AccountAccess accountAccess)
{
return RemoveBase(accountAccess) > 0;
}
public async Task<bool> DeleteAsync(AccountAccess accountAccess, CancellationToken cancellationToken = default)
{
return await RemoveBaseAsync(accountAccess, cancellationToken) > 0;
}
}
@@ -0,0 +1,55 @@
namespace MyOffice.Data.Repositories.Account;
using Microsoft.EntityFrameworkCore;
using Models.Accounts;
using MyOffice.DbContext;
public class AccountAccountCategoryRepository : AppRepository<AccountAccountCategory>, IAccountAccountCategoryRepository
{
public AccountAccountCategoryRepository(AppDbContext context) : base(context)
{
}
public List<AccountAccountCategory> Get(Guid userId, Guid accountId, Guid categoryId)
{
return _context.AccountAccountCategories
.Include(x => x.Account)
.Include(x => x.Category)
.Where(x => x.AccountId == accountId && x.CategoryId == categoryId && x.Category.UserId == userId)
.ToList();
}
public async Task<List<AccountAccountCategory>> GetAsync(
Guid userId,
Guid accountId,
Guid categoryId,
CancellationToken cancellationToken = default
)
{
return await _context.AccountAccountCategories
.Include(x => x.Account)
.Include(x => x.Category)
.Where(x => x.AccountId == accountId && x.CategoryId == categoryId && x.Category.UserId == userId)
.ToListAsync(cancellationToken);
}
public bool Remove(AccountAccountCategory accountAccountCategory)
{
return RemoveBase(accountAccountCategory) > 0;
}
public async Task<bool> RemoveAsync(AccountAccountCategory accountAccountCategory, CancellationToken cancellationToken = default)
{
return await RemoveBaseAsync(accountAccountCategory, cancellationToken) > 0;
}
public bool Add(AccountAccountCategory accountAccountCategory)
{
return AddBase(accountAccountCategory) > 0;
}
public async Task<bool> AddAsync(AccountAccountCategory accountAccountCategory, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(accountAccountCategory, cancellationToken) > 0;
}
}
@@ -0,0 +1,73 @@
namespace MyOffice.Data.Repositories.Account;
using Microsoft.EntityFrameworkCore;
using Models.Accounts;
using MyOffice.Data.Repositories;
using MyOffice.DbContext;
public class AccountCategoryRepository : AppRepository<AccountCategory>, IAccountCategoryRepository
{
public AccountCategoryRepository(AppDbContext context) : base(context)
{
}
public List<AccountCategory> GetAll(Guid userId)
{
return _context.AccountCategories
.Include(x => x.Accounts)
.Where(x => x.UserId == userId)
.ToList();
}
public async Task<List<AccountCategory>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await _context.AccountCategories
.Include(x => x.Accounts)
.Where(x => x.UserId == userId)
.ToListAsync(cancellationToken);
}
public bool Add(AccountCategory accountCategory)
{
return AddBase(accountCategory) > 0;
}
public async Task<bool> AddAsync(AccountCategory accountCategory, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(accountCategory, cancellationToken) > 0;
}
public AccountCategory? Get(Guid userId, Guid id)
{
return _context.AccountCategories
.Include(x => x.Accounts)
.FirstOrDefault(x => x.Id == id && x.UserId == userId);
}
public async Task<AccountCategory?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default)
{
return await _context.AccountCategories
.Include(x => x.Accounts)
.FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, cancellationToken);
}
public bool Update(AccountCategory accountCategory)
{
return UpdateBase(accountCategory) > 0;
}
public async Task<bool> UpdateAsync(AccountCategory accountCategory, CancellationToken cancellationToken = default)
{
return await UpdateBaseAsync(accountCategory, cancellationToken) > 0;
}
public bool Remove(AccountCategory accountCategory)
{
return RemoveBase(accountCategory) > 0;
}
public async Task<bool> RemoveAsync(AccountCategory accountCategory, CancellationToken cancellationToken = default)
{
return await RemoveBaseAsync(accountCategory, cancellationToken) > 0;
}
}
@@ -0,0 +1,641 @@
namespace MyOffice.Data.Repositories.Account;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Models.Accounts;
using MyOffice.Data.Models.Accounts.Domain;
using MyOffice.Data.Models.Currencies;
using MyOffice.Data.Repositories;
using MyOffice.DbContext;
public class AccountRepository : AppRepository<Account>, IAccountRepository
{
private readonly ILogger<AccountRepository> _logger;
public AccountRepository(
AppDbContext context,
ILogger<AccountRepository> logger
) : base(context)
{
_logger = logger;
}
public List<Account> GetAll(Guid userId)
{
return _context.Accounts!
.Include(x => x.CurrencyGlobal)
// categories created with current user
.Include(x => x.Categories!.Where(c => c.Category.UserId == userId))!
.ThenInclude(x => x.Category)
// access rights created with current user
.Include(x => x.AccessRights!.Where(a => a.OwnerId == userId))!
.ThenInclude(x => x.User)
// require only one motions to check if can to delete account
.Include(x => x.Motions!.Take(1))!
// only accounts with access to current user
.Where(x => x.AccessRights!.Any(a => a.UserId == userId))
.ToList();
}
public async Task<List<Account>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await _context.Accounts!
.Include(x => x.CurrencyGlobal)
// categories created with current user
.Include(x => x.Categories!.Where(c => c.Category.UserId == userId))!
.ThenInclude(x => x.Category)
// access rights created with current user
.Include(x => x.AccessRights!.Where(a => a.OwnerId == userId))!
.ThenInclude(x => x.User)
// require only one motions to check if can to delete account
.Include(x => x.Motions!.Take(1))!
// only accounts with access to current user
.Where(x => x.AccessRights!.Any(a => a.UserId == userId))
.ToListAsync(cancellationToken);
}
public List<Account> GetByCategory(Guid userId, Guid categoryId)
{
return _context.Accounts!
.Include(x => x.CurrencyGlobal)
.Include(x => x.Categories)!
.ThenInclude(x => x.Category)
.Include(x => x.AccessRights)!
.ThenInclude(x => x.User)
.Include(x => x.Motions)!
.Where(x => x.Categories!.Any(c => c.CategoryId == categoryId) && x.AccessRights!.Any(a => a.UserId == userId))
.ToList();
}
public async Task<List<Account>> GetByCategoryAsync(Guid userId, Guid categoryId, CancellationToken cancellationToken = default)
{
return await _context.Accounts!
.Include(x => x.CurrencyGlobal)
.Include(x => x.Categories)!
.ThenInclude(x => x.Category)
.Include(x => x.AccessRights)!
.ThenInclude(x => x.User)
.Include(x => x.Motions)!
.Where(x => x.Categories!.Any(c => c.CategoryId == categoryId) && x.AccessRights!.Any(a => a.UserId == userId))
.ToListAsync(cancellationToken);
}
public List<AccountDetailed> GetByCategoryDetailed(Guid userId, Guid categoryId)
{
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.Categories!.Any(c => c.CategoryId == categoryId) && 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),
})
.ToList();
}
public Task<List<AccountDetailed>> GetByCategoryDetailedAsync(
Guid userId,
Guid categoryId,
CancellationToken cancellationToken = default
)
{
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.Categories!.Any(c => c.CategoryId == categoryId) && 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),
})
.ToListAsync(cancellationToken);
}
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 Task<AccountDetailed?> GetByIdDetailedAsync(
Guid userId,
Guid id,
CancellationToken cancellationToken = default
)
{
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),
})
.FirstOrDefaultAsync(cancellationToken);
}
public bool Add(Account account)
{
return AddBase(account) > 0;
}
public async Task<bool> AddAsync(Account account, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(account, cancellationToken) > 0;
}
public bool Delete(Account account)
{
return RemoveBase(account) > 0;
}
public async Task<bool> DeleteAsync(Account account, CancellationToken cancellationToken = default)
{
return await RemoveBaseAsync(account, cancellationToken) > 0;
}
public Account? Get(Guid userId, Guid id)
{
return _context.Accounts!
.Include(x => x.Categories!.Where(c => c.Category.UserId == userId))!
.ThenInclude(x => x.Category)
.Include(x => x.AccessRights)!
.ThenInclude(x => x.User)
//.Include(x => x.Motions)!
.FirstOrDefault(x => x.Id == id && x.AccessRights!.Any(r => r.UserId == userId));
}
public Task<Account?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default)
{
return _context.Accounts!
.Include(x => x.Categories!.Where(c => c.Category.UserId == userId))!
.ThenInclude(x => x.Category)
.Include(x => x.AccessRights)!
.ThenInclude(x => x.User)
.FirstOrDefaultAsync(
x => x.Id == id && x.AccessRights!.Any(r => r.UserId == userId),
cancellationToken);
}
public bool Update(Account account)
{
return UpdateBase(account) > 0;
}
public async Task<bool> UpdateAsync(Account account, CancellationToken cancellationToken = default)
{
return await UpdateBaseAsync(account, cancellationToken) > 0;
}
public bool Remove(Account account)
{
return RemoveBase(account) > 0;
}
public List<Account> FindAccounts(Guid userId, string term)
{
return _context.Accounts
.Where(x => x.AccessRights!.Any(a => a.UserId == userId))
.Where(x => x.Name.ToLower().Contains(term.ToLower()))
.ToList();
}
public async Task<List<Account>> FindAccountsAsync(Guid userId, string term, CancellationToken cancellationToken = default)
{
return await _context.Accounts
.Where(x => x.AccessRights!.Any(a => a.UserId == userId))
.Where(x => x.Name.ToLower().Contains(term.ToLower()))
.ToListAsync(cancellationToken);
}
public List<AccountWithRate> GetAccountsWithRate(Guid userId, DateTime date)
{
var accounts = _context.Accounts
.Where(x => x.AccessRights!.Any(a => a.UserId == userId))
.ToList();
var currencyIds = accounts
.Select(x => x.CurrencyGlobalId)
.ToList();
var rates = _context.CurrencyRates
.Include(x => x.Currency)
.Where(x => x.Currency!.UserId == userId)
.Where(x => x.DateTime <= date)
.Where(x => currencyIds.Contains(x.Currency!.CurrencyGlobalId))
.GroupBy(x => x.Currency!.CurrencyGlobalId)
.Select(x => x.OrderByDescending(r => r.DateTime).First())
.ToList();
return accounts
.Select(account =>
{
var rate = rates.FirstOrDefault(rate => rate.Currency!.CurrencyGlobalId == account.CurrencyGlobalId);
var result = new AccountWithRate
{
Account = account,
Currency = rate?.Currency,
Rate = rate,
};
return result;
})
.ToList();
}
public List<AccountSimple> GetRestAtDate(Guid userId, DateTime date)
{
return _context.AccountAccesses!
.Where(x => x.UserId == userId)
.Include(x => x.Account!)
.ThenInclude(x => x.CurrencyGlobal!)
.ThenInclude(x => x.Currencies!)
.ThenInclude(x => x.CurrentRate!)
.Include(x => x.Account)
.ThenInclude(x => x!.Motions)
.Select(x => new
{
Id = x.AccountId,
Name = x.Account!.Name,
Type = x.Type,
Currency = x.Account!.CurrencyGlobal!.Currencies!.FirstOrDefault(c => c.UserId == userId),
CurrentRate = x.Account!.CurrencyGlobal!.Currencies!.FirstOrDefault(c => c.UserId == userId)!.CurrentRate,
Plus = x.Account.Motions!
.Where(x => !x.DeletedOn.HasValue)
.Sum(m => m.AmountPlus),
Minus = x.Account.Motions!
.Where(x => !x.DeletedOn.HasValue)
.Sum(m => m.AmountMinus),
})
.ToList()
.Select(x => new AccountSimple
{
Id = x.Id,
Name = x.Name,
Type = x.Type,
CurrencyName = x.Currency?.Name,
CurrencyShortName = x.Currency?.ShortName,
CurrencyRate = x.CurrentRate?.Rate,
CurrencyQuantity = x.CurrentRate?.Quantity,
TotalMinus = x.Minus,
TotalPlus = x.Plus,
Balance = x.Plus - x.Minus,
})
.ToList();
}
public List<MotionTotalSimple> GetIncomeByCategories(Guid userId, DateTime from, DateTime to)
{
var accounts = GetAccountsWithRate(userId, to);
var accountIds = accounts.Select(x => x.Account.Id);
return _context.Motions
.Where(x => x.DateTime >= from && x.DateTime <= to)
.Where(x => accountIds.Contains(x.AccountId))
.Where(x => !x.Item.Category!.IsInternal)
.GroupBy(x => new
{
Id = x.Item.CategoryId,
Name = x.Item.Category!.Name,
IsUserCategory = x.Item.Category!.UserId == userId,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.ToList()
.Select(x => new MotionTotalSimple
{
Id = x.Key.IsUserCategory ? x.Key.Id : userId,
Name = x.Key.Name,
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Amount = x.Sum(a => a.AmountPlus),
})
.ToList();
}
public List<MotionTotalSimple> GetIncomeByCategory(Guid userId, Guid categoryId, DateTime from, DateTime to)
{
return _context.Motions
.Where(x => x.DateTime >= from && x.DateTime <= to)
.Where(x => x.Item.Category!.UserId == userId)
.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,
Name = x.Item.ItemGlobal!.Name,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.Select(x => new MotionTotalSimple
{
Name = x.Key.Name,
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Amount = x.Sum(a => a.AmountPlus),
})
.ToList();
}
public List<MotionTotalSimple> GetOutcomeByCategories(Guid userId, DateTime from, DateTime to)
{
var accounts = GetAccountsWithRate(userId, to);
var accountIds = accounts.Select(x => x.Account.Id);
return _context.Motions
.Where(x => x.DateTime >= from && x.DateTime <= to)
.Where(x => accountIds.Contains(x.AccountId))
.Where(x => !x.Item.Category!.IsInternal)
.GroupBy(x => new
{
Id = x.Item.CategoryId,
Name = x.Item.Category!.Name,
IsUserCategory = x.Item.Category!.UserId == userId,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.Select(x => new MotionTotalSimple
{
Id = x.Key.IsUserCategory ? x.Key.Id : userId,
Name = x.Key.IsUserCategory ? x.Key.Name : "UnCategorized",
//Name = x.Key.Name,
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Amount = x.Sum(a => a.AmountMinus),
}).ToList();
}
public List<MotionTotalSimple> GetOutcomeByCategory(Guid userId, Guid categoryId, DateTime from, DateTime to)
{
var accounts = GetAccountsWithRate(userId, to);
var accountIds = accounts.Select(x => x.Account.Id);
return _context.Motions
.Where(x => x.DateTime >= from && x.DateTime <= to)
.Where(x => accountIds.Contains(x.AccountId))
.Where(x => !x.Item.Category!.IsInternal)
.Where(x => x.Item.CategoryId == categoryId)
.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();
}
public async Task<List<AccountWithRate>> GetAccountsWithRateAsync(
Guid userId,
DateTime date,
CancellationToken cancellationToken = default
)
{
var accounts = await _context.Accounts
.Where(x => x.AccessRights!.Any(a => a.UserId == userId))
.ToListAsync(cancellationToken);
var currencyIds = accounts
.Select(x => x.CurrencyGlobalId)
.ToList();
var rates = await _context.CurrencyRates
.Include(x => x.Currency)
.Where(x => x.Currency!.UserId == userId)
.Where(x => x.DateTime <= date)
.Where(x => currencyIds.Contains(x.Currency!.CurrencyGlobalId))
.GroupBy(x => x.Currency!.CurrencyGlobalId)
.Select(x => x.OrderByDescending(r => r.DateTime).First())
.ToListAsync(cancellationToken);
return accounts
.Select(account =>
{
var rate = rates.FirstOrDefault(r => r.Currency!.CurrencyGlobalId == account.CurrencyGlobalId);
return new AccountWithRate
{
Account = account,
Currency = rate?.Currency,
Rate = rate,
};
})
.ToList();
}
public async Task<List<AccountSimple>> GetRestAtDateAsync(
Guid userId,
DateTime date,
CancellationToken cancellationToken = default
)
{
var rows = await _context.AccountAccesses!
.Where(x => x.UserId == userId)
.Include(x => x.Account!)
.ThenInclude(x => x.CurrencyGlobal!)
.ThenInclude(x => x.Currencies!)
.ThenInclude(x => x.CurrentRate!)
.Include(x => x.Account)
.ThenInclude(x => x!.Motions)
.Select(x => new
{
Id = x.AccountId,
Name = x.Account!.Name,
Type = x.Type,
Currency = x.Account!.CurrencyGlobal!.Currencies!.FirstOrDefault(c => c.UserId == userId),
CurrentRate = x.Account!.CurrencyGlobal!.Currencies!.FirstOrDefault(c => c.UserId == userId)!.CurrentRate,
Plus = x.Account.Motions!
.Where(m => !m.DeletedOn.HasValue)
.Sum(m => m.AmountPlus),
Minus = x.Account.Motions!
.Where(m => !m.DeletedOn.HasValue)
.Sum(m => m.AmountMinus),
})
.ToListAsync(cancellationToken);
return rows
.Select(x => new AccountSimple
{
Id = x.Id,
Name = x.Name,
Type = x.Type,
CurrencyName = x.Currency?.Name,
CurrencyShortName = x.Currency?.ShortName,
CurrencyRate = x.CurrentRate?.Rate,
CurrencyQuantity = x.CurrentRate?.Quantity,
TotalMinus = x.Minus,
TotalPlus = x.Plus,
Balance = x.Plus - x.Minus,
})
.ToList();
}
public async Task<List<MotionTotalSimple>> GetIncomeByCategoriesAsync(
Guid userId,
DateTime from,
DateTime to,
CancellationToken cancellationToken = default
)
{
var accounts = await GetAccountsWithRateAsync(userId, to, cancellationToken);
var accountIds = accounts.Select(x => x.Account.Id).ToList();
var groups = await _context.Motions
.Where(x => x.DateTime >= from && x.DateTime <= to)
.Where(x => accountIds.Contains(x.AccountId))
.Where(x => !x.Item.Category!.IsInternal)
.GroupBy(x => new
{
Id = x.Item.CategoryId,
Name = x.Item.Category!.Name,
IsUserCategory = x.Item.Category!.UserId == userId,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.ToListAsync(cancellationToken);
return groups
.Select(x => new MotionTotalSimple
{
Id = x.Key.IsUserCategory ? x.Key.Id : userId,
Name = x.Key.Name,
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Amount = x.Sum(a => a.AmountPlus),
})
.ToList();
}
public Task<List<MotionTotalSimple>> GetIncomeByCategoryAsync(
Guid userId,
Guid categoryId,
DateTime from,
DateTime to,
CancellationToken cancellationToken = default
)
{
return _context.Motions
.Where(x => x.DateTime >= from && x.DateTime <= to)
.Where(x => x.Item.Category!.UserId == userId)
.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,
Name = x.Item.ItemGlobal!.Name,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.Select(x => new MotionTotalSimple
{
Name = x.Key.Name,
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Amount = x.Sum(a => a.AmountPlus),
})
.ToListAsync(cancellationToken);
}
public async Task<List<MotionTotalSimple>> GetOutcomeByCategoriesAsync(
Guid userId,
DateTime from,
DateTime to,
CancellationToken cancellationToken = default
)
{
var accounts = await GetAccountsWithRateAsync(userId, to, cancellationToken);
var accountIds = accounts.Select(x => x.Account.Id).ToList();
return await _context.Motions
.Where(x => x.DateTime >= from && x.DateTime <= to)
.Where(x => accountIds.Contains(x.AccountId))
.Where(x => !x.Item.Category!.IsInternal)
.GroupBy(x => new
{
Id = x.Item.CategoryId,
Name = x.Item.Category!.Name,
IsUserCategory = x.Item.Category!.UserId == userId,
CurrencyId = x.Account.CurrencyGlobalId,
CurrencyName = x.Account.CurrencyGlobal!.Name,
})
.Select(x => new MotionTotalSimple
{
Id = x.Key.IsUserCategory ? x.Key.Id : userId,
Name = x.Key.IsUserCategory ? x.Key.Name : "UnCategorized",
CurrencyId = x.Key.CurrencyId,
CurrencyName = x.Key.CurrencyName,
Amount = x.Sum(a => a.AmountMinus),
})
.ToListAsync(cancellationToken);
}
public async Task<List<MotionTotalSimple>> GetOutcomeByCategoryAsync(
Guid userId,
Guid categoryId,
DateTime from,
DateTime to,
CancellationToken cancellationToken = default
)
{
var accounts = await GetAccountsWithRateAsync(userId, to, cancellationToken);
var accountIds = accounts.Select(x => x.Account.Id).ToList();
return await _context.Motions
.Where(x => x.DateTime >= from && x.DateTime <= to)
.Where(x => accountIds.Contains(x.AccountId))
.Where(x => !x.Item.Category!.IsInternal)
.Where(x => x.Item.CategoryId == categoryId)
.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),
})
.ToListAsync(cancellationToken);
}
}
@@ -0,0 +1,17 @@
namespace MyOffice.Data.Repositories.Account;
using Models.Accounts;
public interface IAccountAccessInviteRepository
{
AccountAccessInvite? Get(Guid userId, string email);
Task<AccountAccessInvite?> GetAsync(Guid userId, string email, CancellationToken cancellationToken = default);
IEnumerable<AccountAccessInvite> GetActive(string email);
Task<List<AccountAccessInvite>> GetActiveAsync(string email, CancellationToken cancellationToken = default);
AccountAccessInvite? Get(Guid id);
Task<AccountAccessInvite?> GetAsync(Guid id, CancellationToken cancellationToken = default);
bool Add(AccountAccessInvite invite);
Task<bool> AddAsync(AccountAccessInvite invite, CancellationToken cancellationToken = default);
bool Update(AccountAccessInvite invite);
Task<bool> UpdateAsync(AccountAccessInvite invite, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,13 @@
namespace MyOffice.Data.Repositories.Account;
using Models.Accounts;
public interface IAccountAccessRepository
{
bool Add(AccountAccess accountAccess);
Task<bool> AddAsync(AccountAccess accountAccess, CancellationToken cancellationToken = default);
bool Update(AccountAccess accountAccess);
Task<bool> UpdateAsync(AccountAccess accountAccess, CancellationToken cancellationToken = default);
bool Delete(AccountAccess accountAccess);
Task<bool> DeleteAsync(AccountAccess accountAccess, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,13 @@
namespace MyOffice.Data.Repositories.Account;
using Models.Accounts;
public interface IAccountAccountCategoryRepository
{
List<AccountAccountCategory> Get(Guid userId, Guid accountId, Guid categoryId);
Task<List<AccountAccountCategory>> GetAsync(Guid userId, Guid accountId, Guid categoryId, CancellationToken cancellationToken = default);
bool Remove(AccountAccountCategory accountAccountCategory);
Task<bool> RemoveAsync(AccountAccountCategory accountAccountCategory, CancellationToken cancellationToken = default);
bool Add(AccountAccountCategory accountAccountCategory);
Task<bool> AddAsync(AccountAccountCategory accountAccountCategory, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,17 @@
namespace MyOffice.Data.Repositories.Account;
using Models.Accounts;
public interface IAccountCategoryRepository
{
List<AccountCategory> GetAll(Guid userId);
Task<List<AccountCategory>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default);
bool Add(AccountCategory accountCategory);
Task<bool> AddAsync(AccountCategory accountCategory, CancellationToken cancellationToken = default);
AccountCategory? Get(Guid userId, Guid id);
Task<AccountCategory?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default);
bool Update(AccountCategory accountCategory);
Task<bool> UpdateAsync(AccountCategory accountCategory, CancellationToken cancellationToken = default);
bool Remove(AccountCategory accountCategory);
Task<bool> RemoveAsync(AccountCategory accountCategory, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,37 @@
namespace MyOffice.Data.Repositories.Account;
using Models.Accounts;
public interface IAccountRepository
{
List<Account> GetAll(Guid userId);
Task<List<Account>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default);
List<Account> GetByCategory(Guid userId, Guid categoryId);
Task<List<Account>> GetByCategoryAsync(Guid userId, Guid categoryId, CancellationToken cancellationToken = default);
List<AccountDetailed> GetByCategoryDetailed(Guid userId, Guid categoryId);
Task<List<AccountDetailed>> GetByCategoryDetailedAsync(Guid userId, Guid categoryId, CancellationToken cancellationToken = default);
AccountDetailed? GetByIdDetailed(Guid userId, Guid id);
Task<AccountDetailed?> GetByIdDetailedAsync(Guid userId, Guid id, CancellationToken cancellationToken = default);
bool Add(Account account);
Task<bool> AddAsync(Account account, CancellationToken cancellationToken = default);
bool Delete(Account account);
Task<bool> DeleteAsync(Account account, CancellationToken cancellationToken = default);
Account? Get(Guid userId, Guid id);
Task<Account?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default);
bool Update(Account account);
Task<bool> UpdateAsync(Account account, CancellationToken cancellationToken = default);
bool Remove(Account account);
List<Account> FindAccounts(Guid userId, string term);
Task<List<Account>> FindAccountsAsync(Guid userId, string term, CancellationToken cancellationToken = default);
List<AccountSimple> GetRestAtDate(Guid userId, DateTime date);
Task<List<AccountSimple>> GetRestAtDateAsync(Guid userId, DateTime date, CancellationToken cancellationToken = default);
List<MotionTotalSimple> GetIncomeByCategories(Guid userId, DateTime from, DateTime to);
Task<List<MotionTotalSimple>> GetIncomeByCategoriesAsync(Guid userId, DateTime from, DateTime to, CancellationToken cancellationToken = default);
List<MotionTotalSimple> GetIncomeByCategory(Guid userId, Guid categoryId, DateTime from, DateTime to);
Task<List<MotionTotalSimple>> GetIncomeByCategoryAsync(Guid userId, Guid categoryId, DateTime from, DateTime to, CancellationToken cancellationToken = default);
List<MotionTotalSimple> GetOutcomeByCategories(Guid userId, DateTime from, DateTime to);
Task<List<MotionTotalSimple>> GetOutcomeByCategoriesAsync(Guid userId, DateTime from, DateTime to, CancellationToken cancellationToken = default);
List<MotionTotalSimple> GetOutcomeByCategory(Guid userId, Guid categoryId, DateTime from, DateTime to);
Task<List<MotionTotalSimple>> GetOutcomeByCategoryAsync(Guid userId, Guid categoryId, DateTime from, DateTime to, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,12 @@
namespace MyOffice.Data.Repositories.Account;
using Models.Accounts;
public interface IMotionRepository
{
Task<bool> AddAsync(Motion motion, CancellationToken cancellationToken = default);
Task<List<Motion>> GetByAccountAsync(Guid accountId, DateTime dateFrom, DateTime dateTo, CancellationToken cancellationToken = default);
Task<Motion?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default);
Task<bool> UpdateAsync(Motion motion, CancellationToken cancellationToken = default);
Task<bool> RemoveAsync(Motion motion, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,55 @@
namespace MyOffice.Data.Repositories.Account;
using Microsoft.EntityFrameworkCore;
using Models.Accounts;
using MyOffice.DbContext;
public class MotionRepository : AppRepository<Motion>, IMotionRepository
{
public MotionRepository(AppDbContext context) : base(context)
{
}
public async Task<bool> AddAsync(Motion motion, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(motion, cancellationToken) > 0;
}
public async Task<List<Motion>> GetByAccountAsync(
Guid accountId,
DateTime dateFrom,
DateTime dateTo,
CancellationToken cancellationToken = default
)
{
return await _context
.Motions
.Include(x => x.Item)
.ThenInclude(x => x.ItemGlobal)
.Where(x => x.AccountId == accountId && x.DateTime >= dateFrom && x.DateTime <= dateTo)
.OrderByDescending(x => x.DateTime)
.ThenByDescending(x => x.CreatedOn)
.ToListAsync(cancellationToken);
}
public async Task<Motion?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default)
{
return await _context
.Motions
.Include(x => x.Item)
.ThenInclude(x => x.ItemGlobal)
.FirstOrDefaultAsync(
x => x.Account!.AccessRights!.Any(a => a.UserId == userId) && x.Id == id,
cancellationToken);
}
public async Task<bool> UpdateAsync(Motion motion, CancellationToken cancellationToken = default)
{
return await UpdateBaseAsync(motion, cancellationToken) > 0;
}
public async Task<bool> RemoveAsync(Motion motion, CancellationToken cancellationToken = default)
{
return await RemoveBaseAsync(motion, cancellationToken) > 0;
}
}
@@ -0,0 +1,10 @@
namespace MyOffice.Data.Repositories;
using DbContext;
public class AppRepository<TEntity> : RepositoryBase<TEntity> where TEntity : class
{
public AppRepository(AppDbContext context) : base(context)
{
}
}
@@ -0,0 +1,22 @@
namespace MyOffice.Data.Repositories.Currency;
using Microsoft.EntityFrameworkCore;
using Models.Currencies;
using MyOffice.DbContext;
public class CurrencyGlobalRepository : AppRepository<CurrencyGlobal>, ICurrencyGlobalRepository
{
public CurrencyGlobalRepository(AppDbContext context) : base(context)
{
}
public List<CurrencyGlobal> GetAll()
{
return _context.CurrencyGlobals.ToList();
}
public async Task<List<CurrencyGlobal>> GetAllAsync(CancellationToken cancellationToken = default)
{
return await _context.CurrencyGlobals.ToListAsync(cancellationToken);
}
}
@@ -0,0 +1,115 @@
namespace MyOffice.Data.Repositories.Currency;
using System.Xml.Schema;
using Microsoft.EntityFrameworkCore;
using Models.Currencies;
using MyOffice.DbContext;
public class CurrencyRateRepository : AppRepository<CurrencyRate>, ICurrencyRateRepository
{
public CurrencyRateRepository(AppDbContext context) : base(context)
{
}
public List<CurrencyRate> GetLastRates(Guid currencyId, DateTime? before = null, int count = 1)
{
before = before ?? DateTime.UtcNow;
return _context.CurrencyRates
.Where(x => x.CurrencyId == currencyId)
.Where(x => x.DateTime <= before)
.OrderByDescending(x => x.DateTime)
.ThenByDescending(x => x.Id)
.Take(count)
.ToList();
}
public async Task<List<CurrencyRate>> GetLastRatesAsync(
Guid currencyId,
DateTime? before = null,
int count = 1,
CancellationToken cancellationToken = default)
{
before ??= DateTime.UtcNow;
return await _context.CurrencyRates
.Where(x => x.CurrencyId == currencyId)
.Where(x => x.DateTime <= before)
.OrderByDescending(x => x.DateTime)
.ThenByDescending(x => x.Id)
.Take(count)
.ToListAsync(cancellationToken);
}
public Dictionary<string, CurrencyRate> GetLastRates(Guid userId, List<string> currencyIds, DateTime? before = null)
{
return _context.CurrencyRates
.Include(x => x.Currency)
.Include(x => x.Currency!.CurrencyGlobal)
.Where(x => x.DateTime <= before)
.Where(x => x.Currency!.UserId == userId)
.Where(x => currencyIds.Contains(x.Currency!.CurrencyGlobalId))
.GroupBy(x => new
{
x.Currency!.CurrencyGlobalId
}, (key, g) => new
{
key.CurrencyGlobalId,
rate = g.OrderByDescending(x => x.DateTime).First()
})
.ToDictionary(x => x.CurrencyGlobalId, x => x.rate);
}
public async Task<Dictionary<string, CurrencyRate>> GetLastRatesAsync(
Guid userId,
List<string> currencyIds,
DateTime? before = null,
CancellationToken cancellationToken = default
)
{
var rows = await _context.CurrencyRates
.Include(x => x.Currency)
.Include(x => x.Currency!.CurrencyGlobal)
.Where(x => x.DateTime <= before)
.Where(x => x.Currency!.UserId == userId)
.Where(x => currencyIds.Contains(x.Currency!.CurrencyGlobalId))
.GroupBy(x => new
{
x.Currency!.CurrencyGlobalId
}, (key, g) => new
{
key.CurrencyGlobalId,
rate = g.OrderByDescending(x => x.DateTime).First()
})
.ToListAsync(cancellationToken);
return rows.ToDictionary(x => x.CurrencyGlobalId, x => x.rate);
}
public bool AddRate(CurrencyRate currencyRate)
{
return this.AddBase(currencyRate) > 0;
}
public async Task<bool> AddRateAsync(CurrencyRate currencyRate, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(currencyRate, cancellationToken) > 0;
}
public List<CurrencyRate> GetAtDate(Guid currencyId, DateTime date)
{
return _context.CurrencyRates
.Where(x => x.CurrencyId == currencyId && x.DateTime == date)
.ToList();
}
public async Task<List<CurrencyRate>> GetAtDateAsync(
Guid currencyId,
DateTime date,
CancellationToken cancellationToken = default)
{
return await _context.CurrencyRates
.Where(x => x.CurrencyId == currencyId && x.DateTime == date)
.ToListAsync(cancellationToken);
}
}
@@ -0,0 +1,102 @@
namespace MyOffice.Data.Repositories.Currency;
using Microsoft.EntityFrameworkCore;
using Models.Currencies;
using MyOffice.Data.Repositories;
using MyOffice.DbContext;
public class CurrencyRepository : AppRepository<Currency>, ICurrencyRepository
{
public CurrencyRepository(AppDbContext context) : base(context)
{
}
public List<Currency> GetAll(Guid userId)
{
return _context.Currencies
.Include(x => x.CurrencyGlobal)
.Where(x => x.UserId == userId)
.ToList();
}
public async Task<List<Currency>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await _context.Currencies
.Include(x => x.CurrencyGlobal)
.Where(x => x.UserId == userId)
.ToListAsync(cancellationToken);
}
public Currency? Get(Guid userId, Guid id)
{
return _context
.Currencies
.Include(x => x.CurrencyGlobal)
.FirstOrDefault(x => x.Id == id && x.UserId == userId);
}
public async Task<Currency?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default)
{
return await _context
.Currencies
.Include(x => x.CurrencyGlobal)
.FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, cancellationToken);
}
public Currency? GetByGlobalCurrency(Guid userId, string globalCurrencyId)
{
return _context.Currencies.FirstOrDefault(x => x.UserId == userId && x.CurrencyGlobalId == globalCurrencyId);
}
public async Task<Currency?> GetByGlobalCurrencyAsync(
Guid userId,
string globalCurrencyId,
CancellationToken cancellationToken = default)
{
return await _context.Currencies.FirstOrDefaultAsync(
x => x.UserId == userId && x.CurrencyGlobalId == globalCurrencyId,
cancellationToken);
}
public bool Add(Currency currency)
{
return AddBase(currency) > 0;
}
public async Task<bool> AddAsync(Currency currency, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(currency, cancellationToken) > 0;
}
public bool Update(Currency currency)
{
return UpdateBase(currency) > 0;
}
public async Task<bool> UpdateAsync(Currency currency, CancellationToken cancellationToken = default)
{
return await UpdateBaseAsync(currency, cancellationToken) > 0;
}
public bool Remove(Currency currency)
{
return RemoveBase(currency) > 0;
}
public async Task<bool> RemoveAsync(Currency currency, CancellationToken cancellationToken = default)
{
return await RemoveBaseAsync(currency, cancellationToken) > 0;
}
public List<Currency> GetPrimaries(Guid userId)
{
return _context.Currencies.Where(x => x.UserId == userId && x.IsPrimary).ToList();
}
public async Task<List<Currency>> GetPrimariesAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await _context.Currencies
.Where(x => x.UserId == userId && x.IsPrimary)
.ToListAsync(cancellationToken);
}
}
@@ -0,0 +1,9 @@
namespace MyOffice.Data.Repositories.Currency;
using Models.Currencies;
public interface ICurrencyGlobalRepository
{
List<CurrencyGlobal> GetAll();
Task<List<CurrencyGlobal>> GetAllAsync(CancellationToken cancellationToken = default);
}
@@ -0,0 +1,19 @@
namespace MyOffice.Data.Repositories.Currency;
using Models.Currencies;
public interface ICurrencyRateRepository
{
List<CurrencyRate> GetLastRates(Guid currencyId, DateTime? before = null, int count = 1);
Task<List<CurrencyRate>> GetLastRatesAsync(Guid currencyId, DateTime? before = null, int count = 1, CancellationToken cancellationToken = default);
Dictionary<string, CurrencyRate> GetLastRates(Guid userId, List<string> currencyIds, DateTime? before = null);
Task<Dictionary<string, CurrencyRate>> GetLastRatesAsync(
Guid userId,
List<string> currencyIds,
DateTime? before = null,
CancellationToken cancellationToken = default);
bool AddRate(CurrencyRate currencyRate);
Task<bool> AddRateAsync(CurrencyRate currencyRate, CancellationToken cancellationToken = default);
List<CurrencyRate> GetAtDate(Guid currencyId, DateTime date);
Task<List<CurrencyRate>> GetAtDateAsync(Guid currencyId, DateTime date, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,21 @@
namespace MyOffice.Data.Repositories.Currency;
using Models.Currencies;
public interface ICurrencyRepository
{
List<Currency> GetAll(Guid userId);
Task<List<Currency>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default);
Currency? Get(Guid userId, Guid id);
Task<Currency?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default);
Currency? GetByGlobalCurrency(Guid userId, string globalCurrencyId);
Task<Currency?> GetByGlobalCurrencyAsync(Guid userId, string globalCurrencyId, CancellationToken cancellationToken = default);
bool Add(Currency currency);
Task<bool> AddAsync(Currency currency, CancellationToken cancellationToken = default);
bool Update(Currency currency);
Task<bool> UpdateAsync(Currency currency, CancellationToken cancellationToken = default);
bool Remove(Currency currency);
Task<bool> RemoveAsync(Currency currency, CancellationToken cancellationToken = default);
List<Currency> GetPrimaries(Guid userId);
Task<List<Currency>> GetPrimariesAsync(Guid userId, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,17 @@
namespace MyOffice.Data.Repositories.Item;
using MyOffice.Data.Models.Items;
public interface IItemCategoryRepository
{
List<ItemCategory> GetAll(Guid userId);
Task<List<ItemCategory>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default);
bool Add(ItemCategory accountCategory);
Task<bool> AddAsync(ItemCategory accountCategory, CancellationToken cancellationToken = default);
ItemCategory? Get(Guid userId, Guid id);
Task<ItemCategory?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default);
bool Update(ItemCategory accountCategory);
Task<bool> UpdateAsync(ItemCategory accountCategory, CancellationToken cancellationToken = default);
bool Remove(ItemCategory accountCategory);
Task<bool> RemoveAsync(ItemCategory accountCategory, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,14 @@
namespace MyOffice.Data.Repositories.Item;
using MyOffice.Data.Models.Items;
public interface IItemGlobalRepository
{
ItemGlobal? Get(Guid id);
ItemGlobal? GetByName(string name);
Task<ItemGlobal?> GetByNameAsync(string name, CancellationToken cancellationToken = default);
bool Add(ItemGlobal itemGlobal);
Task<bool> AddAsync(ItemGlobal itemGlobal, CancellationToken cancellationToken = default);
List<ItemGlobal> GetAvailableToUser(Guid userId);
Task<List<ItemGlobal>> GetAvailableToUserAsync(Guid userId, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,19 @@
namespace MyOffice.Data.Repositories.Item;
using MyOffice.Data.Models.Items;
public interface IItemRepository
{
List<Item> GetAll(Guid userId);
Task<List<Item>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default);
List<Item> GetByCategory(Guid userId, Guid categoryId);
Task<List<Item>> GetByCategoryAsync(Guid userId, Guid categoryId, CancellationToken cancellationToken = default);
Item? GetByGlobal(Guid userId, Guid globalItemId);
Task<Item?> GetByGlobalAsync(Guid userId, Guid globalItemId, CancellationToken cancellationToken = default);
bool Add(Item item);
Task<bool> AddAsync(Item item, CancellationToken cancellationToken = default);
bool Update(Item item);
Task<bool> UpdateAsync(Item item, CancellationToken cancellationToken = default);
List<Item> Find(Guid userId, string term, int limit);
Task<List<Item>> FindAsync(Guid userId, string term, int limit, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,72 @@
namespace MyOffice.Data.Repositories.Item;
using Microsoft.EntityFrameworkCore;
using MyOffice.Data.Models.Items;
using MyOffice.DbContext;
public class ItemCategoryRepository : AppRepository<ItemCategory>, IItemCategoryRepository
{
public ItemCategoryRepository(AppDbContext context) : base(context)
{
}
public List<ItemCategory> GetAll(Guid userId)
{
return _context.ItemCategories
.Include(x => x.Items)
.Where(x => x.UserId == userId)
.ToList();
}
public async Task<List<ItemCategory>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await _context.ItemCategories
.Include(x => x.Items)
.Where(x => x.UserId == userId)
.ToListAsync(cancellationToken);
}
public bool Add(ItemCategory itemCategory)
{
return AddBase(itemCategory) > 0;
}
public async Task<bool> AddAsync(ItemCategory itemCategory, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(itemCategory, cancellationToken) > 0;
}
public ItemCategory? Get(Guid userId, Guid id)
{
return _context.ItemCategories
.Include(x => x.Items)
.FirstOrDefault(x => x.Id == id && x.UserId == userId);
}
public async Task<ItemCategory?> GetAsync(Guid userId, Guid id, CancellationToken cancellationToken = default)
{
return await _context.ItemCategories
.Include(x => x.Items)
.FirstOrDefaultAsync(x => x.Id == id && x.UserId == userId, cancellationToken);
}
public bool Update(ItemCategory itemCategory)
{
return UpdateBase(itemCategory) > 0;
}
public async Task<bool> UpdateAsync(ItemCategory itemCategory, CancellationToken cancellationToken = default)
{
return await UpdateBaseAsync(itemCategory, cancellationToken) > 0;
}
public bool Remove(ItemCategory itemCategory)
{
return RemoveBase(itemCategory) > 0;
}
public async Task<bool> RemoveAsync(ItemCategory itemCategory, CancellationToken cancellationToken = default)
{
return await RemoveBaseAsync(itemCategory, cancellationToken) > 0;
}
}
@@ -0,0 +1,69 @@
namespace MyOffice.Data.Repositories.Item;
using Microsoft.EntityFrameworkCore;
using MyOffice.Data.Models.Items;
using MyOffice.DbContext;
public class ItemGlobalRepository : AppRepository<ItemGlobal>, IItemGlobalRepository
{
public ItemGlobalRepository(AppDbContext context) : base(context)
{
}
public ItemGlobal? Get(Guid id)
{
return _context.ItemGlobals.FirstOrDefault(x => x.Id == id);
}
public ItemGlobal? GetByName(string name)
{
return _context.ItemGlobals.FirstOrDefault(x => x.Name == name);
}
public Task<ItemGlobal?> GetByNameAsync(string name, CancellationToken cancellationToken = default)
{
return _context.ItemGlobals.FirstOrDefaultAsync(x => x.Name == name, cancellationToken);
}
public bool Add(ItemGlobal itemGlobal)
{
return AddBase(itemGlobal) > 0;
}
public async Task<bool> AddAsync(ItemGlobal itemGlobal, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(itemGlobal, cancellationToken) > 0;
}
public List<ItemGlobal> GetAvailableToUser(Guid userId)
{
return _context.Motions
.Include(x => x.Item)
.ThenInclude(x => x.ItemGlobal)
.ThenInclude(x => x.Items)
.ThenInclude(x => x.Category)
.Where(x => x.Account.AccessRights!.Any(a => a.UserId == userId))
.Where(x => x.Item.ItemGlobal.Items.All(g => g.Category!.UserId != userId))
.Select(x => x.Item.ItemGlobal)
.GroupBy(x => x.Id)
.Select(x => x.First())
.ToList();
}
public async Task<List<ItemGlobal>> GetAvailableToUserAsync(
Guid userId,
CancellationToken cancellationToken = default)
{
return await _context.Motions
.Include(x => x.Item)
.ThenInclude(x => x.ItemGlobal)
.ThenInclude(x => x.Items)
.ThenInclude(x => x.Category)
.Where(x => x.Account.AccessRights!.Any(a => a.UserId == userId))
.Where(x => x.Item.ItemGlobal.Items.All(g => g.Category!.UserId != userId))
.Select(x => x.Item.ItemGlobal)
.GroupBy(x => x.Id)
.Select(x => x.First())
.ToListAsync(cancellationToken);
}
}
@@ -0,0 +1,121 @@
namespace MyOffice.Data.Repositories.Item;
using Microsoft.EntityFrameworkCore;
using MyOffice.Data.Models.Items;
using MyOffice.DbContext;
public class ItemRepository : AppRepository<Item>, IItemRepository
{
public ItemRepository(AppDbContext context) : base(context)
{
}
public List<Item> GetAll(Guid userId)
{
return _context.Items
.Include(x => x.Motions)
.Include(x => x.Category)
.Include(x => x.ItemGlobal)
.Where(x => x.Category!.UserId == userId)
.ToList();
}
public async Task<List<Item>> GetAllAsync(Guid userId, CancellationToken cancellationToken = default)
{
return await _context.Items
.Include(x => x.Motions)
.Include(x => x.Category)
.Include(x => x.ItemGlobal)
.Where(x => x.Category!.UserId == userId)
.ToListAsync(cancellationToken);
}
public List<Item> GetByCategory(Guid userId, Guid categoryId)
{
return _context.Items
.Include(x => x.Motions)
.Include(x => x.Category)
.Include(x => x.ItemGlobal)
.Where(x => x.Category!.UserId == userId && x.CategoryId == categoryId)
.ToList();
}
public async Task<List<Item>> GetByCategoryAsync(
Guid userId,
Guid categoryId,
CancellationToken cancellationToken = default)
{
return await _context.Items
.Include(x => x.Motions)
.Include(x => x.Category)
.Include(x => x.ItemGlobal)
.Where(x => x.Category!.UserId == userId && x.CategoryId == categoryId)
.ToListAsync(cancellationToken);
}
public Item? GetByGlobal(Guid userId, Guid globalItemId)
{
return _context.Items
.Include(x => x.Motions)
.Include(x => x.Category)
.Include(x => x.ItemGlobal)
.FirstOrDefault(x => x.Category!.UserId == userId && x.ItemGlobalId == globalItemId);
}
public Task<Item?> GetByGlobalAsync(Guid userId, Guid globalItemId, CancellationToken cancellationToken = default)
{
return _context.Items
.Include(x => x.Motions)
.Include(x => x.Category)
.Include(x => x.ItemGlobal)
.FirstOrDefaultAsync(
x => x.Category!.UserId == userId && x.ItemGlobalId == globalItemId,
cancellationToken);
}
public bool Update(Item item)
{
return base.UpdateBase(item) > 0;
}
public async Task<bool> UpdateAsync(Item item, CancellationToken cancellationToken = default)
{
return await UpdateBaseAsync(item, cancellationToken) > 0;
}
public bool Add(Item item)
{
return base.AddBase(item) > 0;
}
public async Task<bool> AddAsync(Item item, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(item, cancellationToken) > 0;
}
public List<Item> Find(Guid userId, string term, int limit)
{
return _context
.Items
.Include(x => x.ItemGlobal)
.Where(x => x.Category!.UserId == userId && x.ItemGlobal.Name.ToLower().Contains(term.ToLower()))
.OrderByDescending(x => x!.Motions!.Count())
.Take(limit)
.ToList();
}
public async Task<List<Item>> FindAsync(
Guid userId,
string term,
int limit,
CancellationToken cancellationToken = default)
{
return await _context
.Items
.Include(x => x.ItemGlobal)
.Where(x => x.Category!.UserId == userId && x.ItemGlobal.Name.ToLower().Contains(term.ToLower()))
.OrderByDescending(x => x!.Motions!.Count())
.Take(limit)
.ToListAsync(cancellationToken);
}
}
@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Remove="AppDbContext.cs" />
<Compile Remove="AppDbContextFactory.cs" />
<Compile Remove="RepositoryInitializer.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyOffice.Data.Models\MyOffice.Data.Models.csproj" />
<ProjectReference Include="..\MyOffice.DbContext\MyOffice.DbContext.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,17 @@
namespace MyOffice.Data.Repositories.Item;
using MyOffice.Data.Models.Notifications;
using MyOffice.DbContext;
public class EmailTemplateRepository : AppRepository<EmailTemplate>, IEmailTemplateRepository
{
public EmailTemplateRepository(AppDbContext context) : base(context)
{
}
public EmailTemplate? Get(EmailTemplateEnum emailTemplate)
{
var emailTemplateStr = emailTemplate.ToString();
return _context.EmailTemplates.FirstOrDefault(x => x.Id == emailTemplateStr);
}
}
@@ -0,0 +1,8 @@
namespace MyOffice.Data.Repositories.Item;
using MyOffice.Data.Models.Notifications;
public interface IEmailTemplateRepository
{
EmailTemplate? Get(EmailTemplateEnum emailTemplate);
}
@@ -0,0 +1,108 @@
namespace MyOffice.Data.Repositories;
using Microsoft.EntityFrameworkCore;
using DbContext;
public class RepositoryBase<TEntity> where TEntity : class
{
protected readonly AppDbContext _context;
protected RepositoryBase(
AppDbContext context
)
{
_context = context;
}
protected async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
try
{
return await _context.SaveChangesAsync(cancellationToken);
}
catch (DbUpdateException updateException)
{
throw updateException;
}
}
protected int SaveChanges()
{
try
{
return _context.SaveChanges();
}
catch (DbUpdateException updateException)
{
throw updateException;
}
}
protected async Task<TEntity?> GetBaseAsync(Guid id)
{
return await _context.Set<TEntity>().FindAsync(id);
}
protected TEntity? GetBase(Guid id)
{
return _context.Set<TEntity>().Find(id);
}
protected int AddBase(TEntity entity)
{
_context.Entry(entity).State = EntityState.Added;
var result = SaveChanges();
_context.Entry(entity).State = EntityState.Detached;
return result;
}
protected async Task<int> AddBaseAsync(TEntity entity, CancellationToken cancellationToken = default)
{
_context.Entry(entity).State = EntityState.Added;
var result = await SaveChangesAsync(cancellationToken);
_context.Entry(entity).State = EntityState.Detached;
return result;
}
protected int RemoveBase(TEntity entity)
{
_context.Set<TEntity>().Remove(entity);
_context.Entry(entity).State = EntityState.Deleted;
var result = SaveChanges();
_context.Entry(entity).State = EntityState.Detached;
return result;
}
protected async Task<int> RemoveBaseAsync(TEntity entity, CancellationToken cancellationToken = default)
{
_context.Set<TEntity>().Remove(entity);
_context.Entry(entity).State = EntityState.Deleted;
var result = await SaveChangesAsync(cancellationToken);
_context.Entry(entity).State = EntityState.Detached;
return result;
}
protected int UpdateBase(TEntity entity)
{
_context.Entry(entity).State = EntityState.Modified;
var result = SaveChanges();
_context.Entry(entity).State = EntityState.Detached;
return result;
}
protected async Task<int> UpdateBaseAsync(TEntity entity, CancellationToken cancellationToken = default)
{
_context.Entry(entity).State = EntityState.Modified;
var result = await SaveChangesAsync(cancellationToken);
_context.Entry(entity).State = EntityState.Detached;
return result;
}
}
@@ -0,0 +1,20 @@
namespace MyOffice.Data.Repositories.Users;
using Models.Users;
public interface IUserExternalRepository
{
int AddUserExternal(UserExternal external);
Task<int> AddUserExternalAsync(UserExternal external, CancellationToken cancellationToken = default);
Task<List<UserExternal>> GetUserExternalsByUserIdAsync(Guid userId);
Task<UserExternal?> GetByUserIdAsync(Guid userId, string provider);
UserExternal? GetByUserId(Guid userId, string provider);
UserExternal? GetByExternalId(string externalId, string provider);
Task<UserExternal?> GetByExternalIdAsync(string externalId, string provider);
void RemoveUserExternal(UserExternal userExternal);
Task RemoveUserExternalAsync(UserExternal userExternal, CancellationToken cancellationToken = default);
}
@@ -0,0 +1,15 @@
namespace MyOffice.Data.Repositories.Users;
using MyOffice.Data.Models.Users;
public interface IUserRepository
{
Task<User?> GetUserAsync(Guid id);
User? GetUser(Guid id);
Task<User?> GetByUserUserNameAsync(string userName);
User? GetByUserUserName(string userName);
int AddUser(User user);
int UpdateUser(User user);
}
@@ -0,0 +1,108 @@
namespace MyOffice.Data.Repositories.Users;
using MyOffice.Data.Models.Users;
using Repositories;
using Microsoft.EntityFrameworkCore;
using MyOffice.DbContext;
public class UserExternalRepository : AppRepository<UserExternal>, IUserExternalRepository
{
public UserExternalRepository(AppDbContext context) : base(context)
{
}
public int AddUserExternal(UserExternal userExternal)
{
return AddBase(userExternal);
}
public async Task<int> AddUserExternalAsync(UserExternal userExternal, CancellationToken cancellationToken = default)
{
return await AddBaseAsync(userExternal, cancellationToken);
}
public async Task<int> AddUserExternalsAsync(IEnumerable<UserExternal> claims)
{
_context.AddRange(claims);
return await SaveChangesAsync();
}
public async Task<List<UserExternal>> GetUserExternalsByUserNameAsync(string userName)
{
return await _context
.UserClaims
.Where(x => x.User.UserName == userName)
.Include(x => x.User)
.ToListAsync();
}
public async Task<List<UserExternal>> GetUserExternalsByUserIdAsync(Guid userId)
{
return await _context
.UserClaims
.Where(x => x.UserId == userId)
.Include(x => x.User)
.ToListAsync();
}
public List<UserExternal> GetUserExternalsByUser(Guid userId)
{
return _context
.UserClaims
.Where(x => x.UserId == userId)
.Include(x => x.User)
.ToList();
}
public List<UserExternal> GetUserExternalsByUserName(string userName)
{
return _context
.UserClaims
.Where(x => x.User.UserName == userName)
.Include(x => x.User)
.ToList();
}
public async Task<UserExternal?> GetByUserIdAsync(Guid userId, string provider)
{
return await _context
.UserClaims
.Include(x => x.User)
.FirstOrDefaultAsync(x => x.UserId == userId && x.Provider == provider);
}
public UserExternal? GetByUserId(Guid userId, string provider)
{
return _context
.UserClaims
.Include(x => x.User)
.FirstOrDefault(x => x.UserId == userId && x.Provider == provider);
}
public UserExternal? GetByExternalId(string externalId, string provider)
{
return _context
.UserClaims
.Include(x => x.User)
.FirstOrDefault(x => x.ExternalId == externalId && x.Provider == provider);
}
public Task<UserExternal?> GetByExternalIdAsync(string externalId, string provider)
{
return _context
.UserClaims
.Include(x => x.User)
.FirstOrDefaultAsync(x => x.ExternalId == externalId && x.Provider == provider);
}
public void RemoveUserExternal(UserExternal userExternal)
{
RemoveBase(userExternal);
}
public async Task RemoveUserExternalAsync(UserExternal userExternal, CancellationToken cancellationToken = default)
{
await RemoveBaseAsync(userExternal, cancellationToken);
}
}
@@ -0,0 +1,43 @@
namespace MyOffice.Data.Repositories.Users;
using MyOffice.Data.Models.Users;
using Repositories;
using Microsoft.EntityFrameworkCore;
using MyOffice.DbContext;
public class UserRepository : AppRepository<User>, IUserRepository
{
public UserRepository(AppDbContext context) : base(context)
{
}
public async Task<User?> GetUserAsync(Guid id)
{
return await GetBaseAsync(id);
}
public User? GetUser(Guid id)
{
return GetBase(id);
}
public async Task<User?> GetByUserUserNameAsync(string userName)
{
return await _context.Users.FirstOrDefaultAsync(x => x.UserName == userName);
}
public User? GetByUserUserName(string userName)
{
return _context.Users.FirstOrDefault(x => x.UserName == userName);
}
public int AddUser(User user)
{
return AddBase(user);
}
public int UpdateUser(User user)
{
return UpdateBase(user);
}
}
@@ -0,0 +1,11 @@
using MyOffice.Data.Models.Verifications;
namespace MyOffice.Data.Repositories.Item;
public interface IVerificationCodeRepository
{
VerificationCode? GetByCode(string code);
bool Add(VerificationCode entity);
bool Update(VerificationCode entity);
}
@@ -0,0 +1,27 @@
namespace MyOffice.Data.Repositories.Item;
using Microsoft.EntityFrameworkCore;
using MyOffice.Data.Models.Verifications;
using MyOffice.DbContext;
public class VerificationCodeRepository : AppRepository<VerificationCode>, IVerificationCodeRepository
{
public VerificationCodeRepository(AppDbContext context) : base(context)
{
}
public bool Add(VerificationCode entity)
{
return AddBase(entity) > 0;
}
public bool Update(VerificationCode entity)
{
return UpdateBase(entity) > 0;
}
public VerificationCode? GetByCode(string code)
{
return _context.Verifications.FirstOrDefault(x => x.Code == code);
}
}
+335
View File
@@ -0,0 +1,335 @@
namespace MyOffice.DbContext;
using Data.Models.Accounts;
using Data.Models.Currencies;
using Data.Models.Items;
using Microsoft.EntityFrameworkCore;
using Data.Models.Users;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MyOffice.Data.Models.Verifications;
using MyOffice.Data.Models.Notifications;
public enum AppDbContextProvidersEnum
{
sqlite,
mssql,
npgsql
}
public class AppDbContext : DbContext
{
private readonly AppDbContextProvidersEnum _provider;
private readonly Dictionary<AppDbContextProvidersEnum, string> _noCaseCollation = new()
{
{ AppDbContextProvidersEnum.sqlite, "NOCASE" },
{ AppDbContextProvidersEnum.npgsql, "my_ci_collation" }
};
public AppDbContext(AppDbContextProvidersEnum provider, DbContextOptions<AppDbContext> options) : base(options)
{
_provider = provider;
ConfigureChangeTracker();
}
public AppDbContext(DbContextOptions<AppDbContext> options, ConnectionConfiguration connection) : base(options)
{
_provider = Enum.Parse<AppDbContextProvidersEnum>(connection.Provider, ignoreCase: true);
ConfigureChangeTracker();
}
private void ConfigureChangeTracker()
{
// Match historical repository behavior (manual EntityState updates).
ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
ChangeTracker.AutoDetectChangesEnabled = false;
}
public DbSet<User> Users { get; set; } = null!;
public DbSet<UserExternal> UserClaims { get; set; } = null!;
public DbSet<CurrencyGlobal> CurrencyGlobals { get; set; } = null!;
public DbSet<Currency> Currencies { get; set; } = null!;
public DbSet<CurrencyRate> CurrencyRates { get; set; } = null!;
public DbSet<AccountCategory> AccountCategories { get; set; } = null!;
public DbSet<Account> Accounts { get; set; } = null!;
public DbSet<AccountAccountCategory> AccountAccountCategories { get; set; } = null!;
public DbSet<AccountAccess> AccountAccesses { get; set; } = null!;
public DbSet<AccountAccessInvite> AccountAccessInvites { get; set; } = null!;
public DbSet<ItemCategory> ItemCategories { get; set; } = null!;
public DbSet<ItemGlobal> ItemGlobals { get; set; } = null!;
public DbSet<Item> Items { get; set; } = null!;
public DbSet<Motion> Motions { get; set; } = null!;
public DbSet<VerificationCode> Verifications { get; set; } = null!;
public DbSet<EmailTemplate> EmailTemplates { get; set; } = null!;
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var noCaseCollation = _noCaseCollation[_provider];
if (_provider == AppDbContextProvidersEnum.npgsql)
{
modelBuilder.HasCollation("my_ci_collation", "en-u-ks-primary", "icu", false);
}
/* NOCASE PROPERTIES */
modelBuilder.Entity<User>()
.Property(x => x.UserName)
.UseCollation(noCaseCollation);
modelBuilder.Entity<User>()
.Property(x => x.Email)
.UseCollation(noCaseCollation);
modelBuilder.Entity<UserExternal>()
.Property(x => x.Provider)
.UseCollation(noCaseCollation);
modelBuilder.Entity<UserExternal>()
.Property(x => x.Email)
.UseCollation(noCaseCollation);
modelBuilder.Entity<UserExternal>()
.HasOne(x => x.User)
.WithMany(x => x.UserClaims)
.HasForeignKey(x => x.UserId);
UserCreating(modelBuilder);
CurrencyCreating(modelBuilder);
AccountCreating(modelBuilder);
MotionsCreating(modelBuilder);
VerificationsCreating(modelBuilder);
EmailTemplateCreating(modelBuilder);
modelBuilder.UseOpenIddict();
base.OnModelCreating(modelBuilder);
}
private void VerificationsCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<VerificationCode>()
.HasKey(x => x.Id);
modelBuilder.Entity<VerificationCode>()
.HasOne(x => x.User)
.WithMany()
.HasForeignKey(x => x.UserId);
}
private void EmailTemplateCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<EmailTemplate>()
.HasKey(x => x.Id);
}
private void UserCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasOne(x => x.Currency)
.WithMany()
.HasForeignKey(x => x.CurrencyId);
}
private void CurrencyCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<CurrencyGlobal>()
.HasKey(x => x.Id);
modelBuilder.Entity<Currency>()
.HasKey(x => x.Id);
modelBuilder.Entity<CurrencyRate>()
.HasKey(x => x.Id);
modelBuilder.Entity<Currency>()
.HasOne(x => x.CurrencyGlobal)
.WithMany(x => x.Currencies)
.HasForeignKey(x => x.CurrencyGlobalId);
modelBuilder.Entity<Currency>()
.HasOne(x => x.User)
.WithMany(x => x.Currencies)
.HasForeignKey(x => x.UserId);
modelBuilder.Entity<CurrencyRate>()
.HasOne(x => x.Currency)
.WithMany(x => x.Rates)
.HasForeignKey(x => x.CurrencyId);
modelBuilder.Entity<Currency>()
.HasOne(x => x.CurrentRate)
.WithMany(x => x.Currencies)
.HasForeignKey(x => x.CurrentRateId);
}
private void AccountCreating(ModelBuilder modelBuilder)
{
#region Account
modelBuilder.Entity<Account>()
.HasKey(x => x.Id);
modelBuilder.Entity<Account>()
.HasOne(x => x.CurrencyGlobal)
.WithMany(x => x.Accounts)
.HasForeignKey(x => x.CurrencyGlobalId);
modelBuilder.Entity<Account>()
.HasOne(x => x.Owner)
.WithMany(x => x.Accounts)
.HasForeignKey(x => x.OwnerId);
#endregion Account
#region AccountAccess
modelBuilder.Entity<AccountAccess>()
.HasKey(x => x.Id);
modelBuilder.Entity<AccountAccess>()
.HasOne(x => x.Account)
.WithMany(x => x.AccessRights)
.HasForeignKey(x => x.AccountId);
modelBuilder.Entity<AccountAccess>()
.HasOne(x => x.User)
.WithMany(x => x.AccountAccess)
.HasForeignKey(x => x.UserId);
modelBuilder.Entity<AccountAccess>()
.HasOne(x => x.Owner)
.WithMany(x => x.AccountAccessOwners)
.HasForeignKey(x => x.OwnerId);
modelBuilder
.Entity<AccountAccess>()
.Property(d => d.Type)
.HasConversion(new EnumToStringConverter<AccountAccessTypeEnum>());
modelBuilder.Entity<AccountAccess>()
.HasIndex(p => new { p.AccountId, p.UserId })
.IsUnique();
modelBuilder.Entity<AccountAccess>()
.HasIndex(p => new { p.AccountId, p.OwnerId })
.IsUnique();
#endregion AccountAccess
#region AccountAccessInvite
modelBuilder.Entity<AccountAccessInvite>()
.HasKey(x => x.Id);
modelBuilder.Entity<AccountAccessInvite>()
.HasOne(x => x.User)
.WithMany(x => x.AccountAccessInvites)
.HasForeignKey(x => x.UserId);
modelBuilder.Entity<AccountAccessInvite>()
.HasOne(x => x.Account)
.WithMany(x => x.Invites)
.HasForeignKey(x => x.AccountId);
#endregion AccountAccessInvite
#region Motion
modelBuilder.Entity<Motion>()
.HasKey(x => x.Id);
modelBuilder.Entity<Motion>()
.HasOne(x => x.Account)
.WithMany(x => x.Motions)
.HasForeignKey(x => x.AccountId);
#endregion Motion
#region AccountCategory
modelBuilder.Entity<AccountCategory>()
.HasKey(x => x.Id);
modelBuilder.Entity<AccountCategory>()
.HasOne(x => x.User)
.WithMany(x => x.AccountCategories)
.HasForeignKey(x => x.UserId);
#endregion AccountCategory
#region AccountAccountCategory
modelBuilder.Entity<AccountAccountCategory>()
.HasKey(x => x.Id);
modelBuilder.Entity<AccountAccountCategory>()
.HasOne(x => x.Account)
.WithMany(x => x.Categories)
.HasForeignKey(x => x.AccountId);
modelBuilder.Entity<AccountAccountCategory>()
.HasOne(x => x.Category)
.WithMany(x => x.Accounts)
.HasForeignKey(x => x.CategoryId);
modelBuilder.Entity<AccountAccountCategory>()
.HasIndex(p => new { p.AccountId, p.CategoryId })
.IsUnique();
modelBuilder.Entity<AccountAccountCategory>()
.HasOne(x => x.Category)
.WithMany(x => x.Accounts)
.HasForeignKey(x => x.CategoryId);
#endregion AccountAccountCategory
}
private void MotionsCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ItemGlobal>()
.HasKey(x => x.Id);
modelBuilder.Entity<ItemCategory>()
.HasKey(x => x.Id);
modelBuilder.Entity<Item>()
.HasKey(x => x.Id);
modelBuilder.Entity<Motion>()
.HasKey(x => x.Id);
modelBuilder.Entity<ItemCategory>()
.HasOne(x => x.User)
.WithMany(x => x.ItemCategories)
.HasForeignKey(x => x.UserId);
modelBuilder.Entity<Item>()
.HasOne(x => x.Category)
.WithMany(x => x.Items)
.HasForeignKey(x => x.CategoryId);
modelBuilder.Entity<Item>()
.HasOne(x => x.ItemGlobal)
.WithMany(x => x.Items)
.HasForeignKey(x => x.ItemGlobalId);
modelBuilder.Entity<Motion>()
.HasOne(x => x.Item)
.WithMany(x => x.Motions)
.HasForeignKey(x => x.ItemId);
modelBuilder.Entity<Motion>()
.HasOne(x => x.Account)
.WithMany(x => x.Motions)
.HasForeignKey(x => x.AccountId);
modelBuilder.Entity<Motion>()
.Property(x => x.AmountMinus)
.HasPrecision(18, 6);
modelBuilder.Entity<Motion>()
.Property(x => x.AmountPlus)
.HasPrecision(18, 6);
}
}
+37
View File
@@ -0,0 +1,37 @@
namespace MyOffice.DbContext;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
{
public static AppDbContextFactory Instance = new();
public AppDbContext CreateDbContext()
{
return CreateDbContext(null);
}
public AppDbContext CreateDbContext(string[]? args)
{
var connection = RepositoryInitializer.ConnectionString;
if (connection is null)
{
connection = new ConnectionConfiguration(
args?[0] ?? "npgsql",
args?[1] ?? string.Empty);
}
var builder = new DbContextOptionsBuilder<AppDbContext>();
DbContextServiceCollectionExtensions.ConfigureDbContextOptions(builder, connection);
if (!Enum.TryParse<AppDbContextProvidersEnum>(connection?.Provider ?? args?[0] ?? "", ignoreCase: true, out var providerEnum))
throw new InvalidOperationException($"No such provider: [{connection?.Provider}]");
var db = new AppDbContext(providerEnum, builder.Options);
db.ChangeTracker.AutoDetectChangesEnabled = false;
db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
return db;
}
}
@@ -0,0 +1,67 @@
namespace MyOffice.DbContext;
using Data.Models.Currencies;
using Microsoft.EntityFrameworkCore;
/// <summary>
/// Migrate and seed using a DI-scoped <see cref="AppDbContext"/> (not the design-time factory).
/// </summary>
public static class DatabaseBootstrapper
{
public static async Task InitializeAsync(AppDbContext db, CancellationToken cancellationToken = default)
{
await db.Database.MigrateAsync(cancellationToken);
await PrefillAsync(db, cancellationToken);
await DemoDataSeeder.SeedIfEmptyAsync(db, cancellationToken);
await UpdateCurrentRatesAsync(db, cancellationToken);
}
private static async Task PrefillAsync(AppDbContext dbContext, CancellationToken cancellationToken)
{
var predefinedCurrencyGlobals = new List<CurrencyGlobal>
{
new() { Id = CurrencyGlobalIdEnum.UAH.ToString(), DefaultQuantity = 1, Symbol = "₴", Name = "Ukrainian hryvnias" },
new() { Id = CurrencyGlobalIdEnum.USD.ToString(), DefaultQuantity = 1, Symbol = "$", Name = "US Dollar" },
new() { Id = CurrencyGlobalIdEnum.EUR.ToString(), DefaultQuantity = 1, Symbol = "€", Name = "Euros" },
new() { Id = CurrencyGlobalIdEnum.GBP.ToString(), DefaultQuantity = 1, Symbol = "£", Name = "British pounds sterling" },
new() { Id = CurrencyGlobalIdEnum.RUB.ToString(), DefaultQuantity = 10, Symbol = "₽", Name = "Russia Ruble" },
new() { Id = CurrencyGlobalIdEnum.BTC.ToString(), DefaultQuantity = 10, Symbol = "btc", Name = "Bitcoin" },
new() { Id = CurrencyGlobalIdEnum.ETH.ToString(), DefaultQuantity = 10, Symbol = "eth", Name = "Ethereum" },
new() { Id = CurrencyGlobalIdEnum.TON.ToString(), DefaultQuantity = 10, Symbol = "ton", Name = "TON" },
new() { Id = CurrencyGlobalIdEnum.OTHER.ToString(), DefaultQuantity = 1, Symbol = "", Name = "Other" },
};
var currencyGlobals = await dbContext.CurrencyGlobals.ToListAsync(cancellationToken);
foreach (var predefined in predefinedCurrencyGlobals)
{
if (currencyGlobals.All(x => x.Id != predefined.Id))
{
dbContext.CurrencyGlobals.Add(predefined);
}
}
await dbContext.SaveChangesAsync(cancellationToken);
}
private static async Task UpdateCurrentRatesAsync(AppDbContext dbContext, CancellationToken cancellationToken)
{
var lastRates = await dbContext.CurrencyRates
.Include(x => x.Currency)
.GroupBy(x => new { x.CurrencyId },
(key, g) => g.Where(x => x.DateTime <= DateTime.UtcNow).OrderByDescending(x => x.DateTime).First())
.ToListAsync(cancellationToken);
var currencies = await dbContext.Currencies.ToListAsync(cancellationToken);
foreach (var currency in currencies)
{
var rate = lastRates.FirstOrDefault(x => x.CurrencyId == currency.Id);
if (rate != null)
{
currency.CurrentRateId = rate.Id;
dbContext.Attach(currency).State = EntityState.Modified;
}
}
await dbContext.SaveChangesAsync(cancellationToken);
}
}
@@ -0,0 +1,50 @@
namespace MyOffice.DbContext;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
public static class DbContextServiceCollectionExtensions
{
public static IServiceCollection AddAppDbContext(
this IServiceCollection services,
ConnectionConfiguration connection
)
{
services.AddSingleton(connection);
services.AddDbContext<AppDbContext>((_, options) =>
{
ConfigureDbContextOptions(options, connection);
});
return services;
}
public static void ConfigureDbContextOptions(
DbContextOptionsBuilder options,
ConnectionConfiguration connection
)
{
if (!Enum.TryParse<AppDbContextProvidersEnum>(connection.Provider, ignoreCase: true, out var provider))
throw new InvalidOperationException($"No such provider: [{connection.Provider}]");
switch (provider)
{
case AppDbContextProvidersEnum.npgsql:
options.UseNpgsql(connection.ConnectionString, x =>
x.MigrationsAssembly("MyOffice.Migrations.Postgres"));
break;
case AppDbContextProvidersEnum.sqlite:
options.UseSqlite(connection.ConnectionString, x =>
x.MigrationsAssembly("MyOffice.Migrations.Sqlite"));
break;
default:
throw new NotSupportedException($"No such provider: [{connection.Provider}]");
}
#if DEBUG
options.EnableSensitiveDataLogging();
options.EnableDetailedErrors();
#endif
}
}
+292
View File
@@ -0,0 +1,292 @@
namespace MyOffice.DbContext;
using Data.Models.Accounts;
using Data.Models.Currencies;
using Data.Models.Items;
using Data.Models.Users;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
/// <summary>
/// Fills an empty database with three demo users (UAH/USD/EUR) and sample catalog data.
/// </summary>
public static class DemoDataSeeder
{
private static readonly PasswordHasher<object> PasswordHasher = new();
private static readonly string[] CurrencyCodes = ["UAH", "USD", "EUR"];
private static readonly (string Code, string Email, string Password, string FirstName)[] Users =
[
("UAH", "user_UAH@user_UAH.userUAH", "user_UAH", "User UAH"),
("USD", "user_USD@user_USD.userUSD", "user_USD", "User USD"),
("EUR", "user_EUR@user_EUR.userEUR", "user_EUR", "User EUR"),
];
/// <summary>1 USD = 42 UAH, 1 EUR = 50 UAH.</summary>
private const decimal UsdInUah = 42m;
private const decimal EurInUah = 50m;
public static async Task SeedIfEmptyAsync(AppDbContext db, CancellationToken cancellationToken = default)
{
if (await db.Users.AnyAsync(cancellationToken))
{
return;
}
// AppDbContext defaults to NoTracking; seeding needs identity values and graph inserts.
var previousTracking = db.ChangeTracker.QueryTrackingBehavior;
var previousDetect = db.ChangeTracker.AutoDetectChangesEnabled;
db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll;
db.ChangeTracker.AutoDetectChangesEnabled = true;
try
{
var yearStart = new DateTime(DateTime.UtcNow.Year, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var rng = new Random(2026);
foreach (var (code, email, password, firstName) in Users)
{
await SeedUserAsync(db, code, email, password, firstName, yearStart, rng, cancellationToken);
}
await db.SaveChangesAsync(cancellationToken);
}
finally
{
db.ChangeTracker.QueryTrackingBehavior = previousTracking;
db.ChangeTracker.AutoDetectChangesEnabled = previousDetect;
db.ChangeTracker.Clear();
}
}
private static async Task SeedUserAsync(
AppDbContext db,
string homeCurrency,
string email,
string password,
string firstName,
DateTime rateDate,
Random rng,
CancellationToken cancellationToken)
{
var ua = homeCurrency == "UAH";
var userId = Guid.NewGuid();
var user = new User
{
Id = userId,
UserName = email,
Email = email,
PasswordHash = PasswordHasher.HashPassword(new object(), password),
FirstName = firstName,
FullName = firstName,
IsEmailConfirmed = true,
CurrencyId = homeCurrency,
};
db.Users.Add(user);
var currencies = new Dictionary<string, Currency>(StringComparer.Ordinal);
foreach (var code in CurrencyCodes)
{
var currency = new Currency
{
Id = Guid.NewGuid(),
UserId = userId,
CurrencyGlobalId = code,
Name = CurrencyDisplayName(code, ua),
ShortName = code,
IsPrimary = code == homeCurrency,
};
db.Currencies.Add(currency);
db.CurrencyRates.Add(new CurrencyRate
{
CurrencyId = currency.Id,
DateTime = rateDate,
Quantity = 1,
Rate = RateInHome(code, homeCurrency),
});
currencies[code] = currency;
}
// UnCategorized convention: category Id == user Id
db.ItemCategories.Add(new ItemCategory
{
Id = userId,
UserId = userId,
Name = ua ? "Без категорії" : "UnCategorized",
Items = [],
IsInternal = true,
});
var accountCategoryDefs = ua
? new (string Key, string Name)[] { ("CASH", "Готівка"), ("BANK", "Банк"), ("DEPOSIT", "Депозит") }
: [("CASH", "CASH"), ("BANK", "BANK"), ("DEPOSIT", "DEPOSIT")];
var accounts = new List<Account>();
foreach (var (key, name) in accountCategoryDefs)
{
var category = new AccountCategory
{
Id = Guid.NewGuid(),
UserId = userId,
Name = name,
};
db.AccountCategories.Add(category);
foreach (var code in CurrencyCodes)
{
var account = new Account
{
Id = Guid.NewGuid(),
OwnerId = userId,
CurrencyGlobalId = code,
Name = $"{name} {code}",
};
db.Accounts.Add(account);
db.AccountAccountCategories.Add(new AccountAccountCategory
{
AccountId = account.Id,
CategoryId = category.Id,
});
db.AccountAccesses.Add(new AccountAccess
{
AccountId = account.Id,
UserId = userId,
OwnerId = userId,
IsAllowRead = true,
IsAllowWrite = true,
IsAllowManage = true,
Type = AccountAccessTypeEnum.balance,
});
accounts.Add(account);
}
}
var incomeCategory = new ItemCategory
{
Id = Guid.NewGuid(),
UserId = userId,
Name = ua ? "Доходи" : "INCOME",
Items = [],
};
var outcomeCategory = new ItemCategory
{
Id = Guid.NewGuid(),
UserId = userId,
Name = ua ? "Витрати" : "OUTCOME",
Items = [],
};
db.ItemCategories.AddRange(incomeCategory, outcomeCategory);
var incomeNames = ua
? new[] { "Готівка", "Офіс" }
: ["CASH", "OFFICE"];
var outcomeNames = ua
? new[]
{
"Товари", "Бензин", "Steam", "Продукти", "Кафе",
"Оренда", "Комунальні", "Інтернет", "Зв'язок", "Розваги",
}
: [
"Goods", "Petrol", "Steam", "Groceries", "Cafe",
"Rent", "Utilities", "Internet", "Mobile", "Entertainment",
];
var incomeItems = await AddItemsAsync(db, incomeCategory.Id, incomeNames, cancellationToken);
var outcomeItems = await AddItemsAsync(db, outcomeCategory.Id, outcomeNames, cancellationToken);
await db.SaveChangesAsync(cancellationToken);
SeedMotions(db, accounts, incomeItems, outcomeItems, rng, count: 100);
}
private static async Task<List<Item>> AddItemsAsync(
AppDbContext db,
Guid categoryId,
IEnumerable<string> names,
CancellationToken cancellationToken)
{
var items = new List<Item>();
foreach (var name in names)
{
var global = db.ItemGlobals.Local.FirstOrDefault(x => x.Name == name)
?? await db.ItemGlobals.FirstOrDefaultAsync(x => x.Name == name, cancellationToken);
if (global == null)
{
global = new ItemGlobal { Id = Guid.NewGuid(), Name = name };
db.ItemGlobals.Add(global);
}
var item = new Item
{
CategoryId = categoryId,
ItemGlobalId = global.Id,
};
db.Items.Add(item);
items.Add(item);
}
return items;
}
private static void SeedMotions(
AppDbContext db,
List<Account> accounts,
List<Item> incomeItems,
List<Item> outcomeItems,
Random rng,
int count)
{
var now = DateTime.UtcNow;
var from = now.AddMonths(-3);
for (var i = 0; i < count; i++)
{
var isIncome = rng.Next(2) == 0;
var item = isIncome
? incomeItems[rng.Next(incomeItems.Count)]
: outcomeItems[rng.Next(outcomeItems.Count)];
var account = accounts[rng.Next(accounts.Count)];
var days = (now - from).TotalDays;
var when = from.AddDays(rng.NextDouble() * days);
var amount = Math.Round((decimal)(rng.NextDouble() * (isIncome ? 4500 : 700) + (isIncome ? 200 : 20)), 2);
db.Motions.Add(new Motion
{
Id = Guid.NewGuid(),
AccountId = account.Id,
ItemId = item.Id,
DateTime = when,
CreatedOn = when,
Description = isIncome ? "Demo income" : "Demo expense",
AmountPlus = isIncome ? amount : 0,
AmountMinus = isIncome ? 0 : amount,
});
}
}
private static decimal RateInHome(string currencyCode, string homeCurrency)
{
static decimal InUah(string code) => code switch
{
"UAH" => 1m,
"USD" => UsdInUah,
"EUR" => EurInUah,
_ => 1m,
};
return InUah(currencyCode) / InUah(homeCurrency);
}
private static string CurrencyDisplayName(string code, bool ua) => (code, ua) switch
{
("UAH", true) => "Гривня",
("USD", true) => "Долар США",
("EUR", true) => "Євро",
("UAH", _) => "Ukrainian hryvnia",
("USD", _) => "US Dollar",
("EUR", _) => "Euro",
_ => code,
};
}
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.10" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="10.0.10" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.3" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="7.6.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyOffice.Data.Models\MyOffice.Data.Models.csproj" />
<ProjectReference Include="..\MyOffice.Shared\MyOffice.Shared.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,23 @@
namespace MyOffice.DbContext;
using Microsoft.Extensions.DependencyInjection;
public record ConnectionConfiguration(string Provider, string ConnectionString);
public static class RepositoryInitializer
{
/// <summary>
/// Registers DbContext DI. Migrate/seed runs via <c>DatabaseInitializerHostedService</c>.
/// <see cref="ConnectionString"/> remains for design-time <see cref="AppDbContextFactory"/>.
/// </summary>
public static void Initialize(
IServiceCollection services,
ConnectionConfiguration connectionString
)
{
ConnectionString = connectionString;
services.AddAppDbContext(connectionString);
}
public static ConnectionConfiguration ConnectionString { get; internal set; } = null!;
}
@@ -0,0 +1,27 @@
namespace MyOffice.Migrations.Postgres;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using MyOffice.DbContext;
using MyOffice.Shared;
public class AppDbContextFactoryPostgres : IDesignTimeDbContextFactory<AppDbContext>
{
public AppDbContext CreateDbContext(string[]? args)
{
var builder = new DbContextOptionsBuilder<AppDbContext>();
var sharedConfiguration = SharedConfiguration.Build();
var connectionString =
args?.FirstOrDefault()
?? sharedConfiguration.GetConnectionString("npgsql");
builder.UseNpgsql(connectionString, b => b.MigrationsAssembly("MyOffice.Migrations.Postgres"));
var db = new AppDbContext(AppDbContextProvidersEnum.npgsql, builder.Options);
db.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
return db;
}
}
@@ -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("20230621190024_Init")]
partial class Init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False")
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<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<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.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.Motions.ItemCategory", 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("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("Users");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Accounts")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("Currencies")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency")
.WithMany("Rates")
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.Item", b =>
{
b.HasOne("MyOffice.Data.Models.Motions.ItemCategory", "Category")
.WithMany("Items")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Motions.ItemGlobal", "ItemGlobal")
.WithMany("Items")
.HasForeignKey("ItemGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("ItemGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.ItemCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("ItemCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("UserClaims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Navigation("AccessRights");
b.Navigation("Categories");
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Navigation("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Navigation("Rates");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Navigation("Accounts");
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.Item", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.ItemCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Motions.ItemGlobal", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,445 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class Init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False");
migrationBuilder.CreateTable(
name: "CurrencyGlobals",
columns: table => new
{
Id = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Symbol = table.Column<string>(type: "text", nullable: false),
DefaultQuantity = table.Column<int>(type: "integer", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CurrencyGlobals", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ItemGlobals",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ItemGlobals", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Accounts",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CurrencyGlobalId = table.Column<string>(type: "text", nullable: false),
Name = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Accounts", x => x.Id);
table.ForeignKey(
name: "FK_Accounts_CurrencyGlobals_CurrencyGlobalId",
column: x => x.CurrencyGlobalId,
principalTable: "CurrencyGlobals",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
UserName = table.Column<string>(type: "text", nullable: false, collation: "my_ci_collation"),
Email = table.Column<string>(type: "text", nullable: false, collation: "my_ci_collation"),
PasswordHash = table.Column<string>(type: "text", nullable: false),
FirstName = table.Column<string>(type: "text", nullable: true),
LastName = table.Column<string>(type: "text", nullable: true),
FullName = table.Column<string>(type: "text", nullable: true),
Phone = table.Column<string>(type: "text", nullable: true),
IsEmailConfirmed = table.Column<bool>(type: "boolean", nullable: false),
CurrencyId = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
table.ForeignKey(
name: "FK_Users_CurrencyGlobals_CurrencyId",
column: x => x.CurrencyId,
principalTable: "CurrencyGlobals",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AccountAccesses",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
IsAllowRead = table.Column<bool>(type: "boolean", nullable: false),
IsAllowWrite = table.Column<bool>(type: "boolean", nullable: false),
IsAllowManage = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AccountAccesses", x => x.Id);
table.ForeignKey(
name: "FK_AccountAccesses_Accounts_AccountId",
column: x => x.AccountId,
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AccountAccesses_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AccountCategories",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AccountCategories", x => x.Id);
table.ForeignKey(
name: "FK_AccountCategories_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Currencies",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CurrencyGlobalId = table.Column<string>(type: "text", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
ShortName = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Currencies", x => x.Id);
table.ForeignKey(
name: "FK_Currencies_CurrencyGlobals_CurrencyGlobalId",
column: x => x.CurrencyGlobalId,
principalTable: "CurrencyGlobals",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Currencies_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ItemCategories",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ItemCategories", x => x.Id);
table.ForeignKey(
name: "FK_ItemCategories_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "UserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
CreatedOn = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ExternalId = table.Column<string>(type: "text", nullable: false),
Email = table.Column<string>(type: "text", nullable: false, collation: "my_ci_collation"),
Provider = table.Column<string>(type: "text", nullable: false, collation: "my_ci_collation")
},
constraints: table =>
{
table.PrimaryKey("PK_UserClaims", x => x.Id);
table.ForeignKey(
name: "FK_UserClaims_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AccountAccountCategories",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
CategoryId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AccountAccountCategories", x => x.Id);
table.ForeignKey(
name: "FK_AccountAccountCategories_AccountCategories_CategoryId",
column: x => x.CategoryId,
principalTable: "AccountCategories",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AccountAccountCategories_Accounts_AccountId",
column: x => x.AccountId,
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "CurrencyRates",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
CurrencyId = table.Column<Guid>(type: "uuid", nullable: false),
DateTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Quantity = table.Column<int>(type: "integer", nullable: false),
Rate = table.Column<decimal>(type: "numeric", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_CurrencyRates", x => x.Id);
table.ForeignKey(
name: "FK_CurrencyRates_Currencies_CurrencyId",
column: x => x.CurrencyId,
principalTable: "Currencies",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Items",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
CategoryId = table.Column<Guid>(type: "uuid", nullable: false),
ItemGlobalId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Items", x => x.Id);
table.ForeignKey(
name: "FK_Items_ItemCategories_CategoryId",
column: x => x.CategoryId,
principalTable: "ItemCategories",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Items_ItemGlobals_ItemGlobalId",
column: x => x.ItemGlobalId,
principalTable: "ItemGlobals",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Motions",
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),
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
ItemId = table.Column<int>(type: "integer", nullable: false),
Description = table.Column<string>(type: "text", nullable: true),
AmountPlus = table.Column<decimal>(type: "numeric(18,6)", precision: 18, scale: 6, nullable: false),
AmountMinus = table.Column<decimal>(type: "numeric(18,6)", precision: 18, scale: 6, nullable: false),
UserId = table.Column<Guid>(type: "uuid", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Motions", x => x.Id);
table.ForeignKey(
name: "FK_Motions_Accounts_AccountId",
column: x => x.AccountId,
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Motions_Items_ItemId",
column: x => x.ItemId,
principalTable: "Items",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Motions_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id");
});
migrationBuilder.CreateIndex(
name: "IX_AccountAccesses_AccountId",
table: "AccountAccesses",
column: "AccountId");
migrationBuilder.CreateIndex(
name: "IX_AccountAccesses_UserId",
table: "AccountAccesses",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_AccountAccountCategories_AccountId",
table: "AccountAccountCategories",
column: "AccountId");
migrationBuilder.CreateIndex(
name: "IX_AccountAccountCategories_CategoryId",
table: "AccountAccountCategories",
column: "CategoryId");
migrationBuilder.CreateIndex(
name: "IX_AccountCategories_UserId",
table: "AccountCategories",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Accounts_CurrencyGlobalId",
table: "Accounts",
column: "CurrencyGlobalId");
migrationBuilder.CreateIndex(
name: "IX_Currencies_CurrencyGlobalId",
table: "Currencies",
column: "CurrencyGlobalId");
migrationBuilder.CreateIndex(
name: "IX_Currencies_UserId",
table: "Currencies",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_CurrencyRates_CurrencyId",
table: "CurrencyRates",
column: "CurrencyId");
migrationBuilder.CreateIndex(
name: "IX_ItemCategories_UserId",
table: "ItemCategories",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Items_CategoryId",
table: "Items",
column: "CategoryId");
migrationBuilder.CreateIndex(
name: "IX_Items_ItemGlobalId",
table: "Items",
column: "ItemGlobalId");
migrationBuilder.CreateIndex(
name: "IX_Motions_AccountId",
table: "Motions",
column: "AccountId");
migrationBuilder.CreateIndex(
name: "IX_Motions_ItemId",
table: "Motions",
column: "ItemId");
migrationBuilder.CreateIndex(
name: "IX_Motions_UserId",
table: "Motions",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_UserClaims_UserId",
table: "UserClaims",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Users_CurrencyId",
table: "Users",
column: "CurrencyId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AccountAccesses");
migrationBuilder.DropTable(
name: "AccountAccountCategories");
migrationBuilder.DropTable(
name: "CurrencyRates");
migrationBuilder.DropTable(
name: "Motions");
migrationBuilder.DropTable(
name: "UserClaims");
migrationBuilder.DropTable(
name: "AccountCategories");
migrationBuilder.DropTable(
name: "Currencies");
migrationBuilder.DropTable(
name: "Accounts");
migrationBuilder.DropTable(
name: "Items");
migrationBuilder.DropTable(
name: "ItemCategories");
migrationBuilder.DropTable(
name: "ItemGlobals");
migrationBuilder.DropTable(
name: "Users");
migrationBuilder.DropTable(
name: "CurrencyGlobals");
}
}
}
@@ -0,0 +1,611 @@
// <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("20230627044606_IsInternal")]
partial class IsInternal
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False")
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<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<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("UserId");
b.ToTable("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("ItemGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ItemGlobalId");
b.ToTable("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("Users");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Accounts")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("Currencies")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency")
.WithMany("Rates")
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category")
.WithMany("Items")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal")
.WithMany("Items")
.HasForeignKey("ItemGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("ItemGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("ItemCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("UserClaims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Navigation("AccessRights");
b.Navigation("Categories");
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Navigation("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Navigation("Rates");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Navigation("Accounts");
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class IsInternal : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsInternal",
table: "ItemCategories",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsInternal",
table: "ItemCategories");
}
}
}
@@ -0,0 +1,617 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MyOffice.DbContext;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20230720190103_PrimaryCurrencyDeletedMotion")]
partial class PrimaryCurrencyDeletedMotion
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False")
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("UserId");
b.ToTable("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("ItemGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ItemGlobalId");
b.ToTable("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("Users");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Accounts")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("Currencies")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency")
.WithMany("Rates")
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category")
.WithMany("Items")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal")
.WithMany("Items")
.HasForeignKey("ItemGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("ItemGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("ItemCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("UserClaims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Navigation("AccessRights");
b.Navigation("Categories");
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Navigation("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Navigation("Rates");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Navigation("Accounts");
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,40 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class PrimaryCurrencyDeletedMotion : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "DeletedOn",
table: "Motions",
type: "timestamp with time zone",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsPrimary",
table: "Currencies",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "DeletedOn",
table: "Motions");
migrationBuilder.DropColumn(
name: "IsPrimary",
table: "Currencies");
}
}
}
@@ -0,0 +1,631 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MyOffice.DbContext;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20230721175243_CurrentRate")]
partial class CurrentRate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False")
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<int?>("CurrentRateId1")
.HasColumnType("integer");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("CurrentRateId1");
b.HasIndex("UserId");
b.ToTable("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("ItemGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ItemGlobalId");
b.ToTable("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("Users");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Accounts")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany()
.HasForeignKey("CurrentRateId1");
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("Currencies")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
b.Navigation("CurrentRate");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency")
.WithMany("Rates")
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category")
.WithMany("Items")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal")
.WithMany("Items")
.HasForeignKey("ItemGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("ItemGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("ItemCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("UserClaims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Navigation("AccessRights");
b.Navigation("Categories");
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Navigation("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Navigation("Rates");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Navigation("Accounts");
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,58 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class CurrentRate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "CurrentRateId",
table: "Currencies",
type: "integer",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "CurrentRateId1",
table: "Currencies",
type: "integer",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Currencies_CurrentRateId1",
table: "Currencies",
column: "CurrentRateId1");
migrationBuilder.AddForeignKey(
name: "FK_Currencies_CurrencyRates_CurrentRateId1",
table: "Currencies",
column: "CurrentRateId1",
principalTable: "CurrencyRates",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Currencies_CurrencyRates_CurrentRateId1",
table: "Currencies");
migrationBuilder.DropIndex(
name: "IX_Currencies_CurrentRateId1",
table: "Currencies");
migrationBuilder.DropColumn(
name: "CurrentRateId",
table: "Currencies");
migrationBuilder.DropColumn(
name: "CurrentRateId1",
table: "Currencies");
}
}
}
@@ -0,0 +1,617 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MyOffice.DbContext;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20230721180304_CurrentRateRemove")]
partial class CurrentRateRemove
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False")
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("UserId");
b.ToTable("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("ItemGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ItemGlobalId");
b.ToTable("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("Users");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Accounts")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("Currencies")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency")
.WithMany("Rates")
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category")
.WithMany("Items")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal")
.WithMany("Items")
.HasForeignKey("ItemGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("ItemGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("ItemCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("UserClaims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Navigation("AccessRights");
b.Navigation("Categories");
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Navigation("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Navigation("Rates");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Navigation("Accounts");
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,58 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class CurrentRateRemove : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Currencies_CurrencyRates_CurrentRateId1",
table: "Currencies");
migrationBuilder.DropIndex(
name: "IX_Currencies_CurrentRateId1",
table: "Currencies");
migrationBuilder.DropColumn(
name: "CurrentRateId",
table: "Currencies");
migrationBuilder.DropColumn(
name: "CurrentRateId1",
table: "Currencies");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "CurrentRateId",
table: "Currencies",
type: "integer",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "CurrentRateId1",
table: "Currencies",
type: "integer",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Currencies_CurrentRateId1",
table: "Currencies",
column: "CurrentRateId1");
migrationBuilder.AddForeignKey(
name: "FK_Currencies_CurrencyRates_CurrentRateId1",
table: "Currencies",
column: "CurrentRateId1",
principalTable: "CurrencyRates",
principalColumn: "Id");
}
}
}
@@ -0,0 +1,633 @@
// <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("20230721180851_CurrentRateV2")]
partial class CurrentRateV2
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False")
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<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.Navigation("CurrencyGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany("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("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("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,48 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class CurrentRateV2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "CurrentRateId",
table: "Currencies",
type: "integer",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Currencies_CurrentRateId",
table: "Currencies",
column: "CurrentRateId");
migrationBuilder.AddForeignKey(
name: "FK_Currencies_CurrencyRates_CurrentRateId",
table: "Currencies",
column: "CurrentRateId",
principalTable: "CurrencyRates",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Currencies_CurrencyRates_CurrentRateId",
table: "Currencies");
migrationBuilder.DropIndex(
name: "IX_Currencies_CurrentRateId",
table: "Currencies");
migrationBuilder.DropColumn(
name: "CurrentRateId",
table: "Currencies");
}
}
}
@@ -0,0 +1,636 @@
// <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("20230721200424_AccountType")]
partial class AccountType
{
/// <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<int>("Type")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<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.Navigation("CurrencyGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany("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("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("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class AccountType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "Type",
table: "Accounts",
type: "integer",
nullable: false,
defaultValue: 0);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Type",
table: "Accounts");
}
}
}
@@ -0,0 +1,637 @@
// <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("20230722051335_AccountType2")]
partial class AccountType2
{
/// <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<string>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<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.Navigation("CurrencyGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany("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("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("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class AccountType2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Type",
table: "AccountAccesses",
type: "text",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Type",
table: "AccountAccesses");
}
}
}
@@ -0,0 +1,650 @@
// <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("20230722052053_AccountOwner")]
partial class AccountOwner
{
/// <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>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<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", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany("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("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("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Accounts");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,49 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class AccountOwner : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "OwnerId",
table: "Accounts",
type: "uuid",
nullable: true);
migrationBuilder.CreateIndex(
name: "IX_Accounts_OwnerId",
table: "Accounts",
column: "OwnerId");
migrationBuilder.AddForeignKey(
name: "FK_Accounts_Users_OwnerId",
table: "Accounts",
column: "OwnerId",
principalTable: "Users",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Accounts_Users_OwnerId",
table: "Accounts");
migrationBuilder.DropIndex(
name: "IX_Accounts_OwnerId",
table: "Accounts");
migrationBuilder.DropColumn(
name: "OwnerId",
table: "Accounts");
}
}
}
@@ -0,0 +1,652 @@
// <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("20230725054028_Collation")]
partial class Collation
{
/// <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")
.UseCollation("my_ci_collation");
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>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<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")
.UseCollation("my_ci_collation");
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", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany("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("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("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Accounts");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}

Some files were not shown because too many files have changed in this diff Show More