/// <summary> /// Processes a payment after validating few cases. CHECKS FOR INNVALID CREDIT CARD AND VALID DATE ARE DONE /// AT THE CONTROLLER/DTO LEVEL. /// </summary> /// <param name="payment">The payment to be processed</param> /// <returns>A task that resolves to a string.</returns> public async Task <string> ProcessAsync(PaymentDto payment) { if (payment == null) { throw new ArgumentNullException(nameof(payment)); } if (payment.Amount <= 0) { throw new ArgumentException($"£{nameof(payment.Amount)} is not a valid amount"); } if (payment.Amount >= 20 && payment.Amount < 21) { throw new Exception($"Cannot process payment between £20.01 to £20.99"); } PaymentState paymentState = null; string result = ""; try { //Insert into Payment Entity var newPayment = _mapper.Map <Payment>(payment); await _paymentRepo.InsertAsync(newPayment); paymentState = new PaymentState { PaymentId = newPayment.Id, State = nameof(PaymentStateEnum.PENDING) }; await _paymentStateRepo.InsertAsync(paymentState); //proceed to process payment... if (payment.Amount < 20) { //use ICheapPaymentGateway to process the payment. result = _cheapPaymentGateway.Process(payment); } else if (payment.Amount >= 21 && payment.Amount <= 500) { //use IExpensivePaymentGateway to process the payment. result = await _expensivePaymentGateway.ProcessAsync(payment); } else { //use IPremiumPaymentGateway to process the payment. result = await _premiumPaymentGateway.ProcessAsync(payment); } return(result); } finally { //paymentState could be null if the repository method never runs or //it threw an unexpected exception. //if that's the case, no need for cleanup. if (paymentState != null) { if (result.Length > 1) { //there was no error //update Payment State Entity to processed. paymentState.State = nameof(PaymentStateEnum.PROCESSESD); } else { // update Payment State Entity paymentState.State = nameof(PaymentStateEnum.FAILED); } await _paymentStateRepo.UpdateAsync(paymentState); } } }