public async Task <DalResult> BuyFromOfferAsync(int buyerid, long quantity, OfferEntity offer, bool oldestFirst) { if (buyerid <= 0) { return(new(DalErrorCode.Invalid, new("Buyer id is invalid"))); } if (quantity == 0) { return(new(DalErrorCode.Invalid, new("Quantity must be greater than zero"))); } if (offer is null) { return(new(DalErrorCode.Invalid, new ArgumentNullException(nameof(offer)))); } if (offer.UserId <= 0) { return(new(DalErrorCode.Invalid, new Exception("Seller id in offer is invalid"))); } var bean = await _beanRepository.ReadAsync(offer.BeanId); if (bean is null) { return(new(DalErrorCode.NotFound, new Exception($"No bean with the id {offer.BeanId} was found"))); } var buyer = await _userRepository.ReadAsync(buyerid); if (buyer is null) { return(new(DalErrorCode.NotFound, new($"No user with the id {buyerid} was found"))); } if (buyer.Balance < quantity * offer.Price) { return(new(DalErrorCode.NSF, new("Buyer does not have sufficient funds"))); } var seller = await _userRepository.ReadAsync(offer.UserId); if (seller is null) { return(new(DalErrorCode.NotFound, new($"No user with the id {offer.User} was found"))); } var beansHeld = await _holdingRepository.BeansHeldByUserAndBeanAsync(offer.UserId, offer.BeanId); if (quantity > beansHeld) { return(new(DalErrorCode.NSF, new("Seller has insufficient beans"))); } var holdings = await _holdingRepository.GetHoldingsAsync(oldestFirst, offer.UserId, offer.BeanId, quantity); if (holdings.Length == 0) { return(new(DalErrorCode.NotFound, new("Unable to locate holdings to satisfy sale"))); } using var conn = new SqlConnection(ConnectionString); await conn.OpenAsync(); using var transaction = await conn.BeginTransactionAsync(); try { var profit = 0M; long satisfied = 0; var ix = 0; while (ix < holdings.Length - 1) { var holding = await _holdingRepository.ReadAsync(holdings[ix]); if (holding is null) { await transaction.RollbackAsync(); return(new(DalErrorCode.NotFound, new($"No holding with the id {holdings[ix]} was found"))); } var sale = new SaleEntity { Id = 0, UserId = seller.Id, BeanId = bean.Id, PurchaseDate = holding.PurchaseDate, SaleDate = DateTime.UtcNow, CostBasis = holding.Price, Quantity = holding.Quantity, SalePrice = offer.Price, Bean = null }; var insresult = await conn.InsertAsync(sale, transaction : transaction); profit += holding.Quantity * offer.Price; satisfied += holding.Quantity; await conn.DeleteAsync(holding, transaction : transaction); ix++; } var lastHolding = await _holdingRepository.ReadAsync(holdings[^ 1]);
public async Task <long> BeansHeldByUserAndBeanAsync(int userid, int beanid) => await _holdingRepository.BeansHeldByUserAndBeanAsync(userid, beanid);