All Files (100.0% covered at 175.35 hits/line)
43 files in total.
722 relevant lines.
722 lines covered and
0 lines missed
- 2
require File.expand_path(File.join(File.dirname(__FILE__), 'env'))
- 2
require 'active_model'
- 2
require 'active_support/core_ext/object'
- 2
require 'active_support/core_ext/hash/except'
- 2
require 'active_support/core_ext/hash/deep_dup'
- 2
require 'active_support/core_ext/enumerable'
- 2
require 'active_support/core_ext/module/delegation'
- 2
require 'active_support/dependencies'
- 2
require 'active_support/inflector'
- 2
require 'ostruct'
- 2
require 'delegate'
- 2
require 'braintree'
- 2
require 'braintree/exceptions'
- 2
require 'braintree_rails/array_ext'
- 2
require 'braintree_rails/module_ext'
- 2
require 'braintree_rails/braintree_ext'
- 2
require 'braintree_rails/exceptions'
- 2
require 'braintree_rails/braintree_rails'
- 1
module BraintreeRails
- 1
class AddOn < Modification; end
end
- 2
module BraintreeRails
- 2
class AddOns < Modifications; end
end
- 2
module BraintreeRails
- 2
class Address
- 2
include Model
- 2
define_attributes(
:create => [:company, :country_name, :customer_id, :extended_address, :first_name, :id, :last_name, :locality, :postal_code, :region, :street_address],
:update => [:company, :country_name, :extended_address, :first_name, :last_name, :locality, :postal_code, :region, :street_address],
:readonly => [:country_code_alpha2, :country_code_alpha3, :country_code_numeric, :created_at, :updated_at],
:as_association => [:company, :country_name, :extended_address, :first_name, :last_name, :locality, :postal_code, :region, :street_address]
)
- 2
belongs_to :customer, :class => Customer, :foreign_key => :customer_id
- 2
CountryNames = {
:country_name => 0,
:country_code_alpha2 => 1,
:country_code_alpha3 => 2,
:country_code_numeric => 3
}
- 2
def self.sync_country_name_attributes(country_attribute, index)
- 8
define_method("#{country_attribute}=") do |value|
- 302
CountryNames.except(country_attribute).each do |other_attribute, other_index|
- 212316
other_value = Braintree::Address::CountryNames.find{|country_name| country_name[index] == value}.try(:[], other_index)
- 906
instance_variable_set("@#{other_attribute}", other_value)
end
- 302
instance_variable_set("@#{country_attribute}", value)
end
end
- 2
def self.find(customer_id, id)
- 1
new(braintree_model_class.find(customer_id, id))
end
- 2
def self.delete(customer_id, id)
- 2
braintree_model_class.delete(customer_id, id)
end
- 2
def ensure_model(model)
- 132
if Braintree::Transaction::AddressDetails === model
- 2
assign_attributes(extract_values(model))
- 2
self.persisted = model.id.present?
- 2
model
else
- 130
super
end
end
- 2
def full_name
- 3
"#{first_name} #{last_name}".strip
end
- 2
def destroy
- 1
if persisted?
- 1
run_callbacks :destroy do
- 1
self.class.delete(customer_id, id)
end
end
- 1
self.persisted = false unless frozen?
- 1
freeze
end
- 2
protected
- 2
def update
- 1
with_update_braintree(:update) do
- 1
self.class.braintree_model_class.update(self.customer_id, self.id, attributes_for(:update))
end
end
- 2
def update!
- 1
with_update_braintree(:update) do
- 1
self.class.braintree_model_class.update!(self.customer_id, self.id, attributes_for(:update))
end
end
- 2
CountryNames.each do |attribute, index|
- 8
sync_country_name_attributes(attribute, index)
end
end
end
- 2
module BraintreeRails
- 2
class AddressValidator < Validator
- 2
Validations = [
[:customer_id, :presence => true, :length => {:maximum => 36}, :on => :create],
[:first_name, :last_name, :company, :street_address, :extended_address, :locality, :region, :length => {:maximum => 255}],
- 492
[:country_name, :allow_blank => true, :inclusion => { :in => Braintree::Address::CountryNames.map {|country| country[0]}, :message => "%{value} is not allowed" }],
- 73
[:street_address, :presence => true, :if => Proc.new { Configuration.require_street_address }],
- 146
[:postal_code, :presence => true, :format => { :with => /\A[- a-z0-9]+\z/i}, :if => Proc.new { |address| address.errors[:postal_code].blank? && Configuration.require_postal_code }]
]
end
end
- 2
module BraintreeRails
- 2
class Addresses < SimpleDelegator
- 2
include CollectionAssociation
- 2
def initialize(customer)
- 7
@customer = customer
- 7
super(customer.raw_object.addresses)
end
- 2
def default_options
- 5
{:customer_id => @customer.id}
end
end
end
- 1
module BraintreeRails
- 1
class ApiError
- 1
attr_reader :message, :code
- 1
delegate :to_s, :empty?, :to => :message
- 1
def initialize(message, code)
- 22
@message, @code = message, code
end
- 1
def inspect
- 1
"#<#{self.class} (#{code}) #{message}>"
end
end
end
- 2
class Array
- 2
def deep_dup
- 87
self.dup.tap do |dupped|
- 87
dupped.each_with_index do |element, index|
- 252
dupped[index] = element.respond_to?(:deep_dup) ? element.deep_dup : element
end
end
end
end
- 2
module BraintreeRails
- 2
module Association
- 2
module ClassMethods
- 2
def has_many(name, options)
- 26
define_association_reader(name, options.merge(:foreign_key => :presence))
end
- 2
def belongs_to(name, options)
- 20
define_association_reader(name, options)
- 20
define_association_writer(name, options)
end
- 2
def has_one(name, options)
- 4
belongs_to(name, options)
end
- 2
def define_association_reader(name, options)
- 46
define_method(name) do
- 493
value = instance_variable_get("@#{name}")
- 493
return value if value.present?
- 187
value = self.send(options[:foreign_key])
- 187
value &&= options[:class].new(value)
- 187
instance_variable_set("@#{name}", value)
end
end
- 2
def define_association_writer(name, options)
- 20
define_method("#{name}=") do |value|
- 40
value &&= options[:class].new(value)
- 40
instance_variable_set("@#{name}", value)
end
end
end
- 2
def self.included(receiver)
- 13
receiver.extend ClassMethods
end
end
end
- 2
module BraintreeRails
- 2
module Attributes
- 2
module ClassMethods
- 2
def define_attributes(attributes)
- 13
all_attributes = attributes.values.flatten.uniq
- 13
attr_accessor(*all_attributes)
- 164
singleton_class.send(:define_method, :attributes_for) { |action| attributes[action] }
- 850
singleton_class.send(:define_method, :attributes) { all_attributes }
end
end
- 2
module InstanceMethods
- 2
def attributes
- 208
self.class.attributes.inject({}) do |hash, attribute|
- 4328
if (value = self.send(attribute)).present?
- 2066
hash[attribute] = value.respond_to?(:attributes_for) ? value.attributes_for(:as_association) : value
end
- 4328
hash
end
end
- 2
def attributes_for(action)
- 151
attributes_for_action = attributes.slice(*self.class.attributes_for(action))
- 151
attributes_for_action.slice!(*changed) unless action == :as_association
- 151
attributes_for_action
end
- 2
def assign_attributes(hash)
- 621
hash.each do |attribute, value|
- 6493
send("#{attribute}=", value) if respond_to?("#{attribute}=")
end
end
- 2
def extract_values(obj)
- 607
self.class.attributes.inject({}) do |hash, attr|
- 13268
hash[attr] = obj.send(attr) if obj.respond_to?(attr)
- 13268
hash
end
end
- 2
def changed
- 52
new_record? ? changed_for_new_record : changed_for_persisted
end
- 2
def changed_for_new_record
attributes.map do |attribute, value|
- 192
attribute if value.present?
- 40
end.compact
end
- 2
def changed_for_persisted
attributes.map do |attribute, value|
- 211
attribute if value != raw_object.send(attribute)
- 12
end.compact
end
end
- 2
def self.included(receiver)
- 13
receiver.extend ClassMethods
- 13
receiver.send :include, InstanceMethods
- 13
receiver.send :include, ::ActiveModel::Serializers::JSON
- 13
receiver.send :include, ::ActiveModel::Serializers::Xml
end
end
end
- 2
module BraintreeRails
- 2
class BillingAddress < Address
- 2
def self.braintree_model_name
- 77
superclass.braintree_model_name
end
end
end
- 2
[Braintree::Plan, Braintree::Modification].each do |model|
- 4
model.class_eval do
- 4
def self.find(id)
- 24
all.find {|plan| plan.id == id}
end
end
end
- 2
module Braintree
- 2
class Descriptor
- 2
def ==(other)
- 2
return false unless other.is_a?(Descriptor)
- 2
name == other.name && phone == other.phone
end
- 2
def attributes_for(action)
- 4
{:name => name, :phone => phone}
end
end
end
- 2
module Braintree
- 2
class Subscription
- 2
def self.delete(id)
- 4
cancel(id)
end
- 2
def never_expires
- 31
@never_expires
end
end
end
- 2
module Braintree
- 2
class CreditCard
- 2
def id
- 36
token
end
- 2
def expired
- 49
@expired
end
- 2
def default
- 54
@default
end
- 2
def number
nil
end
- 2
def cvv
nil
end
end
end
- 2
module Braintree
- 2
class Transaction
- 2
class CreditCardDetails
- 2
def id
- 6
token
end
end
end
end
- 2
module BraintreeRails
- 2
extend ActiveSupport::Autoload
- 2
Dir.chdir(File.dirname(__FILE__)) do
- 2
eager_autoload do
- 2
Dir.glob("*.rb").each do |file|
- 86
autoload file.chomp(".rb").camelize.to_sym
end
end
end
end
- 2
module BraintreeRails
- 2
module CollectionAssociation
- 2
module ClassMethods
- 2
def self.extended(receiver)
- 10
receiver.class_eval do
- 10
attr_accessor :collection, :loaded
- 10
lazy_load(Array.public_instance_methods - Object.public_instance_methods)
end
end
- 2
def lazy_load(methods)
- 10
methods.each do |method|
- 1344
define_method(method) { |*args, &block| load!; super(*args, &block) }
end
end
end
- 2
module InstanceMethods
- 2
def initialize(collection)
- 68
super(self.collection = (collection || []))
end
- 2
def find(id = nil, &block)
- 40
id.nil? ? super(&block) : super() { |model| model.id == id }
end
- 2
def build(params = {})
- 21
model_class.new(default_options.merge(params))
end
- 2
def create(params = {})
- 11
build(params).tap { |model| push(model) if model.save }
end
- 2
def create!(params = {})
- 20
build(params).tap { |model| push(model) if model.save! }
end
- 2
def model_class
- 79
self.class.name.singularize.constantize
end
- 2
def load!
- 75
return if loaded
- 49
self.loaded = true
- 107
__setobj__(collection.map{|model| model_class.new(model)})
end
end
- 2
def self.included(receiver)
- 10
receiver.extend ClassMethods
- 10
receiver.send :include, InstanceMethods
end
end
end
- 2
module BraintreeRails
- 2
class Configuration
- 2
module Mode
- 2
JS = 'JS'
- 2
S2S = 'S2S'
- 2
TR = 'TR'
end
- 2
singleton_class.class_eval do
- 2
delegate :custom_user_agent, :environment, :merchant_id, :public_key, :private_key, :logger, :to => Braintree::Configuration
- 2
delegate :custom_user_agent=, :environment=, :merchant_id=, :public_key=, :private_key=, :logger=, :to => Braintree::Configuration
- 2
attr_accessor :mode, :require_postal_code, :require_street_address, :client_side_encryption_key
end
- 2
self.custom_user_agent = "braintree-rails-#{Version}"
- 2
self.mode = Mode::JS
- 2
self.require_postal_code = true
- 2
self.require_street_address = true
end
end
- 2
module BraintreeRails
- 2
class CreditCard
- 2
include Model
- 2
define_attributes(
:create => [:billing_address, :cardholder_name, :customer_id, :expiration_date, :expiration_month, :expiration_year, :number, :cvv, :options, :token],
:update => [:billing_address, :cardholder_name, :expiration_date, :expiration_month, :expiration_year, :options, :number, :cvv],
:readonly => [
:bin, :card_type, :commercial, :country_of_issuance, :created_at, :debit, :durbin_regulated, :default,
:expired, :healthcare, :issuing_bank, :last_4, :payroll, :prepaid, :unique_number_identifier, :updated_at
],
:as_association => [:cardholder_name, :cvv, :expiration_date, :expiration_month, :expiration_year, :number]
)
- 2
has_many :transactions, :class => Transactions
- 2
has_many :subscriptions, :class => Subscriptions
- 2
belongs_to :customer, :class => Customer, :foreign_key => :customer_id
- 2
alias_method :id, :token
- 2
alias_method :id=, :token=
- 2
around_persist :clear_encryped_attributes
- 2
def ensure_model(model)
- 126
if Braintree::Transaction::CreditCardDetails === model
- 6
assign_attributes(extract_values(model))
- 6
self.persisted = model.id.present?
- 6
model
else
- 120
super
end
end
- 2
def expired?
- 1
expired
end
- 2
def default?
- 24
default
end
- 2
def masked_number
- 1
"#{bin}******#{last_4}"
end
- 2
def billing_address=(value)
- 93
@billing_address = value && BillingAddress.new(value)
end
- 2
def add_errors(validation_errors)
- 3
billing_address.add_errors(validation_errors.except(:base)) if billing_address
- 3
super(validation_errors)
end
- 2
def attributes_for(action)
- 35
super.tap do |attributes|
- 35
if attributes[:billing_address] && action == :update
- 5
attributes[:billing_address].merge!(:options => {:update_existing => true})
end
end
end
- 2
def clear_encryped_attributes
- 29
yield if block_given?
ensure
- 29
return unless Configuration.mode == Configuration::Mode::JS
- 29
[:number=, :cvv=].each do |encrypted_attribute|
- 58
self.send(encrypted_attribute, nil)
end
end
end
end
- 2
module BraintreeRails
- 2
class CreditCardValidator < Validator
- 2
Validations = [
[:cardholder_name, :length => {:maximum => 255}],
[:customer_id, :presence => true, :length => {:maximum => 36}, :on => :create],
[:number, :presence => true, :allow_blank => false, :if => :new_record?],
- 216
[:number, :numericality => {:only_integer => true}, :length => {:minimum => 12, :maximum => 19}, 'braintree_rails/luhn_10' => true, :if => Proc.new { Configuration.mode == Configuration::Mode::S2S }],
[:cvv, :presence => true, :allow_blank => false, :if => :new_record?],
- 144
[:cvv, :numericality => {:only_integer => true}, :length => {:minimum => 3, :maximum => 4}, :if => Proc.new { Configuration.mode == Configuration::Mode::S2S }],
- 72
[:expiration_month, :presence => true, :if => Proc.new { |credit_card| credit_card.new_record? && credit_card.expiration_date.blank? }],
- 72
[:expiration_year, :presence => true, :if => Proc.new { |credit_card| credit_card.new_record? && credit_card.expiration_date.blank? }],
- 72
[:expiration_date, :presence => true, :if => Proc.new { |credit_card| credit_card.new_record? && credit_card.expiration_month.blank? }],
- 72
[:expiration_month, :numericality => { :only_integer => true, :greater_than_or_equal_to => 1, :less_than_or_equal_to => 12 }, :if => Proc.new { Configuration.mode == Configuration::Mode::S2S }],
- 72
[:expiration_year, :numericality => { :only_integer => true, :greater_than_or_equal_to => 1976, :less_than_or_equal_to => 2200 }, :if => Proc.new { Configuration.mode == Configuration::Mode::S2S }],
]
- 2
def validate(credit_card)
- 72
have_valid_billing_address(credit_card) if validate_billing_address?
end
- 2
def have_valid_billing_address(credit_card)
- 72
credit_card.instance_eval do
- 72
errors.add(:billing_address, "is empty") and return if billing_address.blank?
- 34
if billing_address.invalid?
- 1
errors.add(:billing_address, "is not valid")
- 1
billing_address.errors.full_messages.each do |message|
- 2
errors.add(:base, message)
end
end
end
end
- 2
def validate_billing_address?
- 72
Configuration.require_postal_code || Configuration.require_street_address
end
end
end
- 2
module BraintreeRails
- 2
class CreditCards < SimpleDelegator
- 2
include CollectionAssociation
- 2
def initialize(customer)
- 25
@customer = customer
- 25
super(customer.raw_object.credit_cards)
end
- 2
def default_options
- 8
{:customer_id => @customer.id}
end
end
end
- 2
module BraintreeRails
- 2
class Customer
- 2
include Model
- 2
define_attributes(
:create => [:company, :custom_fields, :email, :fax, :first_name, :id, :last_name, :options, :phone, :website],
:update => [:company, :custom_fields, :email, :fax, :first_name, :last_name, :options, :phone, :website],
:readonly => [:created_at, :updated_at],
:as_association => [:id, :company, :email, :fax, :first_name, :last_name, :phone, :website]
)
- 2
has_many :addresses, :class => Addresses
- 2
has_many :transactions, :class => Transactions
- 2
has_many :credit_cards, :class => CreditCards
- 2
def ensure_model(model)
- 117
if Braintree::Transaction::CustomerDetails === model
- 1
assign_attributes(extract_values(model))
- 1
self.persisted = model.id.present?
- 1
model
else
- 116
super
end
end
- 2
def full_name
- 3
"#{first_name} #{last_name}".strip
end
- 2
def default_credit_card
- 23
credit_cards.find(&:default?)
end
end
end
- 2
module BraintreeRails
- 2
class CustomerValidator < Validator
- 2
Validations = [
[:id, :format => {:with => /\A[-_a-z0-9]*\z/i}, :length => {:maximum => 36}, :exclusion => {:in => %w(all new)}],
[:first_name, :last_name, :company, :website, :phone, :fax, :length => {:maximum => 255}]
]
end
end
- 1
module BraintreeRails
- 1
class Discount < Modification; end
end
- 2
module BraintreeRails
- 2
class Discounts < Modifications; end
end
- 2
module BraintreeRails
- 2
class Error < StandardError; end
- 2
class NotSupportedApiException < Error; end
- 2
class RecordInvalid < Braintree::BraintreeError
- 2
attr_reader :record
- 2
def initialize(record)
- 11
@record = record
- 11
super(@record.errors.full_messages.join(", "))
end
end
end
- 2
module BraintreeRails
- 2
class Luhn10Validator < ActiveModel::EachValidator
- 2
def validate_each(record, attribute, value)
- 25
return unless record.errors[attribute].blank?
- 6
record.errors.add(attribute, 'failed Luhn 10 validation') if invalid_luhn_10_number?(value)
end
- 2
private
- 2
def invalid_luhn_10_number?(number)
- 56
number.to_s.split('').reverse.each_slice(2).sum{|odd, even| [odd, even.to_i*2].join.split('').sum(&:to_i) } % 10 != 0
end
end
end
- 2
module BraintreeRails
- 2
def self.use_relative_model_naming?
- 7
true
end
- 2
module Model
- 2
module ClassMethods
- 2
def self.extended(receiver)
- 13
receiver.class_eval do
- 13
attr_reader :raw_object
- 13
extend ::ActiveModel::Naming
- 13
include ::ActiveModel::Validations
- 13
include ::ActiveModel::Conversion
end
end
end
- 2
module InstanceMethods
- 2
def initialize(model = {})
- 554
init(model)
end
- 2
def ensure_model(model)
- 598
model = case model
when String
- 40
self.persisted = true
- 40
self.class.braintree_model_class.find(model)
when self.class.braintree_model_class
- 205
self.persisted = model.id.present?
- 205
model
when Hash
- 288
self.persisted = false
- 288
OpenStruct.new(model)
else
- 65
self.persisted = model.respond_to?(:persisted?) ? model.persisted? : false
- 65
model
end
- 598
assign_attributes(extract_values(model))
- 598
model
end
- 2
def add_errors(validation_errors)
- 8
validation_errors.each do |attribute, message|
- 21
if attribute.to_s == 'base'
- 1
Array(message).each do |msg|
- 1
self.errors.add(attribute, msg)
end
elsif respond_to?(attribute)
- 9
self.errors.add(attribute, message)
end
end
end
- 2
def ==(other)
- 10
return false unless other.is_a?(self.class) || other.is_a?(self.class.braintree_model_class)
- 10
id == other.id
end
- 2
private
- 2
def init(model)
- 607
@raw_object = ensure_model(model)
end
end
- 2
def self.included(receiver)
- 13
receiver.send :include, BraintreeRails::Attributes
- 13
receiver.send :include, BraintreeRails::Association
- 13
receiver.send :include, BraintreeRails::Persistence
- 13
receiver.send :include, BraintreeRails::Validations
- 13
receiver.send :include, InstanceMethods
- 13
receiver.extend ClassMethods
end
end
end
- 1
module BraintreeRails
- 1
class Modification
- 1
include Model
- 1
singleton_class.not_supported_apis(:delete)
- 1
not_supported_apis(:create, :create!, :update, :update!, :destroy)
- 1
define_attributes(
:readonly => [
:amount, :created_at, :description, :id, :kind, :merchant_id, :name,
:never_expires, :number_of_billing_cycles, :quantity, :updated_at
]
)
- 1
def self.all
- 4
braintree_model_class.all.map{ |modification| new(modification) }
end
- 1
def never_expires?
- 2
never_expires
end
end
end
- 1
module BraintreeRails
- 1
class ModificationValidator < Validator
- 1
Validations = []
end
end
- 2
module BraintreeRails
- 2
class Modifications < SimpleDelegator
- 2
include CollectionAssociation
- 2
not_supported_apis(:build)
- 2
def initialize(parent)
- 12
super(parent.raw_object.send(self.class.name.demodulize.underscore))
end
end
end
- 2
class Module
- 2
def not_supported_apis(*methods)
- 15
methods.each do |method|
- 38
define_method(method) {|*args| raise BraintreeRails::NotSupportedApiException}
end
end
end
- 2
module BraintreeRails
- 2
module Persistence
- 2
module ClassMethods
- 2
def create(params)
- 2
new(params).tap { |new_record| new_record.save }
end
- 2
def create!(params)
- 32
new(params).tap { |new_record| new_record.save! }
end
- 2
def find(id)
- 32
new(braintree_model_class.find(id))
end
- 2
def delete(id)
- 8
braintree_model_class.delete(id)
end
- 2
def braintree_model_class
- 698
"braintree/#{braintree_model_name}".camelize.constantize
end
- 2
def braintree_model_name
- 764
name.demodulize.underscore
end
end
- 2
module InstanceMethods
- 2
def persisted?
- 1389
!!persisted
end
- 2
def new_record?
- 1250
!persisted?
end
- 2
def save(*)
- 18
run_callbacks :save do
- 18
create_or_update
end
rescue RecordInvalid
- 1
false
end
- 2
def save!(*)
- 34
run_callbacks :save do
- 34
create_or_update!
end
end
- 2
def update_attributes(attributes)
- 7
assign_attributes(attributes)
- 7
save
end
- 2
def update_attributes!(attributes)
- 6
assign_attributes(attributes)
- 6
save!
end
- 2
def destroy
- 6
if persisted?
- 5
run_callbacks :destroy do
- 5
self.class.delete(id)
end
end
- 6
self.persisted = false unless frozen?
- 6
freeze
end
- 2
def delete; destroy; end
- 2
def delete!; destroy; end
- 4
def destroy!; destroy; end
- 2
protected
- 2
def create_or_update
- 18
!!(new_record? ? create : update)
end
- 2
def create_or_update!
- 34
!!(new_record? ? create! : update!)
end
- 2
def create
- 12
with_update_braintree(:create) do
- 11
self.class.braintree_model_class.create(attributes_for(:create))
end
end
- 2
def create!
- 28
with_update_braintree(:create) do
- 28
self.class.braintree_model_class.create!(attributes_for(:create))
end
end
- 2
def update
- 4
with_update_braintree(:update) do
- 4
self.class.braintree_model_class.update(id, attributes_for(:update))
end
end
- 2
def update!
- 5
with_update_braintree(:update) do
- 5
self.class.braintree_model_class.update!(id, attributes_for(:update))
end
end
- 2
def with_update_braintree(context)
- 65
raise RecordInvalid.new(self) unless valid?(context)
- 58
run_callbacks context do
- 58
result = yield
- 56
if result.respond_to?(:success?) && !result.success?
- 3
add_errors(extract_errors(result))
- 3
false
else
- 53
new_record = result.respond_to?(self.class.braintree_model_name) ? result.send(self.class.braintree_model_name) : result
- 53
init(new_record)
end
end
end
- 2
def extract_errors(result)
- 3
base_errors(result).merge(attribute_errors(result))
end
- 2
def base_errors(result)
- 3
all_messages = result.message.split("\n")
- 3
base_messages = all_messages - attribute_errors(result).values.map(&:to_s)
- 3
base_messages.empty? ? {} : {'base' => base_messages}
end
- 2
def attribute_errors(result)
- 6
result.errors.inject({}) do |hash, error|
- 18
next hash if error.attribute.to_s == 'base'
- 18
hash[error.attribute.to_s] = BraintreeRails::ApiError.new(error.message, error.code)
- 18
hash
end
end
end
- 2
def self.included(receiver)
- 13
receiver.extend ActiveModel::Callbacks
- 13
receiver.extend ClassMethods
- 13
receiver.send :include, InstanceMethods
- 13
receiver.class_eval do
- 13
attr_accessor :persisted
- 13
define_model_callbacks :validate, :save, :create, :update, :destroy
end
end
end
end
- 2
module BraintreeRails
- 2
class Plan
- 2
include Model
- 2
singleton_class.not_supported_apis(:delete)
- 2
not_supported_apis(:create, :create!, :update, :update!, :destroy)
- 2
define_attributes(
:readonly => [
:billing_day_of_month, :billing_frequency, :created_at, :currency_iso_code, :description, :id, :merchant_id, :name,
:number_of_billing_cycles, :price, :trial_duration, :trial_duration_unit, :trial_period, :updated_at
]
)
- 2
has_many :add_ons, :class => AddOns
- 2
has_many :discounts, :class => Discounts
- 2
has_many :subscriptions, :class => Subscriptions
- 2
def self.all
- 2
braintree_model_class.all.map{ |plan| new(plan) }
end
end
end
- 2
module BraintreeRails
- 2
class PlanValidator < Validator
- 2
Validations = []
end
end
- 2
module BraintreeRails
- 2
class ShippingAddress < Address
- 2
def self.braintree_model_name
- 1
superclass.braintree_model_name
end
end
end
- 2
module BraintreeRails
- 2
class Subscription
- 2
include Model
- 2
define_attributes(
:create => [
:billing_day_of_month, :first_billing_date, :id, :merchant_account_id, :never_expires, :number_of_billing_cycles,
:payment_method_token, :plan_id, :price, :trial_duration, :trial_duration_unit, :trial_period, :options, :descriptor
],
:update => [
:merchant_account_id, :never_expires, :number_of_billing_cycles,
:payment_method_token, :plan_id, :price, :options
],
:readonly => [
:balance, :billing_period_end_date, :billing_period_start_date, :current_billing_cycle, :days_past_due,
:failure_count, :next_billing_date, :next_billing_period_amount, :paid_through_date, :status
]
)
- 2
has_many :add_ons, :class => AddOns
- 2
has_many :discounts, :class => Discounts
- 2
has_many :transactions, :class => Transactions
- 2
belongs_to :plan, :class => Plan, :foreign_key => :plan_id
- 2
belongs_to :credit_card, :class => CreditCard, :foreign_key => :payment_method_token
- 2
def self.cancel(id)
- 1
delete(id)
end
- 2
def cancel
- 1
destroy
end
- 2
def price=(val)
- 40
@price = val.blank? ? nil : val
end
- 2
def never_expires?
- 1
never_expires
end
end
end
- 2
module BraintreeRails
- 2
class SubscriptionValidator < Validator
- 2
Validations = [
[:id, :format => {:with => /\A[-_[:alnum:]]*\z/}, :exclusion => {:in => %w(all new)}],
- 2
[:billing_day_of_month, :numericality => { :only_integer => true }, :inclusion => {:in => [*(1..28), 31]}, :allow_nil => true, :if => :new_record?],
[:number_of_billing_cycles, :numericality => { :only_integer => true, :greater_than_or_equal_to => 1 }, :allow_nil => true],
[:payment_method_token, :presence => true, :if => :new_record?],
[:plan_id, :presence => true, :if => :new_record?],
[:price, :numericality => true, :allow_nil => true],
[:trial_duration, :presence => true, :numericality => { :only_integer => true, :greater_than_or_equal_to => 1, :less_than_or_equal_to => 9999 }, :if => :trial_period],
[:trial_duration_unit, :presence => true, :inclusion => { :in => %w(day month) }, :if => :trial_period]
]
- 2
def validate(subscription)
- 89
number_of_billing_cycles_must_be_greater_than_current_billing_cycle(subscription)
- 89
first_billing_date_must_be_valid_future_date(subscription)
end
- 2
def number_of_billing_cycles_must_be_greater_than_current_billing_cycle(subscription)
- 89
subscription.instance_eval do
- 89
if number_of_billing_cycles.present? && current_billing_cycle.present?
- 2
errors.add(:number_of_billing_cycles, "is too small") if number_of_billing_cycles < current_billing_cycle
end
end
end
- 2
def first_billing_date_must_be_valid_future_date(subscription)
- 89
subscription.instance_eval do
- 89
begin
- 89
if new_record? && first_billing_date.present?
- 9
errors.add(:first_billing_date, "cannot be in the past") if DateTime.parse(first_billing_date.to_s) < Date.today
end
rescue ArgumentError
- 1
errors.add(:first_billing_date, "is invalid")
end
end
end
end
end
- 2
module BraintreeRails
- 2
class Subscriptions < SimpleDelegator
- 2
include CollectionAssociation
- 2
def initialize(belongs_to)
- 9
case belongs_to
when BraintreeRails::CreditCard
- 3
@credit_card = belongs_to
when BraintreeRails::Plan
- 4
@plan = belongs_to
end
- 9
super([])
end
- 2
def default_options
- 3
if @credit_card.present?
- 1
{:payment_method_token => @credit_card.token}
- 2
elsif @plan.present?
- 1
{:plan_id => @plan.id}
else
- 1
{}
end
end
- 2
protected
- 2
def load!
- 4
self.collection = if @credit_card.present?
- 1
@credit_card.raw_object.subscriptions
elsif @plan.present?
- 4
Braintree::Subscription.search {|search| search.plan_id.is @plan.id}
else
- 1
Braintree::Subscription.search
end
- 4
super
end
end
end
- 2
module BraintreeRails
- 2
class Transaction
- 2
include Model
- 2
singleton_class.not_supported_apis(:delete)
- 2
not_supported_apis(:update, :update!, :destroy)
- 2
define_attributes(
:create => [
:amount, :billing, :channel, :custom_fields, :customer_id, :descriptor, :merchant_account_id,
:options, :order_id, :payment_method_token, :purchase_order_number, :recurring, :shipping,
:tax_amount, :tax_exempt, :type, :venmo_sdk_payment_method_code
],
:readonly => [
:avs_error_response_code, :avs_postal_code_response_code, :avs_street_address_response_code, :billing_details,
:channel, :created_at, :credit_card, :credit_card_details, :currency_iso_code, :customer, :customer_details,
:cvv_response_code, :id, :plan_id, :purchase_order_number, :refund_ids, :refunded_transaction_id, :settlement_batch_id,
:shipping_details, :status, :status_history, :subscription_details, :updated_at
]
)
- 2
has_many :add_ons, :class => AddOns
- 2
has_many :discounts, :class => Discounts
- 2
has_one :billing, :class => BillingAddress, :foreign_key => :billing_details
- 2
has_one :shipping, :class => ShippingAddress, :foreign_key => :shipping_details
- 2
belongs_to :customer, :class => Customer, :foreign_key => :customer_details
- 2
belongs_to :credit_card, :class => CreditCard, :foreign_key => :credit_card_details
- 2
belongs_to :subscription, :class => Subscription, :foreign_key => :subscription_id
- 2
belongs_to :plan, :class => Plan, :foreign_key => :plan_id
- 2
around_persist :clear_encryped_attributes
- 2
def type
- 127
@type ||= 'sale'
end
- 2
def submit_for_settlement(amount = nil)
- 4
submit_for_settlement!(amount)
rescue RecordInvalid
- 3
false
end
- 2
def submit_for_settlement!(amount = nil)
- 10
!!with_update_braintree(:submit_for_settlement) {Braintree::Transaction.submit_for_settlement!(id, amount)}
end
- 2
def refund(amount = nil)
- 2
refund!(amount)
rescue RecordInvalid
- 1
false
end
- 2
def refund!(amount = nil)
- 3
!!with_update_braintree(:refund) {Braintree::Transaction.refund!(id, amount)}
end
- 2
def void
- 2
void!
rescue RecordInvalid
- 1
false
end
- 2
def void!
- 9
!!with_update_braintree(:void) {Braintree::Transaction.void!(id)}
end
- 2
def add_errors(validation_errors)
- 1
propergate_errors_to_associations(validation_errors)
- 1
super(validation_errors)
end
- 2
def clear_encryped_attributes
- 17
yield if block_given?
ensure
- 17
credit_card.clear_encryped_attributes if credit_card.present?
end
- 2
def attributes
- 31
super.except(:customer_details, :credit_card_details, :billing_details, :shipping_details, :subscription_details, :status_history)
end
- 2
protected
- 2
def propergate_errors_to_associations(validation_errors)
- 1
[customer, credit_card, billing, shipping].each do |association|
- 4
association.add_errors(validation_errors.except('base')) if association
end
end
- 2
def attributes_for(action)
- 15
super.merge(customer_attributes).merge(credit_card_attributes)
end
- 2
def customer_attributes
- 15
if customer.present?
- 11
if customer.persisted?
- 10
{:customer_id => customer.id}
else
- 1
{:customer => customer.attributes_for(:as_association)}
end
else
- 4
{}
end
end
- 2
def credit_card_attributes
- 15
if credit_card.present?
- 10
if credit_card.persisted?
- 7
{:payment_method_token => credit_card.token}
else
- 3
{:credit_card => credit_card.attributes_for(:as_association)}
end
- 5
elsif customer.present? && customer.default_credit_card
- 4
{:payment_method_token => customer.default_credit_card.token}
else
- 1
{}
end
end
end
end
- 2
module BraintreeRails
- 2
class TransactionValidator < Validator
- 2
Validations = [
[:amount, :presence => true, :numericality => {:greater_than_or_equal_to => 0}, :if => :new_record?],
[:type, :presence => true, :inclusion => {:in => %w(sale credit)}, :if => :new_record?],
[:status, :inclusion => {:in => [Braintree::Transaction::Status::Authorized]}, :on => :submit_for_settlement],
[:status, :inclusion => {:in => [Braintree::Transaction::Status::Settled, Braintree::Transaction::Status::Settling]}, :on => :refund],
[:status, :inclusion => {:in => [Braintree::Transaction::Status::Authorized, Braintree::Transaction::Status::SubmittedForSettlement]}, :on => :void]
]
- 2
def setup(*)
- 2
self.class.model_class.class_eval do
- 2
define_model_callbacks :submit_for_settlement, :refund, :void
end
- 2
super
end
- 2
def validate(transaction)
- 63
must_have_credit_card(transaction) if transaction.new_record?
end
- 2
def must_have_credit_card(transaction)
- 47
if transaction.credit_card.blank?
- 21
validate_customer_have_default_credit_card(transaction)
- 26
elsif transaction.credit_card.new_record?
- 11
validate_new_credit_card(transaction)
end
end
- 2
def validate_customer_have_default_credit_card(transaction)
- 21
if transaction.customer.blank?
- 11
transaction.errors.add(:base, "Either customer or credit card is required")
- 10
elsif transaction.customer.default_credit_card.blank?
- 1
transaction.errors.add(:base, "Customer does not have a default credit card")
end
end
- 2
def validate_new_credit_card(transaction)
- 11
transaction.credit_card.billing_address = transaction.billing
- 11
if transaction.credit_card.invalid?
- 2
transaction.credit_card.errors.full_messages.each do |message|
- 2
transaction.errors.add(:base, message)
end
end
end
end
end
- 2
module BraintreeRails
- 2
class Transactions < SimpleDelegator
- 2
include CollectionAssociation
- 2
def initialize(belongs_to)
- 15
case belongs_to
when BraintreeRails::Customer
- 8
@customer = belongs_to
when BraintreeRails::CreditCard
- 2
@credit_card = belongs_to
when BraintreeRails::Subscription
- 3
@subscription = belongs_to
- 3
self.singleton_class.not_supported_apis(:build)
end
- 15
super([])
end
- 2
def default_options
- 5
if @credit_card.present?
- 1
{:credit_card => @credit_card}
- 4
elsif @customer.present?
- 3
{:customer => @customer, :credit_card => @customer.default_credit_card}
else
- 1
{}
end
end
- 2
protected
- 2
def load!
- 10
self.collection = if @subscription.present?
- 1
@subscription.raw_object.transactions
elsif @credit_card.present?
- 4
Braintree::Transaction.search {|search| search.payment_method_token.is @credit_card.token}
elsif @customer.present?
- 12
Braintree::Transaction.search {|search| search.customer_id.is @customer.id}
else
- 1
Braintree::Transaction.search
end
- 10
super
end
end
end
- 2
module BraintreeRails
- 2
module Validations
- 2
module ClassMethods
- 2
def self.extended(receiver)
- 13
receiver.class_eval do
- 13
include ::ActiveModel::Validations
- 13
define_model_callbacks :persist
- 13
validates_with validator_class
end
end
- 2
def validator_class
- 13
name.concat("Validator").constantize
end
end
- 2
module InstanceMethods
- 2
def save(options = {})
- 23
run_callbacks :persist do
- 23
perform_validations(options) ? super : false
end
end
- 2
def save!(options = {})
- 38
run_callbacks :persist do
- 38
perform_validations(options) ? super : raise(RecordInvalid.new(self))
end
end
- 2
def perform_validations(options={})
- 61
perform_validation = options[:validate] != false
- 61
perform_validation ? valid?(options[:context]) : true
end
end
- 2
def self.included(receiver)
- 13
receiver.extend ClassMethods
- 13
receiver.send :include, InstanceMethods
end
end
end
- 2
module BraintreeRails
- 2
class Validator < ActiveModel::Validator
- 2
def self.setup(&block)
- 17
reset_validations
- 17
set_validations(collect_validations(&block))
end
- 2
def self.reset_validations
- 17
model_class.reset_callbacks(:validate)
end
- 2
def self.set_validations(validations)
- 17
validations.each do |validation|
- 67
model_class.validates(*validation)
end
end
- 2
def self.default_validations
- 17
self::Validations.deep_dup
end
- 2
def self.collect_validations(&block)
- 17
block.present? ? block.call(default_validations) : default_validations
end
- 2
def self.model_class
- 86
name.chomp('Validator').constantize
end
- 2
def setup(*)
- 13
self.class.setup
end
- 2
def validate(record)
end
end
end
- 2
module BraintreeRails
- 2
Version = "1.1.0"
end
- 2
ROOT_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))
- 2
LIB_PATH = File.join(ROOT_PATH, 'lib')
- 2
$LOAD_PATH.unshift(LIB_PATH)