public async Task <ActionResult <TransactionViewModel> > CreateIntent(CreateIntentBody createIntentBody) { try { Logger.LogInformation("Creating intent of {Amount} by {User} for {Event}", createIntentBody.Amount, createIntentBody.UserId, createIntentBody.EventId); var result = await TransactionService.CreateIntent(createIntentBody); return(result); } catch (Exception e) { Logger.LogError(e.ToString()); return(BadRequest(e)); } }
/// <inheritdoc /> /// <exception cref="UserNotFoundException">Thrown when the user is not found</exception> /// <exception cref="Exception">Thrown if error</exception> /// <exception cref="EventNotFoundException">Thrown if the event is not found</exception> public async Task <TransactionViewModel> CreateIntent(CreateIntentBody createIntentBody) { var user = await ApplicationContext.Users .Include(x => x.PaymentMethods) .FirstOrDefaultAsync(x => x.Id == createIntentBody.UserId); var e = await ApplicationContext.Events.AsSplitQuery() .Include(x => x.Promos) .Include(x => x.Host) .Include(x => x.Tickets) .Include(x => x.Transactions) .FirstOrDefaultAsync(x => x.Id == createIntentBody.EventId); if (user == null) { Logger.LogInformation("User was not found"); throw new UserNotFoundException(); } // if the user doesn't have a customer id or payment method throw exception if (user.StripeCustomerId == null || !user.PaymentMethods.Any()) { throw new Exception("Not enough stripe info"); } if (e == null) { Logger.LogInformation("Event was not found"); throw new EventNotFoundException(); } // if the host of the event hasn't setup a bank account throw exception if (e.Host.StripeAccountId == null) { throw new Exception("The host doesn't have enough stripe info"); } // gets a promo that's currently active var promo = e.Promos.FirstOrDefault(x => x.Active && x.Start < DateTime.Now && DateTime.Now < x.End); if (promo != null) { // applies discount to price createIntentBody.Amount -= (createIntentBody.Amount * promo.Discount / 100); Logger.LogInformation("Found promo for event"); } // Stipee api create intent options var options = new PaymentIntentCreateOptions() { Amount = createIntentBody.Amount, Currency = "gbp", OnBehalfOf = e.Host.StripeAccountId, Customer = user.StripeCustomerId, ConfirmationMethod = "manual", ApplicationFeeAmount = 10, TransferData = new PaymentIntentTransferDataOptions() { Destination = e.Host.StripeAccountId }, PaymentMethodTypes = new List <string> { "card" }, Metadata = new Dictionary <string, string> { { "EventId", e.Id.ToString() }, { "PromoId", promo?.Id.ToString() } }, }; var service = new PaymentIntentService(); try { var ticket = e.Tickets.FirstOrDefault(x => x.Available); // if there's no tickets left then throw exception if (ticket == null) { throw new Exception("Out of tickets"); } // Sends request to Strip api to create intent var intent = service.Create(options); e.TicketsLeft = e.Tickets.Count(x => x.Available) - 1; ticket.User = user; ticket.Available = false; // records transaction using Stripe response Transaction transaction = new Transaction() { Amount = intent.Amount, User = user, Paid = intent.Status == "succeeded", StripeIntentId = intent.Id, Start = DateTime.Now, Updated = DateTime.Now, Status = Enum.Parse <PaymentStatus>(intent.Status, true), Ticket = ticket, Event = e, ClientSecret = intent.ClientSecret, PromoId = promo?.Id }; await ApplicationContext.Transactions.AddAsync(transaction); await ApplicationContext.SaveChangesAsync(); // start the intent timout method CheckOnIntent(transaction.StripeIntentId, ticket.Id, e.Id); return(Mapper.Map <TransactionViewModel>(transaction)); } catch (Exception exception) { Console.WriteLine(exception); throw; } }