public TestOrderBuilder WithPayments()
		{
			var payments = new Payment[] {
											 new CreditCardPayment {PaymentMethodId = "CreditCard", PaymentType = PaymentType.CreditCard.GetHashCode(), Status = PaymentStatus.Pending.ToString(), CreditCardCustomerName="John Doe", PaymentMethodName="MasterCard", ValidationCode="RE21321-21", Amount=32.53m, CreditCardExpirationMonth = 12, CreditCardExpirationYear = 2014, CreditCardNumber = "4007000000027", CreditCardType = "VISA", CreditCardSecurityCode = "123", BillingAddressId = _order.OrderForms[0].BillingAddressId},
											 new CashCardPayment { PaymentMethodId = "Phone", PaymentType = PaymentType.CashCard.GetHashCode(), Status = PaymentStatus.Pending.ToString(), PaymentMethodName="Visa", ValidationCode="RE6211-44", Amount=55.73m },
											 new InvoicePayment { PaymentMethodId = "Phone", PaymentType = PaymentType.Invoice.GetHashCode(), Status = PaymentStatus.Pending.ToString(), PaymentMethodName="Bank transaction", ValidationCode="BE3-21", Amount=774.53m }
										   };
			foreach (var payment in payments)
			{
				_order.OrderForms[0].Payments.Add(payment);
			}

			return this;
		}
		/// <summary>
		/// Processes the payment. Can be used for both positive and negative transactions.
		/// </summary>
		/// <param name="payment">The payment.</param>
		/// <param name="message">The message.</param>
		/// <returns></returns>
		public override bool ProcessPayment(Payment payment, ref string message)
		{
			var info = payment as CreditCardPayment;

			if (ReferenceEquals(info, null))
			{
				payment.Status = PaymentStatus.Failed.ToString();
				message = "ICharge gateway supports only CreditCardPayment";
				return false;
			}
			var transactionType = (TransactionType)Enum.Parse(typeof(TransactionType), info.TransactionType);
			payment.Status = PaymentStatus.Processing.ToString();
			var invoiceNr = info.OrderForm.OrderGroupId;
			_icharge = new Icharge
			{
				InvoiceNumber = invoiceNr,
				TransactionId = invoiceNr
			};

			try
			{
				_icharge.MerchantLogin = Settings["MerchantLogin"];
				_icharge.MerchantPassword = Settings["MerchantPassword"];
				_icharge.Gateway = (IchargeGateways)Enum.Parse(typeof(IchargeGateways), Settings["Gateway"]);
				bool isTestMode;
				if (Settings.ContainsKey("TestMode") && bool.TryParse(Settings["TestMode"], out isTestMode) && isTestMode)
				{
					_icharge.TestMode = true;
				}
			}
			catch
			{
				payment.Status = PaymentStatus.Failed.ToString();
				message = "ICharge gateway is not configured properly";
				return false;
			}

			if (!String.IsNullOrEmpty(Settings["GatewayURL"]))
			{
				_icharge.GatewayURL = Settings["GatewayURL"];
			}

			var transactionId = payment.ValidationCode;
			_icharge.AuthCode = payment.AuthorizationCode;

			_icharge.Card.ExpMonth = info.CreditCardExpirationMonth;
			_icharge.Card.ExpYear = info.CreditCardExpirationYear;
			_icharge.Card.Number = info.CreditCardNumber ?? "";
			_icharge.Card.CVVData = info.CreditCardSecurityCode ?? "";

			// Find the address
			var address = info.OrderForm.OrderGroup.OrderAddresses
				.FirstOrDefault(a => String.Compare(a.OrderAddressId, info.BillingAddressId, StringComparison.OrdinalIgnoreCase) == 0);

			if (address != null)
			{
				_icharge.Customer.Address = address.Line1;
				_icharge.Customer.City = address.City;
				_icharge.Customer.Country = address.CountryCode;
				_icharge.Customer.Email = address.Email;
				_icharge.Customer.FirstName = address.FirstName;
				_icharge.Customer.LastName = address.LastName;
				_icharge.Customer.Phone = address.DaytimePhoneNumber;
				_icharge.Customer.State = address.StateProvince;
				_icharge.Customer.Zip = address.PostalCode;
			}

			var transactionAmount = (double)info.Amount;

			//The following gateways require the TransactionAmount to be represented as cents without a decimal point. 
			//For example, a dollar value of "1.00" would equate to "100" for these gateways.

			if (_icharge.Gateway == IchargeGateways.gw3DSI ||
				_icharge.Gateway == IchargeGateways.gwTrustCommerce ||
				_icharge.Gateway == IchargeGateways.gwPayFuse ||
				_icharge.Gateway == IchargeGateways.gwOrbital ||
				_icharge.Gateway == IchargeGateways.gwOgone ||
				//_icharge.Gateway == IchargeGateways.gwOptimal ||
				_icharge.Gateway == IchargeGateways.gwWorldPayXML ||
				_icharge.Gateway == IchargeGateways.gwProPay ||
				_icharge.Gateway == IchargeGateways.gwLitle ||
				_icharge.Gateway == IchargeGateways.gwJetPay ||
				_icharge.Gateway == IchargeGateways.gwHSBC ||
				_icharge.Gateway == IchargeGateways.gwAdyen ||
				_icharge.Gateway == IchargeGateways.gwBarclay ||
				_icharge.Gateway == IchargeGateways.gwCyberbit ||
				_icharge.Gateway == IchargeGateways.gwGoToBilling ||
				_icharge.Gateway == IchargeGateways.gwGlobalIris)
			{
				_icharge.TransactionAmount = (transactionAmount * 100).ToString("F0", CultureInfo.InvariantCulture);
			}
			else
			{
				_icharge.TransactionAmount = transactionAmount.ToString("F2", CultureInfo.InvariantCulture);
			}
			try
			{
				switch (_icharge.Gateway)
				{
					case IchargeGateways.gwAuthorizeNet:
						if (_icharge.TestMode)
						{
							_icharge.AddSpecialField("x_tran_key", _icharge.MerchantPassword);
						}
						AddConfigField("AIMHashSecret");
						break;
					case IchargeGateways.gwPlanetPayment:
					case IchargeGateways.gwMPCS:
					case IchargeGateways.gwRTWare:
					case IchargeGateways.gwECX:
						//AddSpecialField(info, " x_tran_key");
						AddConfigField("AIMHashSecret");
						break;
                    //case IchargeGateways.gwViaKlix:
                    //    AddSpecialField("ssl_user_id");
                    //    break;
					case IchargeGateways.gwBankOfAmerica:
						_icharge.AddSpecialField("ecom_payment_card_name", info.CreditCardCustomerName);
						AddConfigField("referer");
						break;
					case IchargeGateways.gwInnovative:
						AddSpecialField("test_override_errors");
						break;
					case IchargeGateways.gwTrustCommerce:
					case IchargeGateways.gw3DSI:
						_icharge.TransactionAmount = _icharge.TransactionAmount.Replace(".", "");
						break;
					case IchargeGateways.gwPayFuse:
						AddConfigField("MerchantAlias");
						_icharge.TransactionAmount = _icharge.TransactionAmount.Replace(".", "");
						break;
					case IchargeGateways.gwYourPay:
					case IchargeGateways.gwFirstData:
					case IchargeGateways.gwLinkPoint:
						_icharge.SSLCert.Store = Settings["SSLCertStore"];
						_icharge.SSLCert.Subject = Settings["SSLCertSubject"];
						_icharge.SSLCert.Encoded = Settings["SSLCertEncoded"];
						break;
					case IchargeGateways.gwPRIGate:
						_icharge.MerchantPassword = Settings["MerchantPassword"];
						break;
                    //case IchargeGateways.gwProtx:
                    //    AddSpecialField("RelatedSecurityKey");
                    //    AddSpecialField("RelatedVendorTXCode");
                    //    AddSpecialField("RelatedTXAuthNo");
                    //    break;
                    //case IchargeGateways.gwOptimal:
                    //    _icharge.MerchantPassword = Settings["MerchantPassword"];
                    //    AddSpecialField("account");
                    //    break;
                    //case IchargeGateways.gwEFSNet:
                    //    _icharge.AddSpecialField("OriginalTransactionAmount", _icharge.TransactionAmount);
                    //    break;
                    //case IchargeGateways.gwPayStream:
                    //    AddSpecialField("CustomerID");
                    //    AddSpecialField("ZoneID");
                    //    AddSpecialField("Username");
                    //    break;
					case IchargeGateways.gwPayFlowPro:
						// for testing purpose uncomment line below   
						//_icharge.GatewayURL = "test-payflow.verisign.com";
						_icharge.AddSpecialField("user", Settings["MerchantLogin"]);
						break;
					case IchargeGateways.gwMoneris:
						// for testing purpose uncomment line below
						//_icharge.GatewayURL = "https://esqa.moneris.com/HPPDP/index.php";
						_icharge.TransactionAmount = transactionAmount.ToString("##0.00");
						break;
					case IchargeGateways.gwBeanstream:
						break;
				}

				_icharge.TransactionDesc = String.Format("Order Number {0}", _icharge.TransactionId);
				_icharge.OnSSLServerAuthentication += PaymentGateway_OnSSLAuthentication;


				switch (transactionType)
				{
					case TransactionType.Authorization:
						_icharge.AuthOnly();
						break;
					case TransactionType.Capture:
						_icharge.Capture(transactionId, _icharge.TransactionAmount);
						break;
					case TransactionType.Credit:
                        _icharge.Refund(transactionId, _icharge.TransactionAmount);
						break;
					case TransactionType.Sale:
						_icharge.Sale();
						break;
					case TransactionType.Void:
						_icharge.VoidTransaction(transactionId);
						break;
				}

				//_icharge.Sale();

				var approved = _icharge.Response.Approved;
				if (!approved)
				{
					payment.Status = PaymentStatus.Denied.ToString();
					message = "Transaction Declined: " + _icharge.Response.Text;
					return false;
				}

			}
			catch (Exception ex)
			{
				payment.Status = PaymentStatus.Failed.ToString();
				throw new ApplicationException(ex.Message);
			}

			info.StatusCode = _icharge.Response.Code;
			info.StatusDesc = _icharge.Response.Text;
			info.ValidationCode = _icharge.Response.TransactionId;
            info.AuthorizationCode = _icharge.Response.ApprovalCode;

			// transaction is marked as completed every time the payment operation succeeds even if it is void transaction type
			if (_icharge.Response.Approved)
			{
				payment.Status = PaymentStatus.Completed.ToString();
			}

			return true;
		}
		public MockOrderBuilder WithPayments(List<PaymentMethod> paymentMethods)
		{
			var pmCreditCard = paymentMethods.First(x => x.Name == "CreditCard");

			var payments = new Payment[] {
											 new CreditCardPayment
												 { 
												 PaymentType = PaymentType.CreditCard.GetHashCode(),
												 CreditCardCustomerName="John Doe", 
												 CreditCardExpirationMonth = 1, 
												 CreditCardExpirationYear = 2016, 
												 CreditCardNumber = "4007000000027",
												 CreditCardType = "VISA",
												 CreditCardSecurityCode = "123",
												 AuthorizationCode = "0",
												 PaymentMethodId  = pmCreditCard.PaymentMethodId, 
												 PaymentMethodName = pmCreditCard.Description, 
												 ValidationCode="000000", 
												 Amount=32.53m,
												 TransactionType = TransactionType.Sale.ToString(),
												 Status = PaymentStatus.Completed.ToString()
											 },
											new CashCardPayment
												{
													PaymentType = PaymentType.CashCard.GetHashCode(), 
													PaymentMethodName="Visa", 
													ValidationCode="RE6211-44", 
													Amount=55.73m,
													TransactionType = TransactionType.Sale.ToString(),
													Status = PaymentStatus.Failed.ToString()
												},
											 new InvoicePayment
												 {
													 PaymentType = PaymentType.Invoice.GetHashCode(), 
													 PaymentMethodName="Credit", 
													 ValidationCode="BE3-21", 
													 Amount=4.53m,
													 TransactionType = TransactionType.Credit.ToString(),
													 Status = PaymentStatus.Completed.ToString()
												 }
										   };
			foreach (var payment in payments)
			{
				payment.OrderFormId = _order.OrderForms[0].OrderFormId;
				_order.OrderForms[0].Payments.Add(payment);
			}

			return this;
		}
        /// <summary>
        /// Processes the payment. Can be used for both positive and negative transactions.
        /// </summary>
        /// <param name="payment">The payment.</param>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        public override bool ProcessPayment(Payment payment, ref string message)
        {
            try
            {
                payment.Status = PaymentStatus.Processing.ToString();

                //ContractId - used as paypal PayerID
                var payerId = payment.ContractId;
                //ValidationCode - used as paypal token
                var token = payment.AuthorizationCode;

                if (string.IsNullOrEmpty(payerId) || string.IsNullOrEmpty(token))
                {
                    return false;
                }

                // Create the PayPalAPIInterfaceServiceService service object to make the API call
                var service = new PayPalAPIInterfaceServiceService((Dictionary<string, string>)Settings);

                var getECWrapper = new GetExpressCheckoutDetailsReq();
                getECWrapper.GetExpressCheckoutDetailsRequest = new GetExpressCheckoutDetailsRequestType(token);
                var getECResponse = service.GetExpressCheckoutDetails(getECWrapper);

                var request = new DoExpressCheckoutPaymentRequestType();
                var requestDetails = new DoExpressCheckoutPaymentRequestDetailsType();
                request.DoExpressCheckoutPaymentRequestDetails = requestDetails;

                requestDetails.PaymentDetails = getECResponse.GetExpressCheckoutDetailsResponseDetails.PaymentDetails;
                requestDetails.Token = token;
                requestDetails.PayerID = payerId;
                requestDetails.PaymentAction = PaymentActionCodeType.SALE;

                // Invoke the API
                var wrapper = new DoExpressCheckoutPaymentReq();
                wrapper.DoExpressCheckoutPaymentRequest = request;

                var doECResponse = service.DoExpressCheckoutPayment(wrapper);

                if (doECResponse.Ack.Equals(AckCodeType.FAILURE) || (doECResponse.Errors != null && doECResponse.Errors.Count > 0))
                {
                    return false;
                }
                else
                {
                    switch (doECResponse.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].PaymentStatus)
                    {
                        case PaymentStatusCodeType.COMPLETED:
                            payment.Status = PaymentStatus.Completed.ToString();
                            break;
                        case PaymentStatusCodeType.INPROGRESS:
                            payment.Status = PaymentStatus.Processing.ToString();
                            break;
                        case PaymentStatusCodeType.DENIED:
                            payment.Status = PaymentStatus.Denied.ToString();
                            break;
                        case PaymentStatusCodeType.FAILED:
                            payment.Status = PaymentStatus.Failed.ToString();
                            break;
                        default:
                            payment.Status =
                                doECResponse.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].PaymentStatus
                                    .ToString();
                            break;
                    }
                }

            }
            catch (Exception ex)
            {
                message = ex.Message;
                return false;
            }


            return true;
        }
		/// <summary>
		/// Processes the payment. Can be used for both positive and negative transactions.
		/// </summary>
		/// <param name="payment">The payment.</param>
		/// <param name="message">The message.</param>
		/// <returns></returns>
		public override bool ProcessPayment(Payment payment, ref string message)
		{
			payment.Status = PaymentStatus.Processing.ToString();
			return true;
		}
		public CreatePaymentResult CreatePayment(Payment payment)
		{
			var result = new CreatePaymentResult { TransactionId = payment.AuthorizationCode };

			if (string.IsNullOrEmpty(payment.TransactionType))
			{
				result.Message = "Transaction type is required";
				return result;
			}

			var orderForm = _orderRepository.Orders.SelectMany(o => o.OrderForms)
				.ExpandAll().Expand("OrderGroup/OrderAddresses")
				.First(of => of.OrderFormId == payment.OrderFormId);

			var transactionType = (TransactionType)Enum.Parse(typeof(TransactionType), payment.TransactionType);

			if (transactionType == TransactionType.Credit)
			{
				var totalSales = orderForm.Payments.Where(
					p => p.Status == PaymentStatus.Completed.ToString() &&
                         (p.TransactionType == TransactionType.Sale.ToString() 
                         || p.TransactionType == TransactionType.Capture.ToString())).Sum(p => p.Amount);

				if (payment.Amount > totalSales)
				{
					result.Message = string.Format("Payment amount exceeds total sales amount {0} {1}", totalSales,
					                               orderForm.OrderGroup.BillingCurrency);
					return result;
				}
			}

			var paymentMethod = _paymentMethodRepository.PaymentMethods
									.Expand("PaymentGateway")
									.Expand("PaymentMethodPropertyValues")
									.ExpandAll()
									.FirstOrDefault(p => p.PaymentMethodId.Equals(payment.PaymentMethodId));

			if (paymentMethod == null)
			{
				result.Message = String.Format("Specified payment method \"{0}\" has not been defined.", payment.PaymentMethodId);
				return result;
			}


			if ((((TransactionType)paymentMethod.PaymentGateway.SupportedTransactionTypes) & transactionType) != transactionType)
			{
				result.Message = String.Format("Transaction type {0} is not supported by payment gateway", payment.TransactionType);
				return result;
			}

			Debug.WriteLine(String.Format("Getting the type \"{0}\".", paymentMethod.PaymentGateway.ClassType));
			var type = Type.GetType(paymentMethod.PaymentGateway.ClassType);
			if (type == null)
			{
				result.Message = String.Format("Specified payment method class \"{0}\" can not be created.", paymentMethod.PaymentGateway.ClassType);
				return result;
			}

			var provider = (IPaymentGateway)Activator.CreateInstance(type);
			provider.Settings = CreateSettings(paymentMethod);

			payment.Status = PaymentStatus.Pending.ToString();

			var message = "";
            Debug.WriteLine(String.Format("Processing the payment."));

			try
			{
				//Save changes before process
				
				payment.OrderForm = null;
				orderForm.Payments.Add(payment);
				_orderRepository.UnitOfWork.Commit();

				payment.OrderForm = orderForm;

				result.IsSuccess = provider.ProcessPayment(payment, ref message);
				result.Message = message;
				result.TransactionId = payment.AuthorizationCode;

                Debug.WriteLine(String.Format("Payment processed."));
			}
			catch (Exception ex)
			{
				result.Message = ex.Message;
				payment.Status = PaymentStatus.Failed.ToString();
				Trace.TraceError(ex.Message);
			}
			finally
			{
				PostProcessPayment(payment);
				_orderRepository.Update(payment);
				_orderRepository.UnitOfWork.Commit();
			}
			return result;
		}
		/// <summary>
		/// Post process the payment. Decrypts the data if needed.
		/// </summary>
		private void PostProcessPayment(Payment payment)
		{
			// We only care about credit cards here, all other payment types should be encrypted by default
			var cardPayment = payment as CreditCardPayment;
			var store = _storeRepository.Stores.FirstOrDefault(s => s.StoreId == payment.OrderForm.OrderGroup.StoreId);
			if (cardPayment != null)
			{
				if (store != null)
				{
					switch ((CreditCardSavePolicy)store.CreditCardSavePolicy)
					{
						case CreditCardSavePolicy.Full:
							//leave full number
							break;
						case CreditCardSavePolicy.LastFourDigits:
							var ccNumber = cardPayment.CreditCardNumber;
							if (!String.IsNullOrEmpty(ccNumber) && ccNumber.Length > 4)
							{
								ccNumber = ccNumber.Substring(ccNumber.Length - 4);
								cardPayment.CreditCardNumber = ccNumber;
							}
							break;
						case CreditCardSavePolicy.None:
							cardPayment.CreditCardNumber = string.Empty;
							break;
					}
				}
				else
				{
					cardPayment.CreditCardNumber = string.Empty;
				}

				// Always remove pin
				cardPayment.CreditCardSecurityCode = String.Empty;
			}
		}
	    /// <summary>
        /// Processes the payment. Can be used for both positive and negative transactions.
        /// </summary>
        /// <param name="payment">The payment.</param>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        public abstract bool ProcessPayment(Payment payment, ref string message);
        public override bool ProcessPayment(Payment payment, ref string message)
        {
            var info = payment as CreditCardPayment;

            if (ReferenceEquals(info, null))
            {
                payment.Status = PaymentStatus.Failed.ToString();
                message = "AuthorizeNet gateway supports only CreditCardPayment";
                return false;
            }

            string[] validateSettings = { "MerchantLogin", "MerchantPassword" };

            foreach (var validateSetting in validateSettings)
            {
                if (!Settings.ContainsKey(validateSetting) || string.IsNullOrWhiteSpace(Settings[validateSetting]))
                {
                    payment.Status = PaymentStatus.Failed.ToString();
                    message = string.Format("{0} not configured", validateSetting);
                    return false;
                }
            }

            var transactionType = (TransactionType)Enum.Parse(typeof(TransactionType), info.TransactionType);
            payment.Status = PaymentStatus.Processing.ToString();

            var gateway = new Gateway(Settings["MerchantLogin"], Settings["MerchantPassword"]);

            bool isTestMode;
            if (Settings.ContainsKey("TestMode") && bool.TryParse(Settings["TestMode"], out isTestMode))
            {
                gateway.TestMode = isTestMode;
            }

            var description = string.Format("{0} transaction for order id {1}", transactionType, info.OrderForm.OrderGroupId);
            IGatewayRequest request = null;

            switch (transactionType)
            {
                case TransactionType.Authorization:
                case TransactionType.Sale:
                    request = new AuthorizationRequest(info.CreditCardNumber,
                        string.Format("{0}{1}", info.CreditCardExpirationMonth, info.CreditCardExpirationYear),
                        info.Amount,
                        description,
                        transactionType == TransactionType.Sale);
                    break;
                case TransactionType.Capture:
                    request = new PriorAuthCaptureRequest(info.Amount, info.ValidationCode);
                    break;
                case TransactionType.Credit:
                    request = new CreditRequest(info.ValidationCode, info.Amount, info.CreditCardNumber);
                    break;
                case TransactionType.Void:
                    request = new VoidRequest(info.ValidationCode);
                    break;
            }

            if (request == null)
            {
                payment.Status = PaymentStatus.Failed.ToString();
                message = string.Format("Unsupported transation type {0}", transactionType);
                return false;
            }

            request.AddCardCode(info.CreditCardSecurityCode);

            var invoice = info.OrderForm.OrderGroupId;

            var order = info.OrderForm.OrderGroup as Order;
            if (order != null)
            {
                invoice = order.TrackingNumber;
            }

            request.AddInvoice(invoice);
            request.AddTax(info.OrderForm.TaxTotal);

            // Find the address
            var address = info.OrderForm.OrderGroup.OrderAddresses
                .FirstOrDefault(a => String.Compare(a.OrderAddressId, info.BillingAddressId, StringComparison.OrdinalIgnoreCase) == 0);

            if (address != null)
            {
                request.AddCustomer(address.Email, address.FirstName, address.LastName,
                    address.Line1 + " " + address.Line2, address.StateProvince, address.PostalCode);
            }

            //foreach (var lineItem in info.OrderForm.LineItems)
            //{
            //    request.AddLineItem(lineItem.LineItemId, lineItem.DisplayName, lineItem.Description,
            //        (int)lineItem.Quantity, lineItem.PlacedPrice, false);
            //}


            try
            {
                var response = gateway.Send(request, description);

                if (!response.Approved)
                {
                    payment.Status = PaymentStatus.Denied.ToString();
                    message = "Transaction Declined: " + response.Message;
                    return false;
                }
                info.StatusCode = response.ResponseCode;
                info.StatusDesc = response.Message;
                info.ValidationCode = response.TransactionID;
                info.AuthorizationCode = response.AuthorizationCode;

                // transaction is marked as completed every time the payment operation succeeds even if it is void transaction type
                payment.Status = PaymentStatus.Completed.ToString();          
            }
            catch (Exception ex)
            {
                payment.Status = PaymentStatus.Failed.ToString();
                throw new ApplicationException(ex.Message);
            }

            return true;

        }