This commit is contained in:
2023-12-01 20:47:42 +02:00
parent a09fc7ece3
commit 045f60e373
39 changed files with 1252 additions and 945 deletions
@@ -0,0 +1,176 @@
namespace MyOffice.Services.Account;
using System.Collections.Generic;
using Core;
using Core.Extensions;
using Data.Models.Accounts;
using Domain;
public partial class AccountService
{
public Exec<AccountAccessInviteDto, AccessInviteStatus> AccessInvite(Guid userId, Guid accountId, string email, bool isAllowWrite)
{
if (email == null)
throw new ArgumentNullException(nameof(email));
var result = new Exec<AccountAccessInviteDto, AccessInviteStatus>(AccessInviteStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(AccessInviteStatus.account_not_found);
}
if (account.AccessRights!.Any(x => x.User!.Email.EqualsIgnoreCase(email)))
{
return result.Set(AccessInviteStatus.access_exists);
}
var access = _accountAccessInviteRepository.Get(userId, email);
if (access != null)
{
return result.Set(AccessInviteStatus.invite_exists);
}
var invite = new AccountAccessInvite
{
Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow,
UserId = userId,
AccountId = account.Id,
Email = email.SafeTrim()!,
IsAllowWrite = isAllowWrite,
};
_accountAccessInviteRepository.Add(invite);
return result.Set(_mapper.Map<AccountAccessInviteDto>(invite));
}
public Exec<AccountDto, GeneralExecStatus> AccessUpdate(Guid userId, Guid accountId, List<AccountAccessDto> accesses)
{
if (accesses == null)
throw new ArgumentNullException(nameof(accesses));
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
foreach (var access in account.AccessRights!)
{
var newAccess = accesses.FirstOrDefault(x => x.UserId == access.UserId);
if (newAccess != null && newAccess.IsAllowWrite != access.IsAllowWrite)
{
access.IsAllowWrite = newAccess.IsAllowWrite;
_accountAccessRepository.Update(access);
}
}
account = _accountRepository.Get(userId, accountId);
return result.Set(_mapper.Map<AccountDto>(account));
}
public Exec<AccountDto, GeneralExecStatus> AccessDelete(Guid userId, Guid accountId, Guid accessUserId)
{
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null || !account.AccessRights!.Any() || account.AccessRights!.Count() == 1)
{
return result.Set(GeneralExecStatus.not_found);
}
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == accessUserId);
if (access == null)
{
return result.Set(GeneralExecStatus.not_found);
}
if (access.OwnerId == access.UserId)
{
return result.Set(GeneralExecStatus.not_found);
}
_accountAccessRepository.Delete(access);
account = _accountRepository.Get(userId, accountId);
return result.Set(_mapper.Map<AccountDto>(account));
}
public List<AccountAccessInviteDto> InvitesGet(string email)
{
return _mapper.Map<List<AccountAccessInviteDto>>(_accountAccessInviteRepository.GetActive(email).ToList());
}
public Exec<AccountDto, InviteAcceptStatus> InviteAccept(Guid userId, Guid id, string name)
{
var result = new Exec<AccountDto, InviteAcceptStatus>(InviteAcceptStatus.success);
var invite = _accountAccessInviteRepository.Get(id);
if (invite == null
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|| invite.AcceptedOn.HasValue
|| invite.RejectedOn.HasValue
)
{
return result.Set(InviteAcceptStatus.invite_not_found);
}
var account = _accountRepository.Get(invite.UserId, invite.AccountId);
if (account == null)
{
return result.Set(InviteAcceptStatus.account_not_found);
}
if (account.AccessRights!.Any(x => x.UserId == userId))
{
result.Set(InviteAcceptStatus.already_accepted);
}
else
{
_accountAccessRepository.Add(new AccountAccess
{
UserId = userId,
AccountId = account.Id,
OwnerId = invite.UserId,
Name = name,
IsAllowWrite = invite.IsAllowWrite,
Type = AccountAccessTypeEnum.external,
});
}
invite.AcceptedOn = DateTime.UtcNow;
_accountAccessInviteRepository.Update(invite);
account = _accountRepository.Get(userId, account.Id);
return result.Set(_mapper.Map<AccountDto>(account));
}
public Exec<AccountAccessInviteDto, GeneralExecStatus> InviteReject(Guid id)
{
var result = new Exec<AccountAccessInviteDto, GeneralExecStatus>(GeneralExecStatus.success);
var invite = _accountAccessInviteRepository.Get(id);
if (invite == null
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|| invite.AcceptedOn.HasValue
|| invite.RejectedOn.HasValue
)
{
return result.Set(GeneralExecStatus.not_found);
}
invite.RejectedOn = DateTime.UtcNow;
_accountAccessInviteRepository.Update(invite);
return result.Set(_mapper.Map<AccountAccessInviteDto>(invite));
}
}
@@ -0,0 +1,209 @@
namespace MyOffice.Services.Account;
using MyOffice.Core;
using MyOffice.Core.Extensions;
using MyOffice.Data.Models.Accounts;
using MyOffice.Services.Account.Domain;
public partial class AccountService
{
public List<AccountDto> GetAllAccounts(Guid userId)
{
return _accountRepository
.GetAll(userId)
.ToDto<AccountDto>(_mapper);
}
public List<AccountDto> GetByCategory(Guid userId, Guid categoryId)
{
return _accountRepository
.GetByCategory(userId, categoryId)
.ToDto<AccountDto>(_mapper);
}
public List<AccountDto> FindAccounts(Guid userId, string term)
{
return _accountRepository
.FindAccounts(userId, term)
.ToDto<AccountDto>(_mapper);
}
public List<AccountDetailedDto> GetByCategoryDetailed(Guid userId, Guid categoryId)
{
return _accountRepository
.GetByCategoryDetailed(userId, categoryId)
.ToDto<AccountDetailedDto>(_mapper);
}
public Exec<AccountDetailedDto, GeneralExecStatus> GetByIdDetailed(Guid userId, Guid id)
{
var result = new Exec<AccountDetailedDto, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.GetByIdDetailed(userId, id);
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
return result.Set(account.ToDto<AccountDetailedDto>(_mapper));;
}
public Exec<AccountDto, AccountAddStatus> AccountAdd(Guid userId, AccountAdd input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var result = new Exec<AccountDto, AccountAddStatus>(AccountAddStatus.success);
var category = _accountCategoryRepository.Get(userId, input.CategoryId);
if (category == null)
{
return result.Set(AccountAddStatus.category_not_found);
}
var currency = _currencyRepository.GetByGlobalCurrency(userId, input.CurrencyId);
if (currency == null)
{
return result.Set(AccountAddStatus.currency_not_found);
}
var account = new Account
{
Id = Guid.NewGuid(),
Name = input.Name,
CurrencyGlobalId = currency.CurrencyGlobalId,
OwnerId = userId,
};
account.Categories = new List<AccountAccountCategory>
{
new()
{
AccountId = account.Id,
CategoryId = category.Id,
}
};
account.AccessRights = new List<AccountAccess>
{
new()
{
AccountId = account.Id,
UserId = userId,
OwnerId = userId,
IsAllowManage = true,
IsAllowRead = true,
IsAllowWrite = true,
}
};
if (!_accountRepository.Add(account))
{
return result.Set(AccountAddStatus.failure);
}
// TODO: Add category refactoring
if (!_accountAccountCategoryRepository.Add(account.Categories.FirstOrDefault()!))
{
return result.Set(AccountAddStatus.failure);
}
// TODO: Add access refactoring
if (!_accountAccessRepository.Add(account.AccessRights.FirstOrDefault()!))
{
return result.Set(AccountAddStatus.failure);
}
// TODO: Add account update AccessRights ???
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId);
if (access != null && access.Type.ToString() != input.Type)
{
if (Enum.TryParse<AccountAccessTypeEnum>(input.Type, out var enumType))
{
access.Type = enumType;
_accountAccessRepository.Update(access);
}
}
return result.Set(account.ToDto<AccountDto>(_mapper));
}
public Exec<AccountDto, GeneralExecStatus> AccountDelete(Guid userId, string id)
{
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, id.AsGuid());
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
if (account.Motions!.Any())
{
return result.Set(GeneralExecStatus.not_found);
}
_accountRepository.Delete(account);
result.Set(account.ToDto<AccountDto>(_mapper));
return result;
}
public Exec<AccountDto, AccountEditStatus> AccountUpdate(Guid userId, Guid accountId, AccountEdit input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var result = new Exec<AccountDto, AccountEditStatus>(AccountEditStatus.success);
AccountCategory? category = null;
if (input.CategoryId.HasValue)
{
category = _accountCategoryRepository.Get(userId, input.CategoryId.Value);
if (category == null)
{
return result.Set(AccountEditStatus.category_not_found);
}
}
var currency = _currencyRepository.GetByGlobalCurrency(userId, input.CurrencyId);
if (currency == null)
{
return result.Set(AccountEditStatus.currency_not_found);
}
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(AccountEditStatus.not_found);
}
account.Name = input.Name;
if (account.CurrencyGlobalId != currency.CurrencyGlobalId)
{
account.CurrencyGlobalId = currency.CurrencyGlobalId;
}
if (category != null && account.Categories!.All(x => x.CategoryId != category.Id))
{
_accountAccountCategoryRepository.Add(new AccountAccountCategory
{
AccountId = account.Id,
CategoryId = category.Id,
});
}
if (!_accountRepository.Update(account))
{
return result.Set(AccountEditStatus.failure);
}
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId);
if (access != null && access.Type.ToString() != input.Type)
{
if (Enum.TryParse<AccountAccessTypeEnum>(input.Type, out var enumType))
{
access.Type = enumType;
_accountAccessRepository.Update(access);
}
}
return result.Set(account.ToDto<AccountDto>(_mapper));
}
}
@@ -0,0 +1,114 @@
namespace MyOffice.Services.Account;
using MyOffice.Core;
using MyOffice.Data.Models.Accounts;
using MyOffice.Services.Account.Domain;
public partial class AccountService
{
public List<AccountCategoryDto> GetAllCategories(Guid userId)
{
var categories = _accountCategoryRepository.GetAll(userId);
return _mapper.Map<List<AccountCategoryDto>>(categories);
}
public Exec<AccountCategoryDto, GeneralExecStatus> GetCategory(Guid userId, Guid id)
{
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
var category = _accountCategoryRepository.Get(userId, id);
if (category == null)
{
return result.Set(GeneralExecStatus.not_found);
}
return result.Set(_mapper.Map<AccountCategoryDto>(category));
}
public Exec<AccountCategoryDto, GeneralExecStatus> CategoryAdd(Guid userId, AccountCategoryDto input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
var category = new AccountCategory
{
Id = Guid.NewGuid(),
UserId = userId,
Name = input.Name,
};
if (!_accountCategoryRepository.Add(category))
{
return result.Set(GeneralExecStatus.failure);
}
return result.Set(_mapper.Map<AccountCategoryDto>(category));
}
public Exec<AccountCategoryDto, GeneralExecStatus> CategoryUpdate(Guid userId, Guid id, AccountCategoryDto input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
var exists = _accountCategoryRepository.Get(userId, id);
if (exists == null)
{
return result.Set(GeneralExecStatus.not_found);
}
exists.Name = input.Name;
if (!_accountCategoryRepository.Update(exists))
{
return result.Set(GeneralExecStatus.failure);
}
return result.Set(_mapper.Map<AccountCategoryDto>(exists));
}
public Exec<AccountCategoryDto, AccountCategoryRemoveResult> CategoryRemove(Guid userId, Guid id)
{
var result = new Exec<AccountCategoryDto, AccountCategoryRemoveResult>(AccountCategoryRemoveResult.success);
var exists = _accountCategoryRepository.Get(userId, id);
if (exists == null)
{
return result.Set(AccountCategoryRemoveResult.not_found);
}
if (exists.Accounts?.Any() == true)
{
return result.Set(AccountCategoryRemoveResult.accounts_exists);
}
if (!_accountCategoryRepository.Remove(exists))
{
return result.Set(AccountCategoryRemoveResult.failure);
}
return result.Set(_mapper.Map<AccountCategoryDto>(exists));
}
public Exec<List<AccountAccountCategoryDto>, GeneralExecStatus> AccountCategoryRemove(Guid userId, Guid accountId, Guid categoryId)
{
var result = new Exec<List<AccountAccountCategoryDto>, GeneralExecStatus>(GeneralExecStatus.success);
var categories = _accountAccountCategoryRepository.Get(userId, accountId, categoryId);
if (categories.Count == 0)
{
return result.Set(GeneralExecStatus.not_found);
}
foreach (var category in categories)
{
_accountAccountCategoryRepository.Remove(category);
}
return result.Set(_mapper.Map<List<AccountAccountCategoryDto>>(categories));
}
}
@@ -0,0 +1,178 @@
namespace MyOffice.Services.Account;
using System.Collections.Generic;
using Core;
using Core.Extensions;
using Data.Models.Accounts;
using Domain;
using Item.Domain;
public partial class AccountService
{
public Exec<List<MotionDto>, MotionAddStatus> MotionAdd(
Guid userId,
Guid accountId,
MotionAddUpdate motion
)
{
if (motion == null)
throw new ArgumentNullException(nameof(motion));
if (motion.Item == null)
throw new ArgumentNullException(nameof(motion.Item));
var result = new Exec<List<MotionDto>, MotionAddStatus>(MotionAddStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(MotionAddStatus.account_not_found);
}
var itemExec = _itemService.GetOrCreate(userId, motion.Item);
if (itemExec.Status != ItemGetOrAddResult.success)
{
return result.Set(MotionAddStatus.failure);
}
var motionDb = new Motion
{
Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow,
DateTime = motion.Date,
AccountId = account.Id,
ItemId = itemExec.Result!.Id,
Description = motion.Description,
AmountPlus = motion.Plus,
AmountMinus = motion.Minus,
};
if (!_motionRepository.Add(motionDb))
{
return result.Set(MotionAddStatus.failure);
}
result.Set(new List<MotionDto>());
result.Result!.Add(_mapper.Map<MotionDto>(motionDb));
if (motion.AccountId.IsPresent() && motion.AmountBalancing != 0)
{
var accountBalancing = _accountRepository.Get(userId, motion.AccountId!.AsGuid());
if (accountBalancing != null)
{
var balancingName = $"+{account.Name}";
var itemBalancingExec = _itemService.GetOrCreate(userId, balancingName);
var plus = motion.AmountBalancing;
var minus = 0m;
if (motion.Plus != 0)
{
plus = 0;
minus = motion.AmountBalancing;
}
var motionBalancing = new Motion
{
Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow,
DateTime = motion.Date,
AccountId = accountBalancing.Id,
ItemId = itemBalancingExec.Result!.Id,
Description = motion.Description,
AmountPlus = plus,
AmountMinus = minus,
};
if (_motionRepository.Add(motionBalancing))
{
result.Result!.Add(_mapper.Map<MotionDto>(motionBalancing));
}
}
}
motionDb.Item = itemExec.Result!;
return result;
}
public Exec<MotionDto, MotionUpdateStatus> MotionUpdate(
Guid userId,
Guid accountId,
Guid motionId,
MotionAddUpdate motion
)
{
if (motion == null)
throw new ArgumentNullException(nameof(motion));
if (motion.Item == null)
throw new ArgumentNullException(nameof(motion.Item));
var result = new Exec<MotionDto, MotionUpdateStatus>(MotionUpdateStatus.success);
var exists = _motionRepository.Get(userId, motionId);
if (exists == null || exists.AccountId != accountId)
{
return result.Set(MotionUpdateStatus.not_found);
}
var itemExec = _itemService.GetOrCreate(userId, motion.Item);
if (itemExec.Status != ItemGetOrAddResult.success)
{
return result.Set(MotionUpdateStatus.failure);
}
exists.Item.Id = itemExec.Result!.Id;
exists.DateTime = motion.Date;
exists.Description = motion.Description;
exists.AmountPlus = motion.Plus;
exists.AmountMinus = motion.Minus;
if (!_motionRepository.Update(exists))
{
return result.Set(MotionUpdateStatus.failure);
}
return result.Set(_mapper.Map<MotionDto>(exists));
}
public Exec<List<MotionDto>, GeneralExecStatus> GetMotions(
Guid userId,
Guid accountId,
DateTime dateFrom,
DateTime dateTo
)
{
var result = new Exec<List<MotionDto>, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
var motions = _motionRepository.GetByAccount(accountId, dateFrom.ToUtc(), dateTo.ToUtc());
return result.Set(_mapper.Map<List<MotionDto>>(motions));
}
public Exec<MotionDto, MotionDeleteStatus> MotionRemove(
Guid userId,
Guid accountId,
Guid motionId
)
{
var result = new Exec<MotionDto, MotionDeleteStatus>(MotionDeleteStatus.success);
var exists = _motionRepository.Get(userId, motionId);
if (exists == null || exists.AccountId != accountId)
{
return result.Set(MotionDeleteStatus.not_found);
}
if (!_motionRepository.Remove(exists))
{
return result.Set(MotionDeleteStatus.failure);
}
return result.Set(_mapper.Map<MotionDto>(exists));
}
}
+53 -680
View File
@@ -1,685 +1,58 @@
namespace MyOffice.Services.Account
namespace MyOffice.Services.Account;
using AutoMapper;
using Microsoft.Extensions.Logging;
using Identity;
using Data.Repositories.Account;
using Data.Repositories.Currency;
using Data.Repositories.Item;
using Item;
public partial class AccountService
{
using AutoMapper;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
private ILogger<AccountService> _logger;
private readonly IMapper _mapper;
private readonly IAccountCategoryRepository _accountCategoryRepository;
private readonly IAccountAccessRepository _accountAccessRepository;
private readonly IAccountAccessInviteRepository _accountAccessInviteRepository;
private readonly IAccountRepository _accountRepository;
private readonly ICurrencyRepository _currencyRepository;
private readonly IAccountAccountCategoryRepository _accountAccountCategoryRepository;
private readonly IMotionRepository _motionRepository;
private readonly IItemRepository _itemRepository;
private readonly IItemGlobalRepository _itemGlobalRepository;
private readonly ItemService _itemService;
private readonly IContextProvider _contextProvider;
using Identity;
using Core;
using Core.Extensions;
using Data.Models.Accounts;
using Data.Repositories.Account;
using Data.Repositories.Currency;
using Data.Repositories.Item;
using Domain;
using Item;
using Item.Domain;
public class AccountService
public AccountService(
ILogger<AccountService> logger,
IMapper mapper,
IAccountCategoryRepository accountCategoryRepository,
IAccountAccessRepository accountAccessRepository,
IAccountAccessInviteRepository accountAccessInviteRepository,
IAccountRepository accountRepository,
ICurrencyRepository currencyRepository,
IAccountAccountCategoryRepository accountAccountCategoryRepository,
IMotionRepository motionRepository,
IItemRepository itemRepository,
IItemGlobalRepository itemGlobalRepository,
ItemService itemService,
IContextProvider contextProvider
)
{
private ILogger<AccountService> _logger;
private readonly IMapper _mapper;
private readonly IAccountCategoryRepository _accountCategoryRepository;
private readonly IAccountAccessRepository _accountAccessRepository;
private readonly IAccountAccessInviteRepository _accountAccessInviteRepository;
private readonly IAccountRepository _accountRepository;
private readonly ICurrencyRepository _currencyRepository;
private readonly IAccountAccountCategoryRepository _accountAccountCategoryRepository;
private readonly IMotionRepository _motionRepository;
private readonly IItemRepository _itemRepository;
private readonly IItemGlobalRepository _itemGlobalRepository;
private readonly ItemService _itemService;
private readonly IContextProvider _contextProvider;
public AccountService(
ILogger<AccountService> logger,
IMapper mapper,
IAccountCategoryRepository accountCategoryRepository,
IAccountAccessRepository accountAccessRepository,
IAccountAccessInviteRepository accountAccessInviteRepository,
IAccountRepository accountRepository,
ICurrencyRepository currencyRepository,
IAccountAccountCategoryRepository accountAccountCategoryRepository,
IMotionRepository motionRepository,
IItemRepository itemRepository,
IItemGlobalRepository itemGlobalRepository,
ItemService itemService,
IContextProvider contextProvider
)
{
_logger = logger;
_mapper = mapper;
_accountCategoryRepository = accountCategoryRepository;
_accountAccessRepository = accountAccessRepository;
_accountAccessInviteRepository = accountAccessInviteRepository;
_accountRepository = accountRepository;
_currencyRepository = currencyRepository;
_accountAccountCategoryRepository = accountAccountCategoryRepository;
_motionRepository = motionRepository;
_itemRepository = itemRepository;
_itemGlobalRepository = itemGlobalRepository;
_itemService = itemService;
_contextProvider = contextProvider;
}
public List<AccountCategoryDto> GetAllCategories(Guid userId)
{
var categories = _accountCategoryRepository.GetAll(userId);
return _mapper.Map<List<AccountCategoryDto>>(categories);
}
public Exec<AccountCategoryDto, GeneralExecStatus> GetCategory(Guid userId, Guid id)
{
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
var category = _accountCategoryRepository.Get(userId, id);
if (category == null)
{
return result.Set(GeneralExecStatus.not_found);
}
return result.Set(_mapper.Map<AccountCategoryDto>(category));
}
public Exec<AccountCategoryDto, GeneralExecStatus> CategoryAdd(Guid userId, AccountCategoryDto input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
var category = new AccountCategory
{
Id = Guid.NewGuid(),
UserId = userId,
Name = input.Name,
};
if (!_accountCategoryRepository.Add(category))
{
return result.Set(GeneralExecStatus.failure);
}
return result.Set(_mapper.Map<AccountCategoryDto>(category));
}
public Exec<AccountCategoryDto, GeneralExecStatus> CategoryUpdate(Guid userId, Guid id, AccountCategoryDto input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
var exists = _accountCategoryRepository.Get(userId, id);
if (exists == null)
{
return result.Set(GeneralExecStatus.not_found);
}
exists.Name = input.Name;
if (!_accountCategoryRepository.Update(exists))
{
return result.Set(GeneralExecStatus.failure);
}
return result.Set(_mapper.Map<AccountCategoryDto>(exists));
}
public Exec<AccountCategoryDto, AccountCategoryRemoveResult> CategoryRemove(Guid userId, Guid id)
{
var result = new Exec<AccountCategoryDto, AccountCategoryRemoveResult>(AccountCategoryRemoveResult.success);
var exists = _accountCategoryRepository.Get(userId, id);
if (exists == null)
{
return result.Set(AccountCategoryRemoveResult.not_found);
}
if (exists.Accounts?.Any() == true)
{
return result.Set(AccountCategoryRemoveResult.accounts_exists);
}
if (!_accountCategoryRepository.Remove(exists))
{
return result.Set(AccountCategoryRemoveResult.failure);
}
return result.Set(_mapper.Map<AccountCategoryDto>(exists));
}
public List<AccountDto> GetAllAccounts(Guid userId)
{
var accounts = _accountRepository.GetAll(userId);
return _mapper.Map<List<AccountDto>>(accounts, o => o.Items.Add("UserId", userId));
}
public List<AccountDto> GetByCategory(Guid userId, Guid categoryId)
{
return _mapper.Map<List<AccountDto>>(_accountRepository.GetByCategory(userId, categoryId));
}
public List<AccountDetailedDto> GetByCategoryDetailed(Guid userId, Guid categoryId)
{
return _mapper.Map<List<AccountDetailedDto>>(_accountRepository.GetByCategoryDetailed(userId, categoryId));
}
public Exec<AccountDetailedDto, GeneralExecStatus> GetByIdDetailed(Guid userId, Guid id)
{
var result = new Exec<AccountDetailedDto, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.GetByIdDetailed(userId, id);
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
return result.Set(_mapper.Map<AccountDetailedDto>(account));
}
public Exec<Account, AccountAddStatus> AccountAdd(Guid userId, AccountAdd input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var result = new Exec<Account, AccountAddStatus>(AccountAddStatus.success);
var category = _accountCategoryRepository.Get(userId, input.CategoryId);
if (category == null)
{
return result.Set(AccountAddStatus.category_not_found);
}
var currency = _currencyRepository.GetByGlobalCurrency(userId, input.CurrencyId);
if (currency == null)
{
return result.Set(AccountAddStatus.currency_not_found);
}
var account = new Account
{
Id = Guid.NewGuid(),
Name = input.Name,
CurrencyGlobalId = currency.CurrencyGlobalId,
OwnerId = userId,
};
account.Categories = new List<AccountAccountCategory>
{
new()
{
AccountId = account.Id,
CategoryId = category.Id,
}
};
account.AccessRights = new List<AccountAccess>
{
new()
{
AccountId = account.Id,
UserId = userId,
OwnerId = userId,
IsAllowManage = true,
IsAllowRead = true,
IsAllowWrite = true,
}
};
if (!_accountRepository.Add(account))
{
return result.Set(AccountAddStatus.failure);
}
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId);
if (access != null && access.Type.ToString() != input.Type)
{
if (Enum.TryParse<AccountAccessTypeEnum>(input.Type, out var enumType))
{
access.Type = enumType;
_accountAccessRepository.Update(access);
}
}
return result.Set(account);
}
public Exec<Account, GeneralExecStatus> AccountDelete(Guid userId, string id)
{
var result = new Exec<Account, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, id.AsGuid());
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
if (account.Motions!.Any())
{
return result.Set(GeneralExecStatus.not_found);
}
_accountRepository.Delete(account);
result.Set(account);
return result;
}
public Exec<Account, AccountEditStatus> AccountUpdate(Guid userId, Guid accountId, AccountEdit input)
{
if (input == null)
throw new ArgumentNullException(nameof(input));
var result = new Exec<Account, AccountEditStatus>(AccountEditStatus.success);
AccountCategory? category = null;
if (input.CategoryId.HasValue)
{
category = _accountCategoryRepository.Get(userId, input.CategoryId.Value);
if (category == null)
{
return result.Set(AccountEditStatus.category_not_found);
}
}
var currency = _currencyRepository.GetByGlobalCurrency(userId, input.CurrencyId);
if (currency == null)
{
return result.Set(AccountEditStatus.currency_not_found);
}
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(AccountEditStatus.not_found);
}
account.Name = input.Name;
if (account.CurrencyGlobalId != currency.CurrencyGlobalId)
{
account.CurrencyGlobalId = currency.CurrencyGlobalId;
}
if (category != null && account.Categories!.All(x => x.CategoryId != category.Id))
{
_accountAccountCategoryRepository.Add(new AccountAccountCategory
{
AccountId = account.Id,
CategoryId = category.Id,
});
}
if (!_accountRepository.Update(account))
{
return result.Set(AccountEditStatus.failure);
}
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId);
if (access != null && access.Type.ToString() != input.Type)
{
if (Enum.TryParse<AccountAccessTypeEnum>(input.Type, out var enumType))
{
access.Type = enumType;
_accountAccessRepository.Update(access);
}
}
return result.Set(account);
}
public Exec<List<AccountAccountCategory>, GeneralExecStatus> AccountCategoryRemove(Guid userId, Guid accountId, Guid categoryId)
{
var result = new Exec<List<AccountAccountCategory>, GeneralExecStatus>(GeneralExecStatus.success);
var categories = _accountAccountCategoryRepository.Get(userId, accountId, categoryId);
if (categories.Count == 0)
{
return result.Set(GeneralExecStatus.not_found);
}
foreach (var category in categories)
{
_accountAccountCategoryRepository.Remove(category);
}
return result.Set(categories);
}
public Exec<List<MotionDto>, MotionAddStatus> MotionAdd(
Guid userId,
Guid accountId,
MotionAddUpdate motion
)
{
if (motion == null)
throw new ArgumentNullException(nameof(motion));
if (motion.Item == null)
throw new ArgumentNullException(nameof(motion.Item));
var result = new Exec<List<MotionDto>, MotionAddStatus>(MotionAddStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(MotionAddStatus.account_not_found);
}
var itemExec = _itemService.GetOrCreate(userId, motion.Item);
if (itemExec.Status != ItemGetOrAddResult.success)
{
return result.Set(MotionAddStatus.failure);
}
var motionDb = new Motion
{
Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow,
DateTime = motion.Date,
AccountId = account.Id,
ItemId = itemExec.Result!.Id,
Description = motion.Description,
AmountPlus = motion.Plus,
AmountMinus = motion.Minus,
};
if (!_motionRepository.Add(motionDb))
{
return result.Set(MotionAddStatus.failure);
}
result.Set(new List<MotionDto>());
result.Result!.Add(_mapper.Map<MotionDto>(motionDb));
if (motion.AccountId.IsPresent() && motion.AmountBalancing != 0)
{
var accountBalancing = _accountRepository.Get(userId, motion.AccountId!.AsGuid());
if (accountBalancing != null)
{
var balancingName = $"+{account.Name}";
var itemBalancingExec = _itemService.GetOrCreate(userId, balancingName);
var plus = motion.AmountBalancing;
var minus = 0m;
if (motion.Plus != 0)
{
plus = 0;
minus = motion.AmountBalancing;
}
var motionBalancing = new Motion
{
Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow,
DateTime = motion.Date,
AccountId = accountBalancing.Id,
ItemId = itemBalancingExec.Result!.Id,
Description = motion.Description,
AmountPlus = plus,
AmountMinus = minus,
};
if (_motionRepository.Add(motionBalancing))
{
result.Result!.Add(_mapper.Map<MotionDto>(motionBalancing));
}
}
}
motionDb.Item = itemExec.Result!;
return result;
}
public Exec<MotionDto, MotionUpdateStatus> MotionUpdate(
Guid userId,
Guid accountId,
Guid motionId,
MotionAddUpdate motion
)
{
if (motion == null)
throw new ArgumentNullException(nameof(motion));
if (motion.Item == null)
throw new ArgumentNullException(nameof(motion.Item));
var result = new Exec<MotionDto, MotionUpdateStatus>(MotionUpdateStatus.success);
var exists = _motionRepository.Get(userId, motionId);
if (exists == null || exists.AccountId != accountId)
{
return result.Set(MotionUpdateStatus.not_found);
}
var itemExec = _itemService.GetOrCreate(userId, motion.Item);
if (itemExec.Status != ItemGetOrAddResult.success)
{
return result.Set(MotionUpdateStatus.failure);
}
exists.Item.Id = itemExec.Result!.Id;
exists.DateTime = motion.Date;
exists.Description = motion.Description;
exists.AmountPlus = motion.Plus;
exists.AmountMinus = motion.Minus;
if (!_motionRepository.Update(exists))
{
return result.Set(MotionUpdateStatus.failure);
}
return result.Set(_mapper.Map<MotionDto>(exists));
}
public Exec<List<Motion>, GeneralExecStatus> GetMotions(
Guid userId,
Guid accountId,
DateTime dateFrom,
DateTime dateTo
)
{
var result = new Exec<List<Motion>, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
var motions = _motionRepository.GetByAccount(accountId, dateFrom.ToUtc(), dateTo.ToUtc());
return result.Set(motions);
}
public Exec<Motion, MotionDeleteStatus> MotionRemove(
Guid userId,
Guid accountId,
Guid motionId
)
{
var result = new Exec<Motion, MotionDeleteStatus>(MotionDeleteStatus.success);
var exists = _motionRepository.Get(userId, motionId);
if (exists == null || exists.AccountId != accountId)
{
return result.Set(MotionDeleteStatus.not_found);
}
if (!_motionRepository.Remove(exists))
{
return result.Set(MotionDeleteStatus.failure);
}
return result.Set(exists);
}
public List<Account> FindAccounts(Guid userId, string term)
{
return _accountRepository.FindAccounts(userId, term);
}
public Exec<AccountAccessInvite, AccessInviteStatus> AccessInvite(Guid userId, Guid accountId, string email, bool isAllowWrite)
{
if (email == null)
throw new ArgumentNullException(nameof(email));
var result = new Exec<AccountAccessInvite, AccessInviteStatus>(AccessInviteStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(AccessInviteStatus.account_not_found);
}
if (account.AccessRights!.Any(x => x.User!.Email.EqualsIgnoreCase(email)))
{
return result.Set(AccessInviteStatus.access_exists);
}
var access = _accountAccessInviteRepository.Get(userId, email);
if (access != null)
{
return result.Set(AccessInviteStatus.invite_exists);
}
var invite = new AccountAccessInvite
{
Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow,
UserId = userId,
AccountId = account.Id,
Email = email.SafeTrim()!,
IsAllowWrite = isAllowWrite,
};
_accountAccessInviteRepository.Add(invite);
return result.Set(invite);
}
public Exec<AccountDto, GeneralExecStatus> AccessUpdate(Guid userId, Guid accountId, List<AccountAccessDto> accesses)
{
if (accesses == null)
throw new ArgumentNullException(nameof(accesses));
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null)
{
return result.Set(GeneralExecStatus.not_found);
}
foreach (var access in account.AccessRights!)
{
var newAccess = accesses.FirstOrDefault(x => x.UserId == access.UserId);
if (newAccess != null && newAccess.IsAllowWrite != access.IsAllowWrite)
{
access.IsAllowWrite = newAccess.IsAllowWrite;
_accountAccessRepository.Update(access);
}
}
account = _accountRepository.Get(userId, accountId);
return result.Set(_mapper.Map<AccountDto>(account));
}
public Exec<AccountDto, GeneralExecStatus> AccessDelete(Guid userId, Guid accountId, Guid accessUserId)
{
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
var account = _accountRepository.Get(userId, accountId);
if (account == null || !account.AccessRights!.Any() || account.AccessRights!.Count() == 1)
{
return result.Set(GeneralExecStatus.not_found);
}
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == accessUserId);
if (access == null)
{
return result.Set(GeneralExecStatus.not_found);
}
if (access.OwnerId == access.UserId)
{
return result.Set(GeneralExecStatus.not_found);
}
_accountAccessRepository.Delete(access);
account = _accountRepository.Get(userId, accountId);
return result.Set(_mapper.Map<AccountDto>(account));
}
public List<AccountAccessInviteDto> InvitesGet(string email)
{
return _mapper.Map<List<AccountAccessInviteDto>>(_accountAccessInviteRepository.GetActive(email).ToList());
}
public Exec<AccountDto, InviteAcceptStatus> InviteAccept(Guid userId, Guid id, string name)
{
var result = new Exec<AccountDto, InviteAcceptStatus>(InviteAcceptStatus.success);
var invite = _accountAccessInviteRepository.Get(id);
if (invite == null
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|| invite.AcceptedOn.HasValue
|| invite.RejectedOn.HasValue
)
{
return result.Set(InviteAcceptStatus.invite_not_found);
}
var account = _accountRepository.Get(invite.UserId, invite.AccountId);
if (account == null)
{
return result.Set(InviteAcceptStatus.account_not_found);
}
if (account.AccessRights!.Any(x => x.UserId == userId))
{
result.Set(InviteAcceptStatus.already_accepted);
}
else
{
_accountAccessRepository.Add(new AccountAccess
{
UserId = userId,
AccountId = account.Id,
OwnerId = invite.UserId,
Name = name,
IsAllowWrite = invite.IsAllowWrite,
Type = AccountAccessTypeEnum.external,
});
}
invite.AcceptedOn = DateTime.UtcNow;
_accountAccessInviteRepository.Update(invite);
account = _accountRepository.Get(userId, account.Id);
return result.Set(_mapper.Map<AccountDto>(account));
}
public Exec<AccountAccessInviteDto, GeneralExecStatus> InviteReject(Guid id)
{
var result = new Exec<AccountAccessInviteDto, GeneralExecStatus>(GeneralExecStatus.success);
var invite = _accountAccessInviteRepository.Get(id);
if (invite == null
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|| invite.AcceptedOn.HasValue
|| invite.RejectedOn.HasValue
)
{
return result.Set(GeneralExecStatus.not_found);
}
invite.RejectedOn = DateTime.UtcNow;
_accountAccessInviteRepository.Update(invite);
return result.Set(_mapper.Map<AccountAccessInviteDto>(invite));
}
_logger = logger;
_mapper = mapper;
_accountCategoryRepository = accountCategoryRepository;
_accountAccessRepository = accountAccessRepository;
_accountAccessInviteRepository = accountAccessInviteRepository;
_accountRepository = accountRepository;
_currencyRepository = currencyRepository;
_accountAccountCategoryRepository = accountAccountCategoryRepository;
_motionRepository = motionRepository;
_itemRepository = itemRepository;
_itemGlobalRepository = itemGlobalRepository;
_itemService = itemService;
_contextProvider = contextProvider;
}
}
@@ -1,19 +1,16 @@
namespace MyOffice.Services.Account.Domain;
using AutoMapper;
using Core.Attributes;
using Data.Models.Accounts;
using Data.Models.Users;
using Mapper;
using MyOffice.Services.Identity;
[Link(typeof(AccountAccess))]
[Link(typeof(AccountServiceProfile))]
public class AccountAccessDto
{
/// <summary>
/// Current user
/// </summary>
public Guid CurrenUserId { get; set; }
public Guid AccountId { get; set; }
public AccountDto? Account { get; set; }
@@ -21,15 +18,41 @@ public class AccountAccessDto
/// User can access to account
/// </summary>
public Guid UserId { get; set; }
public User? User { get; set; }
/// <summary>
/// Who add access
/// </summary>
public Guid OwnerId { get; set; }
public User? Owner { get; set; }
public UserDto? User { get; set; }
public bool IsAllowRead { get; set; }
public bool IsAllowWrite { get; set; }
public bool IsAllowManage { get; set; }
public bool IsOwner { get; set; }
public AccountAccessTypeEnum Type { get; set; }
/// <summary>
/// Who add access
/// </summary>
public Guid OwnerId { get; set; }
public UserDto? Owner { get; set; }
public string? Name { get; set; }
}
public class AccountAccessDtoProfile: Profile
{
public AccountAccessDtoProfile()
{
CreateMap<AccountAccess, AccountAccessDto>()
.AfterMap<AccountAccessDtoMappingAction>()
;
}
}
public class AccountAccessDtoMappingAction: IMappingAction<AccountAccess, AccountAccessDto>
{
private readonly IContextProvider _contextProvider;
public AccountAccessDtoMappingAction(IContextProvider contextProvider)
{
_contextProvider = contextProvider;
}
public void Process(AccountAccess source, AccountAccessDto destination, ResolutionContext context)
{
destination.IsOwner = destination.OwnerId == _contextProvider.UserId;
}
}
@@ -1,9 +1,21 @@
namespace MyOffice.Services.Account.Domain;
using AutoMapper;
using MyOffice.Core;
using MyOffice.Data.Models.Accounts;
public class AccountDetailedDto
namespace MyOffice.Services.Account.Domain;
public class AccountDetailedDto: IDataModelDto<AccountDetailed>
{
public AccountDto Account { get; set; } = null!;
public decimal TotalPlus { get; set; }
public decimal TotalMinus { get; set; }
public decimal Rest => TotalPlus - TotalMinus;
}
public class AccountDetailedDtoProfile: Profile
{
public AccountDetailedDtoProfile()
{
CreateMap<AccountDetailed, AccountDetailedDto>();
}
}
+64 -12
View File
@@ -1,27 +1,79 @@
namespace MyOffice.Services.Account.Domain;
using MyOffice.Data.Models.Currencies;
using System;
using Data.Models.Accounts;
using MyOffice.Services.Currency.Domain;
using AutoMapper;
using MyOffice.Services.Identity;
using MyOffice.Core;
using MyOffice.Services.Mapper;
public class AccountDto
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)]
public class GenerateMappedDtoAttribute: Attribute
{
public GenerateMappedDtoAttribute()
{
}
}
[GenerateMappedDto]
public class AccountDto : IDataModelDto<Account>
{
#region Account properties
public Guid Id { get; set; }
public string CurrencyGlobalId { get; set; } = null!;
public CurrencyGlobal? CurrencyGlobal { get; set; }
public Guid CurrencyId { get; set; }
public Currency? Currency { get; set; }
public Guid UserId { get; set; }
public UserDto? User { get; set; }
public CurrencyGlobalDto? CurrencyGlobal { get; set; }
public string Name { get; set; } = null!;
public Guid OwnerId { get; set; }
public UserDto? Owner { get; set; }
public string Name { get; set; } = null!;
public bool HasMotions { get; set; }
#endregion Account properties
#region Dto properties
public Guid CurrencyId { get; set; }
public CurrencyDto? Currency { get; set; }
public string Type { get; set; } = null!;
public List<AccountAccessDto>? AccessRights { get; set; }
public List<AccountAccountCategoryDto>? Categories { get; set; }
public bool HasMotions { get; set; }
public Guid CurrentUserId { get; set; }
public AccountAccess? AccountAccess { get; set; }
#endregion Dto properties
#region Permissions
public List<AccountAccessDto>? AccessRights { get; set; }
public bool AllowRead { get; set; }
public bool AllowWrite { get; set; }
public bool AllowDelete { get; set; }
public bool AllowManage { get; set; }
#endregion Permissions
}
public class AccountDtoProfile : BaseProfile<Account, AccountDto>
{
public AccountDtoProfile()
{
Mapping
.ForMember(x => x.HasMotions, o => o.MapFrom(x => x.Motions!.Any()))
.AfterMap<AccountDtoMappingAction>();
}
}
public class AccountDtoMappingAction : BaseMappingAction, IMappingAction<Account, AccountDto>
{
public AccountDtoMappingAction(IContextProvider contextProvider) : base(contextProvider) { }
public void Process(Account source, AccountDto destination, ResolutionContext context)
{
var accessRight = destination.AccessRights?.FirstOrDefault(x => x.UserId == ContextProvider.UserId);
destination.AllowRead = accessRight?.IsAllowRead ?? false;
destination.AllowWrite = accessRight?.IsAllowWrite ?? false;
destination.AllowManage = accessRight?.IsAllowManage ?? false;
destination.AllowDelete = (accessRight?.IsOwner ?? false) && !destination.HasMotions;
destination.Name = accessRight?.Name ?? destination.Name;
destination.Type = accessRight?.Name ?? destination.Type;
}
}
@@ -1,14 +1,13 @@
namespace MyOffice.Services.Account.Domain;
using MyOffice.Data.Models.Users;
using MyOffice.Data.Models.Items;
public class ItemCategoryDto
{
public Guid Id { get; set; }
public Guid UserId { get; set; }
public User User { get; set; } = null!;
public UserDto User { get; set; } = null!;
public string Name { get; set; } = null!;
public List<ItemDto> Items { get; set; } = null!;
public bool IsInternal { get; set; }
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
namespace MyOffice.Services.Account.Domain;
using Data.Models.Currencies;
using MyOffice.Services.Currency.Domain;
public class UserDto
{
@@ -13,5 +13,5 @@ public class UserDto
public string? Phone { get; set; }
public string CurrencyId { get; set; } = null!;
public CurrencyGlobal? Currency { get; set; }
}
public CurrencyGlobalDto? Currency { get; set; }
}