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 async Task> GetAllAccountsAsync(Guid userId, CancellationToken cancellationToken = default) { var accounts = await _accountRepository.GetAllAsync(userId, cancellationToken); return accounts.ToDto(_mapper); } public async Task> GetByCategoryAsync(Guid userId, Guid categoryId, CancellationToken cancellationToken = default) { var accounts = await _accountRepository.GetByCategoryAsync(userId, categoryId, cancellationToken); return accounts.ToDto(_mapper); } public async Task> FindAccountsAsync(Guid userId, string term, CancellationToken cancellationToken = default) { var accounts = await _accountRepository.FindAccountsAsync(userId, term, cancellationToken); return accounts.ToDto(_mapper); } public List GetByCategoryDetailed(Guid userId, Guid categoryId) { return _accountRepository .GetByCategoryDetailed(userId, categoryId) .ToDto(_mapper); } public async Task> GetByCategoryDetailedAsync( Guid userId, Guid categoryId, CancellationToken cancellationToken = default ) { var list = await _accountRepository.GetByCategoryDetailedAsync(userId, categoryId, cancellationToken); return list.ToDto(_mapper); } public Exec GetByIdDetailed(Guid userId, Guid id) { var result = new Exec(GeneralExecStatus.success); var account = _accountRepository.GetByIdDetailed(userId, id); if (account == null) { return result.Set(GeneralExecStatus.not_found); } return result.Set(account.ToDto(_mapper));; } public async Task> GetByIdDetailedAsync( Guid userId, Guid id, CancellationToken cancellationToken = default ) { var result = new Exec(GeneralExecStatus.success); var account = await _accountRepository.GetByIdDetailedAsync(userId, id, cancellationToken); if (account == null) { return result.Set(GeneralExecStatus.not_found); } return result.Set(account.ToDto(_mapper)); } public async Task> AccountAddAsync( Guid userId, AccountAdd input, CancellationToken cancellationToken = default ) { if (input == null) throw new ArgumentNullException(nameof(input)); var result = new Exec(AccountAddStatus.success); var category = await _accountCategoryRepository.GetAsync(userId, input.CategoryId, cancellationToken); if (category == null) { return result.Set(AccountAddStatus.category_not_found); } var currency = await _currencyRepository.GetByGlobalCurrencyAsync(userId, input.CurrencyId, cancellationToken); 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 { new() { AccountId = account.Id, CategoryId = category.Id, } }; account.AccessRights = new List { new() { AccountId = account.Id, UserId = userId, OwnerId = userId, IsAllowManage = true, IsAllowRead = true, IsAllowWrite = true, } }; if (!await _accountRepository.AddAsync(account, cancellationToken)) { return result.Set(AccountAddStatus.failure); } // TODO: Add category refactoring if (!await _accountAccountCategoryRepository.AddAsync(account.Categories.FirstOrDefault()!, cancellationToken)) { return result.Set(AccountAddStatus.failure); } // TODO: Add access refactoring if (!await _accountAccessRepository.AddAsync(account.AccessRights.FirstOrDefault()!, cancellationToken)) { 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(input.Type, out var enumType)) { access.Type = enumType; await _accountAccessRepository.UpdateAsync(access, cancellationToken); } } return result.Set(account.ToDto(_mapper)); } public async Task> AccountDeleteAsync( Guid userId, string id, CancellationToken cancellationToken = default ) { var result = new Exec(GeneralExecStatus.success); var account = await _accountRepository.GetAsync(userId, id.AsGuid(), cancellationToken); if (account == null) { return result.Set(GeneralExecStatus.not_found); } if (!CanManage(account, userId)) { return result.Set(GeneralExecStatus.forbidden); } if (account.Motions!.Any()) { return result.Set(GeneralExecStatus.not_found); } await _accountRepository.DeleteAsync(account, cancellationToken); result.Set(account.ToDto(_mapper)); return result; } public async Task> AccountUpdateAsync( Guid userId, Guid accountId, AccountEdit input, CancellationToken cancellationToken = default ) { if (input == null) throw new ArgumentNullException(nameof(input)); var result = new Exec(AccountEditStatus.success); AccountCategory? category = null; if (input.CategoryId.HasValue) { category = await _accountCategoryRepository.GetAsync(userId, input.CategoryId.Value, cancellationToken); if (category == null) { return result.Set(AccountEditStatus.category_not_found); } } var currency = await _currencyRepository.GetByGlobalCurrencyAsync(userId, input.CurrencyId, cancellationToken); if (currency == null) { return result.Set(AccountEditStatus.currency_not_found); } var account = await _accountRepository.GetAsync(userId, accountId, cancellationToken); if (account == null) { return result.Set(AccountEditStatus.not_found); } if (!CanManage(account, userId)) { return result.Set(AccountEditStatus.forbidden); } account.Name = input.Name; if (account.CurrencyGlobalId != currency.CurrencyGlobalId) { account.CurrencyGlobalId = currency.CurrencyGlobalId; } AccountAccountCategory? addedLink = null; if (category != null && account.Categories!.All(x => x.CategoryId != category.Id)) { addedLink = new AccountAccountCategory { AccountId = account.Id, CategoryId = category.Id, Category = category, }; await _accountAccountCategoryRepository.AddAsync(addedLink, cancellationToken); } if (!await _accountRepository.UpdateAsync(account, cancellationToken)) { 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(input.Type, out var enumType)) { access.Type = enumType; await _accountAccessRepository.UpdateAsync(access, cancellationToken); } } // AddAsync detaches the link and does not refresh Account.Categories — keep response in sync. if (addedLink != null && (account.Categories?.All(x => x.CategoryId != addedLink.CategoryId) ?? true)) { account.Categories = (account.Categories ?? Enumerable.Empty()) .Append(addedLink) .ToList(); } return result.Set(account.ToDto(_mapper)); } }