private Transaction doCharge(BraintreeSession session, Account from, Account to, Amount amount, bool capture = true, string description = null, object extraData = null) { var fromActualData = session.FetchAccountData(from); var toActualData = session.FetchAccountData(to); try { var transaction = new XElement("transaction", new XElement("type", "sale"), new XElement("amount", amount.Value), new XElement(fromActualData.IsWebTerminal ? "payment-method-nonce" : "payment-method-token", fromActualData.AccountID)); if (toActualData != null) { transaction.Add(new XElement("order-id", "{0}:{1}:{2}".Args(toActualData.Identity, toActualData.IdentityID, toActualData.AccountID))); } if (fromActualData.IsWebTerminal) { if (fromActualData.IsNew) { transaction.Add(new XElement("customer", new XElement("id", fromActualData.IdentityID))); } else { try { getResponse(session, URI_Customer(session.MerchantID, fromActualData.IdentityID.ToString()), method: HTTPRequestMethod.GET); transaction.Add(new XElement("customer-id", fromActualData.IdentityID)); } catch { transaction.Add(new XElement("customer", new XElement("id", fromActualData.IdentityID))); } } } if (fromActualData.IsWebTerminal) { var billing = new XElement("billing"); if (fromActualData.FirstName.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("first-name", fromActualData.FirstName)); } if (fromActualData.LastName.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("last-name", fromActualData.LastName)); } if (fromActualData.BillingAddress.Address1.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("street-address", fromActualData.BillingAddress.Address1)); } if (fromActualData.BillingAddress.Address2.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("extended-address", fromActualData.BillingAddress.Address2)); } if (fromActualData.BillingAddress.City.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("locality", fromActualData.BillingAddress.City)); } if (fromActualData.BillingAddress.Country.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("country-code-alpha3", fromActualData.BillingAddress.Country)); } if (fromActualData.BillingAddress.Region.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("region", fromActualData.BillingAddress.Region)); } if (fromActualData.BillingAddress.PostalCode.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("postal-code", fromActualData.BillingAddress.PostalCode)); } if (fromActualData.BillingAddress.Company.IsNotNullOrWhiteSpace()) { billing.Add(new XElement("company", fromActualData.BillingAddress.Company)); } transaction.Add(billing); } var descriptorName = buildDescriptor(toActualData.IssuerName, description); if (descriptorName.IsNotNullOrWhiteSpace()) { var descriptor = new XElement("descriptor"); descriptor.Add(new XElement("name", descriptorName)); if (toActualData.IssuerUri.IsNotNullOrWhiteSpace()) { descriptor.Add(new XElement("url", toActualData.IssuerUri.TakeFirstChars(13))); } if (toActualData.IssuerPhone.IsNotNullOrWhiteSpace()) { descriptor.Add(new XElement("phone", toActualData.IssuerPhone)); } transaction.Add(descriptor); } var options = new XElement("options", new XElement("submit-for-settlement", capture)); if (fromActualData.IsWebTerminal) { options.Add(new XElement("store-in-vault-on-success", true)); } transaction.Add(options); var response = getResponse(session, URI_Transactions(session.MerchantID), new XDocument(transaction)); transaction = response.Root; var transactionID = transaction.Element("id").Value; var status = transaction.Element("status").Value; var captured = status.EqualsOrdIgnoreCase("submitted_for_settlement"); var createdAt = transaction.Element("created-at").Value.AsDateTime(); var creditCard = transaction.Element("credit-card"); var token = creditCard.Element("token").Value; var cardBin = creditCard.Element("bin").Value; var cardLast4 = creditCard.Element("last-4").Value; var cardType = creditCard.Element("card-type").Value; var cardHolder = creditCard.Element("cardholder-name").Value; var cardExpMonth = creditCard.Element("expiration-month").Value.AsNullableInt(); var cardExpYear = creditCard.Element("expiration-year").Value.AsNullableInt(); var cardExpDate = cardExpMonth.HasValue && cardExpYear.HasValue ? new DateTime(cardExpYear.Value, cardExpMonth.Value, 1) : (DateTime?)null; var cardMaskedName = "{2}{0}..{1}".Args(cardType, cardLast4, cardExpMonth.HasValue && cardExpYear.HasValue ? "{0}/{1} ".Args(cardExpMonth, cardExpYear) : string.Empty); var amountAuth = transaction.Element("amount").Value.AsDecimal(); var taId = session.GenerateTransactionID(TransactionType.Charge); var ta = new Transaction(taId, TransactionType.Charge, TransactionStatus.Success, from, to, Name, transactionID, createdAt, new Amount(amount.CurrencyISO, amountAuth), description: description, extraData: extraData); if (captured) { ta.__Apply(Transaction.Operation.Capture(TransactionStatus.Success, createdAt, token: transactionID, description: description, amount: amountAuth, extraData: extraData)); } session.StoreAccountData(new ActualAccountData(fromActualData.Account) { IdentityID = fromActualData.IdentityID, AccountID = token, AccountType = fromActualData.AccountType, CardHolder = cardHolder, CardMaskedName = cardMaskedName, CardExpirationDate = cardExpDate, FirstName = fromActualData.FirstName, MiddleName = fromActualData.MiddleName, LastName = fromActualData.LastName, Phone = fromActualData.Phone, EMail = fromActualData.EMail, BillingAddress = fromActualData.BillingAddress, IsNew = fromActualData.IsNew, IsWebTerminal = false, IssuerID = fromActualData.IssuerID, IssuerName = fromActualData.IssuerName, IssuerPhone = fromActualData.IssuerPhone, IssuerEMail = fromActualData.IssuerEMail, IssuerUri = fromActualData.IssuerUri, HadSuccessfullTransactions = true, // TODO: useless fields ShippingAddress = fromActualData.ShippingAddress, CardVC = fromActualData.CardVC, RoutingNumber = fromActualData.RoutingNumber, }); StatCharge(amount); if (capture) { StatCapture(ta, amount.Value); } return(ta); } catch (Exception ex) { StatChargeError(); if (ex is PaymentException) { throw ex; } throw new PaymentException(StringConsts.PAYMENT_CANNOT_CHARGE_PAYMENT_ERROR + GetType().Name + ".Charge(session='{0}', card='{1}', amount='{2}')".Args(session, from, amount), ex); } }