using BankYouBankruptContracts.BindingModels; using BankYouBankruptContracts.BusinessLogicsContracts; using BankYouBankruptContracts.SearchModels; using BankYouBankruptContracts.StoragesContracts; using BankYouBankruptContracts.ViewModels; using BankYouBankruptContracts.ViewModels.Client.Diagram; using BankYouBankruptDataModels.Enums; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BankYouBankruptBusinessLogic.BusinessLogics { public class AccountLogic : IAccountLogic { private readonly ILogger _logger; private readonly IAccountStorage _accountStorage; private readonly ICashWithdrawalLogic _cashWithdrawalLogic; private readonly IMoneyTransferLogic _moneyTransferLogic; public AccountLogic(ILogger logger, IAccountStorage accountStorage, ICashWithdrawalLogic cashWithdrawalLogic, IMoneyTransferLogic moneyTransferLogic) { _logger = logger; _accountStorage = accountStorage; _cashWithdrawalLogic = cashWithdrawalLogic; _moneyTransferLogic = moneyTransferLogic; } public AccountViewModel? ReadElement(AccountSearchModel model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } _logger.LogInformation("ReadElement. AccountNumber:{Name}. Id:{Id}", model.AccountNumber, model?.Id); var element = _accountStorage.GetElement(model); if (element == null) { _logger.LogWarning("ReadElement element not found"); return null; } _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); return element; } public List? ReadList(AccountSearchModel? model) { //_logger.LogInformation("ReadList. AccountNumber:{AccountNumber}. Id:{Id}", model.AccountNumber, model?.Id); //list хранит весь список в случае, если model пришло со значением null на вход метода var list = model == null ? _accountStorage.GetFullList() : _accountStorage.GetFilteredList(model); if (list == null) { _logger.LogWarning("ReadList return null list"); return null; } _logger.LogInformation("ReadList. Count:{Count}", list.Count); return list; } //метод, отвечающий за изменение баланса счёта public bool ChangeBalance(AccountSearchModel? model, int sum) { //ищем счёт var account = ReadElement(model); if (account == null) { throw new ArgumentNullException("Счёт не найден", nameof(account)); } //проверяем возможность операции снятия (sum может быть отрицательной) if (sum + account.Balance < 0) { return false; } //обновляем балланс счёта _accountStorage.Update(new AccountBindingModel { Id = account.Id, Balance = account.Balance + sum }); return true; } public bool Create(AccountBindingModel model) { CheckModel(model); if (_accountStorage.Insert(model) == null) { _logger.LogWarning("Insert operation failed"); return false; } return true; } public bool Update(AccountBindingModel model) { CheckModel(model); if (_accountStorage.Update(model) == null) { _logger.LogWarning("Update operation failed"); return false; } return true; } public bool Delete(AccountBindingModel model) { CheckModel(model, false); _logger.LogInformation("Delete. Id:{Id}", model.Id); if (_accountStorage.Delete(model) == null) { _logger.LogWarning("Delete operation failed"); return false; } return true; } public List GetMonthInfo(int AccountId) { Dictionary<(int, int), int> cashWithdrawals = _cashWithdrawalLogic.ReadList(new CashWithdrawalSearchModel() { AccountId = AccountId, }).Where(x => x.DebitingStatus == StatusEnum.Закрыта ).GroupBy(x => new { x.DateOperation.Month, x.DateOperation.Year }) .Select(x => new { x.Key.Month, x.Key.Year, Sum = x.Select(y => y.Sum).Sum() }).ToDictionary(x => (x.Month, x.Year), x => (x.Sum)); Dictionary<(int, int), int> moneyTransfers = _moneyTransferLogic.ReadList(new MoneyTransferSearchModel() { AccountPayeeId = AccountId, }).GroupBy(x => new { x.DateOperation.Month, x.DateOperation.Year }) .Select(x => new { x.Key.Month, x.Key.Year, Sum = x.Select(y => y.Sum).Sum() }).ToDictionary(x => (x.Month, x.Year), x => (x.Sum)); Dictionary<(int, int), int> moneyTransfersDebiting = _moneyTransferLogic.ReadList(new MoneyTransferSearchModel() { AccountSenderId = AccountId, }).GroupBy(x => new { x.DateOperation.Month, x.DateOperation.Year }) .Select(x => new { x.Key.Month, x.Key.Year, Sum = x.Select(y => y.Sum).Sum() }).ToDictionary(x => (x.Month, x.Year), x => (x.Sum)); List result = new(); int sum = 0; foreach (var key in cashWithdrawals.Keys.Union(moneyTransfers.Keys).Union(moneyTransfers.Keys).OrderBy(x => x.Item1 * 12 + x.Item2)) { if (cashWithdrawals.ContainsKey(key)) sum += cashWithdrawals.GetValueOrDefault(key); if (moneyTransfers.ContainsKey(key)) sum += moneyTransfers.GetValueOrDefault(key); if (moneyTransfers.ContainsKey(key)) sum -= moneyTransfersDebiting.GetValueOrDefault(key); result.Add(new CashierDiagramElementsViewModel() { Name = Enum.GetName(typeof(Months), key.Item1) + " " + key.Item2.ToString(), Value = sum }); } return result; } //проверка входного аргумента для методов Insert, Update и Delete private void CheckModel(AccountBindingModel model, bool withParams = true) { if (model == null) { throw new ArgumentNullException(nameof(model)); } //так как при удалении передаём как параметр false if (!withParams) { return; } //проверка на наличие номера счёта if (string.IsNullOrEmpty(model.AccountNumber)) { throw new ArgumentNullException("Отсутствие номера у счёта", nameof(model.AccountNumber)); } //проверка на наличие id владельца if (model.CashierId < 0) { throw new ArgumentNullException("Некорректный Id владельца счёта", nameof(model.CashierId)); } //проверка на наличие id кассира, создавшего счёт if (model.CashierId < 0) { throw new ArgumentNullException("Некорректный Id кассира, открывшего счёт", nameof(model.CashierId)); } //проверка на наличие пароля счёта if (string.IsNullOrEmpty(model.PasswordAccount) ) { throw new ArgumentNullException("Некорректный пароль счёта", nameof(model.PasswordAccount)); } if (model.Balance < 0) { throw new ArgumentNullException("Изначальный баланс аккаунта не может быть < 0", nameof(model.Balance)); } //проверка на корректную дату открытия счёта if (model.DateOpen > DateTime.Now) { throw new ArgumentNullException("Дата открытия счёта не может быть ранее текущей", nameof(model.DateOpen)); } _logger.LogInformation("Account. AccountNumber:{AccountNumber}. PasswordAccount:{PasswordAccount}. ClientId:{ClientId}. " + "CashierId:{CashierId}. DateOpen:{DateOpen}. Id:{Id}", model.AccountNumber, model.PasswordAccount, model.ClientId, model.CashierId, model.DateOpen, model.Id); //для проверка на наличие такого же счёта var element = _accountStorage.GetElement(new AccountSearchModel { AccountNumber = model.AccountNumber, }); //если элемент найден и его Id не совпадает с Id переданного объекта if (element != null && element.Id != model.Id) { throw new InvalidOperationException("Счёт с таким номером уже существует"); } } } }