230 lines
7.5 KiB
C#
230 lines
7.5 KiB
C#
namespace AAIntegration.SimmonsBank.API.Services;
|
|
|
|
using AutoMapper;
|
|
using BCrypt.Net;
|
|
using AAIntegration.SimmonsBank.API.Entities;
|
|
using AAIntegration.SimmonsBank.API.Config;
|
|
using AAIntegration.SimmonsBank.API.Models.Transactions;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Internal;
|
|
using System.Collections.Immutable;
|
|
|
|
public interface ITransactionService
|
|
{
|
|
IEnumerable<Transaction> GetAll(int ownerId);
|
|
Transaction GetById(int id, int ownerId);
|
|
IEnumerable<Transaction> BulkCreate(List<TransactionCreate> model, int ownerId);
|
|
Transaction Create(TransactionCreate model, int ownerId, bool errorOnFail = true);
|
|
void Update(int id, TransactionUpdateRequest model, int ownerId);
|
|
void Delete(int id, int ownerId);
|
|
}
|
|
|
|
public class TransactionService : ITransactionService
|
|
{
|
|
private DataContext _context;
|
|
private readonly IMapper _mapper;
|
|
private readonly ILogger<TransactionService> _logger;
|
|
|
|
public TransactionService(
|
|
DataContext context,
|
|
IMapper mapper,
|
|
ILogger<TransactionService> logger)
|
|
{
|
|
_context = context;
|
|
_mapper = mapper;
|
|
_logger = logger;
|
|
}
|
|
|
|
public IEnumerable<Transaction> GetAll(int ownerId)
|
|
{
|
|
return _context.Transactions
|
|
.Include(t => t.DebitAccount)
|
|
.Include(t => t.CreditAccount)
|
|
.Include(t => t.Owner)
|
|
.Where(x => x.Owner.Id == ownerId);
|
|
}
|
|
|
|
public Transaction GetById(int id, int ownerId)
|
|
{
|
|
return getTransaction(id, ownerId);
|
|
}
|
|
|
|
private Account prepareAccount(int? accountId)
|
|
{
|
|
if (accountId == null || accountId.Value == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
Account account = _context.Accounts.Find(accountId.Value);
|
|
if (account == null)
|
|
throw new AppException("Could not find account with ID of '" + accountId.Value + "'.");
|
|
|
|
return account;
|
|
}
|
|
|
|
public IEnumerable<Transaction> BulkCreate(List<TransactionCreate> model, int ownerId)
|
|
{
|
|
List<Transaction> transactions = new List<Transaction>();
|
|
|
|
foreach (TransactionCreate tr in model)
|
|
{
|
|
var tran = this.Create(tr, ownerId, false);
|
|
if (tran != null)
|
|
transactions.Add(tran);
|
|
}
|
|
|
|
return transactions;
|
|
}
|
|
|
|
public Transaction Create(TransactionCreate model, int ownerId, bool errorOnFail = true)
|
|
{
|
|
Transaction transaction = new Transaction {
|
|
Description = model.Description,
|
|
Date = model.Date.Date.ToUniversalTime(),
|
|
CreatedOn = DateTime.UtcNow,
|
|
UpdatedOn = DateTime.UtcNow,
|
|
ExternalId = string.IsNullOrWhiteSpace(model.ExternalId) ? "" : model.ExternalId,
|
|
DebitAccount = prepareAccount(model.DebitAccount),
|
|
CreditAccount = prepareAccount(model.CreditAccount),
|
|
Amount = Convert.ToDecimal(model.Amount),
|
|
Owner = this.getOwner(ownerId),
|
|
IsPending = model.IsPending
|
|
};
|
|
|
|
if (this.ValidateTransaction(transaction, ownerId, errorOnFail) == false)
|
|
{
|
|
_logger.LogInformation($"Aborted adding transaction '{transaction.Description}'.");
|
|
return null;
|
|
}
|
|
|
|
// At this point transaction itself is valid
|
|
|
|
_context.Transactions.Add(transaction);
|
|
_context.SaveChanges();
|
|
|
|
_logger.LogInformation("New transaction successfully created.");
|
|
|
|
return transaction;
|
|
}
|
|
|
|
public void Update(int id, TransactionUpdateRequest model, int ownerId)
|
|
{
|
|
Transaction transaction = getTransaction(id, ownerId);
|
|
|
|
// Transaction.Date
|
|
if (model.Date.HasValue)
|
|
transaction.Date = model.Date.Value;
|
|
|
|
// Transaction.ExternalId
|
|
if (model.ExternalId != null)
|
|
transaction.ExternalId = model.ExternalId;
|
|
|
|
// Transaction.Description
|
|
if (model.Description != null)
|
|
transaction.Description = model.Description;
|
|
|
|
// Transaction.DebitAccount
|
|
if (model.DebitAccount.HasValue)
|
|
transaction.DebitAccount = prepareAccount(model.DebitAccount);
|
|
|
|
// Transaction.CreditAccount
|
|
if (model.CreditAccount.HasValue)
|
|
transaction.CreditAccount = prepareAccount(model.CreditAccount.Value);
|
|
|
|
// Transaction.Amount
|
|
if (model.Amount.HasValue)
|
|
transaction.Amount = model.Amount.Value;
|
|
|
|
// Transaction.IsPending
|
|
if (model.IsPending.HasValue)
|
|
transaction.IsPending = model.IsPending.Value;
|
|
|
|
this.ValidateTransaction(transaction, ownerId);
|
|
|
|
transaction.UpdatedOn = DateTime.UtcNow;
|
|
|
|
_context.Transactions.Update(transaction);
|
|
_context.SaveChanges();
|
|
|
|
_logger.LogInformation($"Transaction '{id}' successfully updated.");
|
|
}
|
|
|
|
public void Delete(int id, int ownerId)
|
|
{
|
|
var transaction = getTransaction(id, ownerId);
|
|
_context.Transactions.Remove(transaction);
|
|
_context.SaveChanges();
|
|
}
|
|
|
|
// helpers
|
|
|
|
private bool ErrorOrFalse(bool error, string errorMessage)
|
|
{
|
|
if (error)
|
|
throw new AppException(errorMessage);
|
|
|
|
_logger.LogWarning(errorMessage);
|
|
return false;
|
|
}
|
|
|
|
private bool ValidateTransaction(Transaction transaction, int ownerId, bool errorOnFail = true)
|
|
{
|
|
// There has to be at least 1 specified account
|
|
if (transaction.DebitAccount == null && transaction.CreditAccount == null)
|
|
return ErrorOrFalse(errorOnFail, "There must be an envelope or account chosen for a transaction.");
|
|
|
|
// Accounts cannot be the same
|
|
if (transaction.DebitAccount != null && transaction.CreditAccount != null &&
|
|
transaction.DebitAccount.Id == transaction.CreditAccount.Id)
|
|
return ErrorOrFalse(errorOnFail, "The debit and credit accounts of a transaction cannot be the same.");
|
|
|
|
// Transaction Duplication Check - External ID
|
|
if (!string.IsNullOrWhiteSpace(transaction.ExternalId)
|
|
&& _context.Transactions
|
|
.Include(x => x.Owner)
|
|
.Any(x => x.ExternalId == transaction.ExternalId && x.Owner.Id == ownerId))
|
|
return ErrorOrFalse(errorOnFail, "Transaction with the external ID '" + transaction.ExternalId + "' already exists");
|
|
|
|
// Transaction Duplication Check - All other fields
|
|
/*if (_context.Transactions.Any(x =>
|
|
x.Description == transaction.Description
|
|
&& x.Date == transaction.Date
|
|
&& x.DebitAccount == transaction.DebitAccount
|
|
&& x.CreditAccount == transaction.CreditAccount
|
|
&& x.Amount == transaction.Amount))
|
|
{
|
|
return ErrorOrFalse(errorOnFail, "Transaction with the same fields already exists");
|
|
}*/
|
|
|
|
return true;
|
|
}
|
|
|
|
private Transaction getTransaction(int id, int ownerId)
|
|
{
|
|
var transaction = _context.Transactions
|
|
.Include(t => t.DebitAccount)
|
|
.Include(t => t.CreditAccount)
|
|
.Include(t => t.Owner)
|
|
.FirstOrDefault(t => t.Id == id && t.Owner.Id == ownerId);
|
|
|
|
if (transaction == null)
|
|
throw new KeyNotFoundException("Transaction not found");
|
|
|
|
return transaction;
|
|
}
|
|
|
|
private User getOwner(int ownerId)
|
|
{
|
|
User? owner = _context.Users.Find(ownerId);
|
|
|
|
if (owner == null)
|
|
throw new AppException($"Owner with ID of '{ownerId}' could not be found");
|
|
|
|
return owner;
|
|
}
|
|
} |