private async Task <PaymentStatus> ValidateTransaction(CompletePurchaseDto payment) { var purchase = _context.Purchases.FirstOrDefault(x => x.OrderId == payment.OrderId); if (purchase == null) { throw new ApiException($"The purchase with orderId {payment.OrderId} does not exist", 400); } if (purchase.Completed) { throw new ApiException("The given purchase has already been completed", 400); } var mobilePayPaymentStatus = await _mobilePayService.GetPaymentStatus(payment.OrderId); if (!Equals(Convert.ToDouble(purchase.Price), mobilePayPaymentStatus.OriginalAmount)) { Log.Warning( "Purchase price did not match the withdrawn amount from MobilePay. Possible tampering. Cancel transaction."); await _mobilePayService.CancelPaymentReservation(payment.OrderId); throw new ApiException("The purchase could not be completed. The purchase has been cancelled."); } return(mobilePayPaymentStatus.LatestPaymentStatus); }
public Purchase DeliverProduct(CompletePurchaseDto completeDto, IEnumerable <Claim> claims) { var userId = claims.FirstOrDefault(x => x.Type == Constants.UserId); if (userId == null) { throw new ApiException("The token is invalid!", 401); } var id = int.Parse(userId.Value); var user = _context.Users.Include(x => x.Purchases).FirstOrDefault(x => x.Id == id); if (user == null) { throw new ApiException("The user could not be found"); } var purchase = user.Purchases.FirstOrDefault(x => x.OrderId == completeDto.OrderId); if (purchase == null) { throw new ApiException("Purchase could not be found"); } if (purchase.PurchasedBy.Id != user.Id) { throw new ApiException("You cannot complete a purchase that you did not initiate!", 401); } return(DeliverProductToUser(purchase, user, completeDto.TransactionId)); }
public async Task <ActionResult <MessageResponseDto> > CompletePurchase([FromBody] CompletePurchaseDto dto) { await _purchaseService.CompletePurchase(dto, User.Claims); return(Ok(new MessageResponseDto() { Message = "The purchase was completed with success!" })); }
public async Task <Purchase> CompletePurchase(CompletePurchaseDto dto, IEnumerable <Claim> claims) { Log.Information( $"Trying to complete purchase with orderid: {dto.OrderId} and transactionId: {dto.TransactionId}"); try { //TODO Figure out the purpose of this check, and probably fix it in regard to test environment if (!_mobilePaySettings.MerchantId.Equals("APPDK0000000000")) { var paymentStatus = await ValidateTransaction(dto); switch (paymentStatus) { case PaymentStatus.Captured: { Log.Information( $"Validating transaction with orderId: {dto.OrderId} and transactionId: {dto.TransactionId} succeeded!"); break; } case PaymentStatus.Reserved: { var captureResponse = await _mobilePayService.CapturePayment(dto.OrderId); Log.Information( $"Validating transaction with orderId: {dto.OrderId} and transactionId: {captureResponse.TransactionId} succeeded!"); break; } default: { Log.Warning($"Validating transaction at MobilePay failed with status: {paymentStatus}"); throw new ApiException("The purchase could not be completed", 400); } } } } catch (MobilePayException e) { Log.Warning( $"Complete purchase failed with error message: {e.Message} and status code: {e.GetHttpStatusCode()}"); throw new ApiException("Failed to complete purchase using MobilePay", 400); } var purchase = DeliverProduct(dto, claims); await SendInvoiceEmailAsync(purchase); Log.Information( $"Completed purchase with success! OrderId: {dto.OrderId} transactionId: {dto.TransactionId}"); return(purchase); }