/// <summary>
        /// Does the express checkout.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="authorizeOnly">if set to <c>true</c> [authorize only].</param>
        /// <returns></returns>
        internal Transaction DoExpressCheckout(Order order, bool authorizeOnly)
        {
            Transaction transaction = null;

              DoExpressCheckoutPaymentReq expressCheckoutPayment = new DoExpressCheckoutPaymentReq();
              DoExpressCheckoutPaymentRequestType expressCheckoutPaymentRequest = new DoExpressCheckoutPaymentRequestType();
              DoExpressCheckoutPaymentRequestDetailsType expressCheckoutPaymentRequestDetails = new DoExpressCheckoutPaymentRequestDetailsType();

              PaymentDetailsType paymentDetails = new PaymentDetailsType();
              if(authorizeOnly) {
            expressCheckoutPaymentRequestDetails.PaymentAction = PaymentActionCodeType.Authorization;
              }
              else {
            expressCheckoutPaymentRequestDetails.PaymentAction = PaymentActionCodeType.Sale;
              }

              expressCheckoutPaymentRequestDetails.Token = order.ExtendedProperties[PAYPAL_TOKEN].ToString();
              expressCheckoutPaymentRequestDetails.PayerID = order.ExtendedProperties[PAYPAL_PAYER_ID].ToString();

              expressCheckoutPaymentRequest.Version = PayPalServiceUtility.PayPalVersionNumber;

              #region Basic Payment Information

              Currency currency = new Currency();
              decimal total = GetOrderTotal(currency, order);
              //Required
              paymentDetails.OrderTotal = GetBasicAmount(total);

              //Optional (see DoDirectPayment for additional notes)
              paymentDetails.ItemTotal =
            GetBasicAmount(decimal.Round(order.SubTotal, currency.CurrencyDecimals));

              paymentDetails.ShippingTotal =
            GetBasicAmount(decimal.Round(order.ShippingAmount, currency.CurrencyDecimals));

              paymentDetails.TaxTotal =
            GetBasicAmount(decimal.Round(order.TaxTotal, currency.CurrencyDecimals));

              paymentDetails.HandlingTotal =
            GetBasicAmount(decimal.Round(order.HandlingAmount, currency.CurrencyDecimals));

              //Note: You can use this value for whatever purpose, such as an accounting tracking number
              //or additional data needed by your program.
              paymentDetails.Custom = order.OrderNumber;
              paymentDetails.ButtonSource = Constants.EC_BN_ID;

              #endregion

              #region ShipTo Address

              //Load up The ShipTo Address
              paymentDetails.ShipToAddress = new PayPalSvc.AddressType();
              paymentDetails.ShipToAddress.Name =
            order.ShippingAddress.FirstName + " " + order.ShippingAddress.LastName;
              paymentDetails.ShipToAddress.Street1 =
            order.ShippingAddress.Address1;
              paymentDetails.ShipToAddress.Street2 =
            order.ShippingAddress.Address2;
              paymentDetails.ShipToAddress.CityName =
            order.ShippingAddress.City;
              paymentDetails.ShipToAddress.StateOrProvince =
            order.ShippingAddress.StateOrRegion;
              paymentDetails.ShipToAddress.Country =
            (CountryCodeType)Enum.Parse(typeof(CountryCodeType), order.ShippingAddress.Country);
              paymentDetails.ShipToAddress.CountrySpecified = true;
              paymentDetails.ShipToAddress.PostalCode =
            order.ShippingAddress.PostalCode;

              #endregion

              #region Load Individual Items

              //Add the individual items if they are available
              //This will also add nice line item entries to the PayPal invoice - good for customers!
              OrderItemCollection orderItemCollection = order.OrderItemRecords();
              if(orderItemCollection != null) {
            if(orderItemCollection.Count > 0) {
              paymentDetails.PaymentDetailsItem = new PaymentDetailsItemType[orderItemCollection.Count];
              PaymentDetailsItemType[] paymentDetailsItems = new PaymentDetailsItemType[orderItemCollection.Count];
              PaymentDetailsItemType item = null;
              for(int i = 0;i < orderItemCollection.Count;i++) {
            item = new PaymentDetailsItemType();
            string sku = orderItemCollection[i].Sku.Trim();
            if(sku.Length > 127) {
              sku = sku.Substring(0, 126);
            }
            item.Name = orderItemCollection[i].Name;
            item.Number = sku;
            item.Amount = GetBasicAmount(decimal.Round(orderItemCollection[i].PricePaid, currency.CurrencyDecimals));
            item.Quantity = orderItemCollection[i].Quantity.ToString();
            item.Tax = GetBasicAmount(decimal.Round(orderItemCollection[i].ItemTax, currency.CurrencyDecimals));
            paymentDetailsItems[i] = item;
              }
              paymentDetails.PaymentDetailsItem = paymentDetailsItems;
            }
              }

              #endregion

              //Now load it all up
              expressCheckoutPayment.DoExpressCheckoutPaymentRequest = expressCheckoutPaymentRequest;
              expressCheckoutPayment.DoExpressCheckoutPaymentRequest.DoExpressCheckoutPaymentRequestDetails = expressCheckoutPaymentRequestDetails;
              expressCheckoutPayment.DoExpressCheckoutPaymentRequest.DoExpressCheckoutPaymentRequestDetails.PaymentDetails[0] = paymentDetails;

              #region Charge and Validation
              //Finally, send it
              DoExpressCheckoutPaymentResponseType expressCheckoutPaymentResponse =
            payPalAPIAASoapBinding.DoExpressCheckoutPayment(expressCheckoutPayment);
              //Validate the response
              string errorList = ValidateResponse(expressCheckoutPaymentResponse);
            //      if(expressCheckoutPaymentResponse.Ack != AckCodeType.Success && expressCheckoutPaymentResponse.Ack != AckCodeType.SuccessWithWarning) {
              if(IsValidResponse(expressCheckoutPaymentResponse.Ack)){
            if(!string.IsNullOrEmpty(errorList)) {
              throw new PayPalServiceException(errorList);
            }
              }
              #endregion

              #region Transaction

              transaction = new Transaction();
              transaction.OrderId = order.OrderId;
              if(!authorizeOnly) {
            transaction.TransactionTypeDescriptorId = (int)TransactionType.Charge;
              }
              else {
            transaction.TransactionTypeDescriptorId = (int)TransactionType.Authorization;
              }
              transaction.PaymentMethod = order.CreditCardType.ToString();
              transaction.GatewayName = PAYPAL_EXPRESSCHECKOUT;
              string gatewayResponse = expressCheckoutPaymentResponse.Ack.ToString();
              if(expressCheckoutPaymentResponse.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].PaymentStatus == PaymentStatusCodeType.Pending) {
            gatewayResponse += "::Pending";
              }
              transaction.GatewayResponse = gatewayResponse;
              transaction.GatewayTransactionId = expressCheckoutPaymentResponse.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].TransactionID;
              transaction.GrossAmount = Convert.ToDecimal(expressCheckoutPaymentResponse.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].GrossAmount.Value);
              transaction.FeeAmount = expressCheckoutPaymentResponse.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].FeeAmount != null ? Convert.ToDecimal(
            expressCheckoutPaymentResponse.DoExpressCheckoutPaymentResponseDetails.PaymentInfo[0].FeeAmount.Value) : 0M;
              transaction.TransactionDate = DateTime.Now;
              transaction.GatewayErrors = errorList;
              transaction.Save("System");

              #endregion

              return transaction;
        }
        /// <summary>
        /// Does the direct payment.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="authorizeOnly">if set to <c>true</c> [authorize only].</param>
        /// <returns></returns>
        internal Transaction DoDirectPayment(Order order, bool authorizeOnly)
        {
            Transaction transaction = null;

              DoDirectPaymentReq directPaymentReq = new DoDirectPaymentReq();
              directPaymentReq.DoDirectPaymentRequest = new DoDirectPaymentRequestType();
              directPaymentReq.DoDirectPaymentRequest.Version = PayPalServiceUtility.PayPalVersionNumber;

              DoDirectPaymentRequestDetailsType directPaymentRequestDetails = new DoDirectPaymentRequestDetailsType();
              //1st, set up the required objects / fields.
              directPaymentRequestDetails.PaymentDetails = new PaymentDetailsType();
              directPaymentRequestDetails.CreditCard = new CreditCardDetailsType();
              directPaymentRequestDetails.IPAddress = order.IPAddress;
              //Note: PaymentAction is not required, but defaults to Sale, so it makes sense to set it ASAP.
              // - PayPal_APIReference pg.45
              if (authorizeOnly) {
            directPaymentRequestDetails.PaymentAction = PaymentActionCodeType.Authorization;
              }
              else {
            directPaymentRequestDetails.PaymentAction = PaymentActionCodeType.Sale;
              }

              //2nd, populate the required objects / fields (in same order as in step 1, above)
              #region Load PaymentDetails

              Currency currency = new Currency();
              decimal total = GetOrderTotal(currency, order);
              //Required
              directPaymentRequestDetails.PaymentDetails.OrderTotal = GetBasicAmount(total);

              //Optional
              //Note: If you send these 4 items, they must sum to the OrderTotal (above)
              // - PaymentsPro Integration Guide, March 2007, pg.42
              //Note: You must specify the ItemTotal if you specify Amount in PaymentDetailsItem
              //or if you specify values for ShippingTotal or HandlingTotal
              directPaymentRequestDetails.PaymentDetails.ItemTotal =
            GetBasicAmount(decimal.Round(order.SubTotal - order.DiscountAmount, currency.CurrencyDecimals));

              directPaymentRequestDetails.PaymentDetails.ShippingTotal =
            GetBasicAmount(decimal.Round(order.ShippingAmount, currency.CurrencyDecimals));

              directPaymentRequestDetails.PaymentDetails.TaxTotal =
            GetBasicAmount(decimal.Round(order.TaxTotal, currency.CurrencyDecimals));

              directPaymentRequestDetails.PaymentDetails.HandlingTotal =
            GetBasicAmount(decimal.Round(order.HandlingAmount, currency.CurrencyDecimals));
              //End Note

              //Note: You can use this value for whatever purpose, such as an accounting tracking number
              //or additional data needed by your program.
              directPaymentRequestDetails.PaymentDetails.Custom = order.OrderNumber;
              directPaymentRequestDetails.PaymentDetails.ButtonSource = Constants.DP_BN_ID;

              #region ShipTo Address

              //Load up The ShipTo Address
              if(order.ShippingAddress != null) {
            directPaymentRequestDetails.PaymentDetails.ShipToAddress = new PayPalSvc.AddressType();
            directPaymentRequestDetails.PaymentDetails.ShipToAddress.Name =
              order.ShippingAddress.FirstName + " " + order.ShippingAddress.LastName;
            directPaymentRequestDetails.PaymentDetails.ShipToAddress.Street1 =
              order.ShippingAddress.Address1;
            directPaymentRequestDetails.PaymentDetails.ShipToAddress.Street2 =
              order.ShippingAddress.Address2;
            directPaymentRequestDetails.PaymentDetails.ShipToAddress.CityName =
              order.ShippingAddress.City;
            directPaymentRequestDetails.PaymentDetails.ShipToAddress.StateOrProvince =
              order.ShippingAddress.StateOrRegion;
            directPaymentRequestDetails.PaymentDetails.ShipToAddress.Country =
              (CountryCodeType)Enum.Parse(typeof(CountryCodeType), order.ShippingAddress.Country);
            directPaymentRequestDetails.PaymentDetails.ShipToAddress.CountrySpecified = true;
            directPaymentRequestDetails.PaymentDetails.ShipToAddress.PostalCode =
              order.ShippingAddress.PostalCode;
            }

              #endregion

              #region Load Individual Items

              //Add the individual items if they are available
              //This will also add nice line item entries to the PayPal invoice - good for customers!
              OrderItemCollection orderItemCollection = order.OrderItemCollection;
              if (orderItemCollection != null) {
            if (orderItemCollection.Count > 0) {
              directPaymentRequestDetails.PaymentDetails.PaymentDetailsItem = new PaymentDetailsItemType[orderItemCollection.Count];
              PaymentDetailsItemType[] paymentDetailsItems = new PaymentDetailsItemType[orderItemCollection.Count];
              PaymentDetailsItemType item = null;
              for(int i = 0;i < orderItemCollection.Count;i++) {
            item = new PaymentDetailsItemType();
            string sku = orderItemCollection[i].Sku.Trim();
            if (sku.Length > 127) {
              sku = sku.Substring(0, 126);
            }
            item.Name = orderItemCollection[i].Name;
            item.Number = sku;
            item.Amount = GetBasicAmount(decimal.Round(orderItemCollection[i].ItemDiscountedPrice, currency.CurrencyDecimals));
            item.Quantity = orderItemCollection[i].Quantity.ToString();
            item.Tax = GetBasicAmount(decimal.Round(orderItemCollection[i].ItemTax, currency.CurrencyDecimals));
            paymentDetailsItems[i] = item;
              }
              directPaymentRequestDetails.PaymentDetails.PaymentDetailsItem = paymentDetailsItems;
            }
              }

              #endregion

              #endregion

              #region CreditCard
              //Load up the Credit Card Payer information
              directPaymentRequestDetails.CreditCard.CardOwner = new PayerInfoType();
              directPaymentRequestDetails.CreditCard.CardOwner.Address = new PayPalSvc.AddressType();
              directPaymentRequestDetails.CreditCard.CardOwner.PayerName = new PersonNameType();
              if (order.BillingAddress == null)
            throw new ArgumentException("BillingAddress is missing " + order.PaymentMethod + " " + order.CreditCardType);
              if (order.BillingAddress.FirstName == null)
            throw new ArgumentException("BillingAddress.FirstName is missing " + order.PaymentMethod + " " + order.CreditCardType);
              directPaymentRequestDetails.CreditCard.CardOwner.PayerName.FirstName = order.BillingAddress.FirstName;
              directPaymentRequestDetails.CreditCard.CardOwner.PayerName.LastName = order.BillingAddress.LastName;
              CountryCodeType customerCountry = CountryCodeType.US;
              if (order.BillingAddress.Country != CountryCodeType.US.ToString()) {
            if (Enum.IsDefined(typeof(CountryCodeType), order.BillingAddress.Country)) {
              customerCountry = (CountryCodeType)Enum.Parse(typeof(CountryCodeType), order.BillingAddress.Country);
            }
              }
              directPaymentRequestDetails.CreditCard.CardOwner.PayerCountry = customerCountry;
              //Load up the Card Owner Address information
              directPaymentRequestDetails.CreditCard.CardOwner.Address.Country = customerCountry;
              directPaymentRequestDetails.CreditCard.CardOwner.Address.CountrySpecified = true;
              directPaymentRequestDetails.CreditCard.CardOwner.Address.Street1 = order.BillingAddress.Address1;
              directPaymentRequestDetails.CreditCard.CardOwner.Address.Street2 = order.BillingAddress.Address2;
              directPaymentRequestDetails.CreditCard.CardOwner.Address.CityName = order.BillingAddress.City;
              directPaymentRequestDetails.CreditCard.CardOwner.Address.StateOrProvince = order.BillingAddress.StateOrRegion;
              directPaymentRequestDetails.CreditCard.CardOwner.Address.PostalCode = order.BillingAddress.PostalCode;
              //Load up the Credit Card information
              directPaymentRequestDetails.CreditCard.CreditCardNumber = order.CreditCardNumber;
              CreditCardTypeType creditCardType = CreditCardTypeType.Visa;
              switch (order.CreditCardType) {
            case CreditCardType.MasterCard:
              creditCardType = CreditCardTypeType.MasterCard;
              break;
            case CreditCardType.Amex:
              creditCardType = CreditCardTypeType.Amex;
              break;
            case CreditCardType.Maestro:
              creditCardType = CreditCardTypeType.Switch;
              break;
            case CreditCardType.Solo:
              creditCardType = CreditCardTypeType.Solo;
              break;
              }
              directPaymentRequestDetails.CreditCard.CreditCardType = creditCardType;
              directPaymentRequestDetails.CreditCard.CreditCardTypeSpecified = true;
              directPaymentRequestDetails.CreditCard.IssueNumber = order.CreditCardIssueNumber;
              if (order.CreditCardStartMonth > 0) {
            directPaymentRequestDetails.CreditCard.StartMonth = order.CreditCardStartMonth;
            directPaymentRequestDetails.CreditCard.StartMonthSpecified = true;
              }
              if (order.CreditCardStartYear > 0) {
            directPaymentRequestDetails.CreditCard.StartYear = order.CreditCardStartYear;
            directPaymentRequestDetails.CreditCard.StartYearSpecified = true;
              }
              directPaymentRequestDetails.CreditCard.ExpMonth = order.CreditCardExpirationMonth;
              directPaymentRequestDetails.CreditCard.ExpMonthSpecified = true;
              directPaymentRequestDetails.CreditCard.ExpYear = order.CreditCardExpirationYear;
              directPaymentRequestDetails.CreditCard.ExpYearSpecified = true;
              directPaymentRequestDetails.CreditCard.CVV2 = order.CreditCardSecurityNumber;

              #endregion

              directPaymentReq.DoDirectPaymentRequest.DoDirectPaymentRequestDetails = directPaymentRequestDetails;

              #region Charge and Validation
              //Finally, send it
              DoDirectPaymentResponseType directPaymentResponse =
            payPalAPIAASoapBinding.DoDirectPayment(directPaymentReq);
              //Validate the response
              string errorList = ValidateResponse(directPaymentResponse);
              if (IsValidResponse(directPaymentResponse.Ack)){
            if (!string.IsNullOrEmpty(errorList)) {
              throw new PayPalServiceException(errorList);
            }
              }
              #endregion

              #region Transaction

              transaction = new Transaction();
              transaction.OrderId = order.OrderId;
              if(!authorizeOnly) {
            transaction.TransactionTypeDescriptorId = (int)TransactionType.Charge;
              }
              else {
            transaction.TransactionTypeDescriptorId = (int)TransactionType.Authorization;
              }
              transaction.PaymentMethod = order.CreditCardType.ToString();
              transaction.GatewayName = PAYPALPRO;
              transaction.GatewayResponse = directPaymentResponse.Ack.ToString();
              //These "Not Available"'s shouldn't trip off, but if PayPal is being flaky (like it is today), then this will allow the transaction to be saved.
              transaction.GatewayTransactionId = !string.IsNullOrEmpty(directPaymentResponse.TransactionID) ? directPaymentResponse.TransactionID : Strings.ResourceManager.GetString("lblNotAvailable");
              transaction.AVSCode = !string.IsNullOrEmpty(directPaymentResponse.AVSCode) ? directPaymentResponse.AVSCode : Strings.ResourceManager.GetString("lblNotAvailable");
              transaction.CVV2Code = !string.IsNullOrEmpty(directPaymentResponse.CVV2Code) ? directPaymentResponse.CVV2Code : Strings.ResourceManager.GetString("lblNotAvailable");
              if (directPaymentResponse.Amount != null) {//try to get it from PayPal
            transaction.GrossAmount = Convert.ToDecimal(directPaymentResponse.Amount.Value);
              }
              else {//but if it fails, then use the Order total
            transaction.GrossAmount = order.Total;
              }
              transaction.TransactionDate = DateTime.Now;
              transaction.GatewayErrors = errorList;
              transaction.Save("System");
              #endregion

              return transaction;
        }