class Pay::Braintree::Billable
Attributes
pay_customer[R]
Public Class Methods
new(pay_customer)
click to toggle source
# File lib/pay/braintree/billable.rb, line 14 def initialize(pay_customer) @pay_customer = pay_customer end
Public Instance Methods
add_payment_method(token, default: false)
click to toggle source
# File lib/pay/braintree/billable.rb, line 101 def add_payment_method(token, default: false) customer unless processor_id? result = gateway.payment_method.create( customer_id: processor_id, payment_method_nonce: token, options: { make_default: default, verify_card: true } ) raise Pay::Braintree::Error, result unless result.success? pay_payment_method = save_payment_method(result.payment_method, default: default) # Update existing subscriptions to the new payment method pay_customer.subscriptions.each do |subscription| if subscription.active? gateway.subscription.update(subscription.processor_id, {payment_method_token: token}) end end pay_payment_method rescue ::Braintree::AuthorizationError => e raise Pay::Braintree::AuthorizationError, e rescue ::Braintree::BraintreeError => e raise Pay::Braintree::Error, e end
card_details_for_braintree_transaction(transaction)
click to toggle source
# File lib/pay/braintree/billable.rb, line 220 def card_details_for_braintree_transaction(transaction) case transaction.payment_instrument_type when "android_pay_card", "apple_pay_card", "credit_card", "google_pay_card", "samsung_pay_card", "visa_checkout_card" # Lookup the attribute with the payment method details by name attribute_name = transaction.payment_instrument_type # The attribute name for Apple and Google Pay don't include _card for some reason if ["apple_pay_card", "google_pay_card"].include?(transaction.payment_instrument_type) attribute_name = attribute_name.split("_card").first # Android Pay was renamed to Google Pay, but test nonces still use android_pay_card elsif attribute_name == "android_pay_card" attribute_name = "google_pay" end # Retrieve payment method details from transaction payment_method = transaction.send("#{attribute_name}_details") { payment_method_type: :card, brand: payment_method.card_type, last4: payment_method.last_4, exp_month: payment_method.expiration_month, exp_year: payment_method.expiration_year } when "paypal_account" { payment_method_type: :paypal, brand: "PayPal", last4: transaction.paypal_details.payer_email, exp_month: nil, exp_year: nil } when "venmo_account" { payment_method_type: :venmo, brand: "Venmo", last4: transaction.venmo_account_details.username, exp_month: nil, exp_year: nil } else {payment_method_type: "unknown"} end end
charge(amount, options = {})
click to toggle source
# File lib/pay/braintree/billable.rb, line 50 def charge(amount, options = {}) args = { amount: amount.to_i / 100.0, customer_id: customer.id, options: {submit_for_settlement: true}, custom_fields: options.delete(:metadata) }.merge(options) result = gateway.transaction.sale(args) raise Pay::Braintree::Error, result unless result.success? save_transaction(result.transaction) rescue ::Braintree::AuthorizationError => e raise Pay::Braintree::AuthorizationError, e rescue ::Braintree::BraintreeError => e raise Pay::Braintree::Error, e end
customer()
click to toggle source
Retrieve the Braintree::Customer object
-
If no processor_id is present, creates a Customer.
-
When 'payment_method_token' is present, it will also set the default payment method
# File lib/pay/braintree/billable.rb, line 22 def customer if processor_id? customer = gateway.customer.find(processor_id) if payment_method_token? add_payment_method(payment_method_token, default: true) pay_customer.payment_method_token = nil end customer else result = gateway.customer.create(email: email, first_name: try(:first_name), last_name: try(:last_name), payment_method_nonce: payment_method_token) raise Pay::Braintree::Error, result unless result.success? pay_customer.update!(processor_id: result.customer.id) if payment_method_token? save_payment_method(result.customer.payment_methods.last, default: true) pay_customer.payment_method_token = nil end result.customer end rescue ::Braintree::AuthorizationError => e raise Pay::Braintree::AuthorizationError, e rescue ::Braintree::BraintreeError => e raise Pay::Braintree::Error, e end
gateway()
click to toggle source
# File lib/pay/braintree/billable.rb, line 163 def gateway Pay.braintree_gateway end
processor_subscription(subscription_id, options = {})
click to toggle source
# File lib/pay/braintree/billable.rb, line 140 def processor_subscription(subscription_id, options = {}) gateway.subscription.find(subscription_id) end
save_payment_method(payment_method, default:)
click to toggle source
# File lib/pay/braintree/billable.rb, line 167 def save_payment_method(payment_method, default:) attributes = case payment_method when ::Braintree::CreditCard, ::Braintree::ApplePayCard, ::Braintree::GooglePayCard, ::Braintree::SamsungPayCard, ::Braintree::VisaCheckoutCard { payment_method_type: :card, brand: payment_method.card_type, last4: payment_method.last_4, exp_month: payment_method.expiration_month, exp_year: payment_method.expiration_year } when ::Braintree::PayPalAccount { payment_method_type: :paypal, brand: "PayPal", email: payment_method.email } when ::Braintree::VenmoAccount { payment_method_type: :venmo, brand: "Venmo", username: payment_method.username } when ::Braintree::UsBankAccount { payment_method_type: "us_bank_account", bank: payment_method.bank_name, last4: payment_method.last_4 } else { payment_method_type: payment_method.class.name.demodulize.underscore, brand: payment_method.try(:card_type), last4: payment_method.try(:last_4), exp_month: payment_method.try(:expiration_month), exp_year: payment_method.try(:expiration_year), bank: payment_method.try(:bank_name), username: payment_method.try(:username), email: payment_method.try(:email) } end pay_payment_method = pay_customer.payment_methods.where(processor_id: payment_method.token).first_or_initialize pay_customer.payment_methods.update_all(default: false) if default pay_payment_method.update!(attributes.merge(default: default)) # Reload the Rails association pay_customer.reload_default_payment_method if default pay_payment_method end
save_transaction(transaction)
click to toggle source
# File lib/pay/braintree/billable.rb, line 144 def save_transaction(transaction) attrs = card_details_for_braintree_transaction(transaction) attrs[:amount] = transaction.amount.to_f * 100 attrs[:metadata] = transaction.custom_fields attrs[:currency] = transaction.currency_iso_code attrs[:application_fee_amount] = transaction.service_fee_amount # Associate charge with subscription if we can if transaction.subscription_id pay_subscription = pay_customer.subscriptions.find_by(processor_id: transaction.subscription_id) attrs[:subscription] = pay_subscription attrs[:metadata] = pay_subscription.metadata end charge = pay_customer.charges.find_or_initialize_by(processor_id: transaction.id) charge.update!(attrs) charge end
subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options)
click to toggle source
# File lib/pay/braintree/billable.rb, line 68 def subscribe(name: Pay.default_product_name, plan: Pay.default_plan_name, **options) token = customer.payment_methods.find(&:default?).try(:token) raise Pay::Error, "Customer has no default payment method" if token.nil? # Standardize the trial period options if (trial_period_days = options.delete(:trial_period_days)) && trial_period_days > 0 options.merge!(trial_period: true, trial_duration: trial_period_days, trial_duration_unit: :day) end metadata = options.delete(:metadata) subscription_options = options.merge( payment_method_token: token, plan_id: plan ) result = gateway.subscription.create(subscription_options) raise Pay::Braintree::Error, result unless result.success? pay_customer.subscriptions.create!( name: name, processor_id: result.subscription.id, processor_plan: plan, status: :active, trial_ends_at: trial_end_date(result.subscription), ends_at: nil, metadata: metadata ) rescue ::Braintree::AuthorizationError => e raise Pay::Braintree::AuthorizationError, e rescue ::Braintree::BraintreeError => e raise Pay::Braintree::Error, e end
trial_end_date(subscription)
click to toggle source
# File lib/pay/braintree/billable.rb, line 134 def trial_end_date(subscription) return unless subscription.trial_period # Braintree returns dates without time zones, so we'll assume they're UTC subscription.first_billing_date.end_of_day end
update_email!()
click to toggle source
# File lib/pay/braintree/billable.rb, line 130 def update_email! gateway.customer.update(processor_id, email: email, first_name: try(:first_name), last_name: try(:last_name)) end