Merge pull request #5879 from luisramos0/payments

[Bye bye Spree] Bring models payment_method, credit_card and gateway from spree_core
This commit is contained in:
Luis Ramos
2020-08-26 22:09:16 +01:00
committed by GitHub
14 changed files with 803 additions and 144 deletions

View File

@@ -0,0 +1,155 @@
# frozen_string_literal: true
module Spree
class CreditCard < ActiveRecord::Base
belongs_to :payment_method
belongs_to :user
has_many :payments, as: :source
before_save :set_last_digits
attr_accessor :verification_value
attr_reader :number
attr_writer :save_requested_by_customer # For holding customer preference in memory
validates :month, :year, numericality: { only_integer: true }
validates :number, presence: true, unless: :has_payment_profile?, on: :create
validates :verification_value, presence: true, unless: :has_payment_profile?, on: :create
validate :expiry_not_in_the_past
after_create :ensure_single_default_card
after_save :ensure_single_default_card, if: :default_card_needs_updating?
scope :with_payment_profile, -> { where('gateway_customer_profile_id IS NOT NULL') }
# needed for some of the ActiveMerchant gateways (eg. SagePay)
alias_attribute :brand, :cc_type
def expiry=(expiry)
self[:month], self[:year] = expiry.split(" / ")
self[:year] = "20" + self[:year]
end
def number=(num)
@number = begin
num.gsub(/[^0-9]/, '')
rescue StandardError
nil
end
end
# cc_type is set by jquery.payment, which helpfully provides different
# types from Active Merchant. Converting them is necessary.
def cc_type=(type)
real_type = case type
when 'mastercard', 'maestro'
'master'
when 'amex'
'american_express'
when 'dinersclub'
'diners_club'
else
type
end
self[:cc_type] = real_type
end
def set_last_digits
number.to_s.gsub!(/\s/, '')
verification_value.to_s.gsub!(/\s/, '')
self.last_digits ||= number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1)
end
def name?
first_name? && last_name?
end
def name
"#{first_name} #{last_name}"
end
def verification_value?
verification_value.present?
end
# Show the card number, with all but last 4 numbers replace with "X". (XXXX-XXXX-XXXX-4338)
def display_number
"XXXX-XXXX-XXXX-#{last_digits}"
end
def actions
%w{capture void credit}
end
# Indicates whether its possible to capture the payment
def can_capture?(payment)
payment.pending? || payment.checkout?
end
# Indicates whether its possible to void the payment.
def can_void?(payment)
!payment.void?
end
# Indicates whether its possible to credit the payment. Note that most gateways require that the
# payment be settled first which generally happens within 12-24 hours of the transaction.
def can_credit?(payment)
return false unless payment.completed?
return false unless payment.order.payment_state == 'credit_owed'
payment.credit_allowed.positive?
end
# Allows us to use a gateway_payment_profile_id to store Stripe Tokens
def has_payment_profile?
gateway_customer_profile_id.present? || gateway_payment_profile_id.present?
end
def to_active_merchant
ActiveMerchant::Billing::CreditCard.new(
number: number,
month: month,
year: year,
verification_value: verification_value,
first_name: first_name,
last_name: last_name
)
end
def save_requested_by_customer?
!!@save_requested_by_customer
end
private
def expiry_not_in_the_past
return unless year.present? && month.present?
time = "#{year}-#{month}-1".to_time
return unless time < Time.zone.now.to_time.beginning_of_month
errors.add(:base, :card_expired)
end
def reusable?
gateway_customer_profile_id.present?
end
def default_missing?
!user.credit_cards.exists?(is_default: true)
end
def default_card_needs_updating?
is_default_changed? || gateway_customer_profile_id_changed?
end
def ensure_single_default_card
return unless user
return unless is_default? || (reusable? && default_missing?)
user.credit_cards.update_all(['is_default=(id=?)', id])
self.is_default = true
end
end
end

View File

@@ -1,47 +0,0 @@
Spree::CreditCard.class_eval do
# For holding customer preference in memory
attr_writer :save_requested_by_customer
# Should be able to remove once we reach Spree v2.2.0
# https://github.com/spree/spree/commit/411010f3975c919ab298cb63962ee492455b415c
belongs_to :payment_method
belongs_to :user
after_create :ensure_single_default_card
after_save :ensure_single_default_card, if: :default_card_needs_updating?
# Allows us to use a gateway_payment_profile_id to store Stripe Tokens
# Should be able to remove once we reach Spree v2.2.0
# Commit: https://github.com/spree/spree/commit/5a4d690ebc64b264bf12904a70187e7a8735ef3f
# See also: https://github.com/spree/spree_gateway/issues/111
def has_payment_profile? # rubocop:disable Naming/PredicateName
gateway_customer_profile_id.present? || gateway_payment_profile_id.present?
end
def save_requested_by_customer?
!!@save_requested_by_customer
end
private
def reusable?
gateway_customer_profile_id.present?
end
def default_missing?
!user.credit_cards.exists?(is_default: true)
end
def default_card_needs_updating?
is_default_changed? || gateway_customer_profile_id_changed?
end
def ensure_single_default_card
return unless user
return unless is_default? || (reusable? && default_missing?)
user.credit_cards.update_all(['is_default=(id=?)', id])
self.is_default = true
end
end

View File

@@ -0,0 +1,62 @@
# frozen_string_literal: true
require 'spree/concerns/payment_method_distributors'
module Spree
class Gateway < PaymentMethod
include Spree::PaymentMethodDistributors
delegate_belongs_to :provider, :authorize, :purchase, :capture, :void, :credit
validates :name, :type, presence: true
# Default to live
preference :server, :string, default: 'live'
preference :test_mode, :boolean, default: false
def payment_source_class
CreditCard
end
# instantiates the selected gateway and configures with the options stored in the database
def self.current
super
end
def provider
gateway_options = options
gateway_options.delete :login if gateway_options.key?(:login) && gateway_options[:login].nil?
if gateway_options[:server]
ActiveMerchant::Billing::Base.gateway_mode = gateway_options[:server].to_sym
end
@provider ||= provider_class.new(gateway_options)
end
def options
preferences.each_with_object({}){ |(key, value), memo| memo[key.to_sym] = value; }
end
def method_missing(method, *args)
if @provider.nil? || !@provider.respond_to?(method)
super
else
provider.__send__(method, *args)
end
end
def payment_profiles_supported?
false
end
def method_type
'gateway'
end
def supports?(source)
return true unless provider_class.respond_to? :supports?
return false unless source.brand
provider_class.supports?(source.brand)
end
end
end

View File

@@ -0,0 +1,102 @@
# frozen_string_literal: true
module Spree
class Gateway
class Bogus < Spree::Gateway
TEST_VISA = ['4111111111111111', '4012888888881881', '4222222222222'].freeze
TEST_MC = ['5500000000000004', '5555555555554444', '5105105105105100'].freeze
TEST_AMEX = ['378282246310005', '371449635398431',
'378734493671000', '340000000000009'].freeze
TEST_DISC = ['6011000000000004', '6011111111111117', '6011000990139424'].freeze
VALID_CCS = ['1', TEST_VISA, TEST_MC, TEST_AMEX, TEST_DISC].flatten
attr_accessor :test
def provider_class
self.class
end
def preferences
{}
end
def create_profile(payment)
# simulate the storage of credit card profile using remote service
success = VALID_CCS.include? payment.source.number
payment.source.update(gateway_customer_profile_id: generate_profile_id(success))
end
def authorize(_money, credit_card, _options = {})
profile_id = credit_card.gateway_customer_profile_id
if VALID_CCS.include?(credit_card.number) || profile_id&.starts_with?('BGS-')
ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {},
test: true, authorization: '12345',
avs_result: { code: 'A' })
else
ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure',
{ message: 'Bogus Gateway: Forced failure' },
test: true)
end
end
def purchase(_money, credit_card, _options = {})
profile_id = credit_card.gateway_customer_profile_id
if VALID_CCS.include?(credit_card.number) || profile_id&.starts_with?('BGS-')
ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {},
test: true, authorization: '12345',
avs_result: { code: 'A' })
else
ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure',
message: 'Bogus Gateway: Forced failure',
test: true)
end
end
def credit(_money, _credit_card, _response_code, _options = {})
ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {},
test: true, authorization: '12345')
end
def capture(authorization, _credit_card, _gateway_options)
if authorization.response_code == '12345'
ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {},
test: true, authorization: '67890')
else
ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure',
error: 'Bogus Gateway: Forced failure', test: true)
end
end
def void(_response_code, _credit_card, _options = {})
ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {},
test: true, authorization: '12345')
end
def test?
# Test mode is not really relevant with bogus gateway (no such thing as live server)
true
end
def payment_profiles_supported?
true
end
def actions
%w(capture void credit)
end
private
def generate_profile_id(success)
record = true
prefix = success ? 'BGS' : 'FAIL'
while record
random = "#{prefix}-#{Array.new(6){ rand(6) }.join}"
record = CreditCard.find_by(gateway_customer_profile_id: random)
end
random
end
end
end
end

View File

@@ -0,0 +1,36 @@
# frozen_string_literal: true
# Bogus Gateway that doesn't support payment profiles
module Spree
class Gateway
class BogusSimple < Spree::Gateway::Bogus
def payment_profiles_supported?
false
end
def authorize(_money, credit_card, _options = {})
if VALID_CCS.include? credit_card.number
ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {},
test: true, authorization: '12345',
avs_result: { code: 'A' })
else
ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure',
{ message: 'Bogus Gateway: Forced failure' },
test: true)
end
end
def purchase(_money, credit_card, _options = {})
if VALID_CCS.include? credit_card.number
ActiveMerchant::Billing::Response.new(true, 'Bogus Gateway: Forced success', {},
test: true, authorization: '12345',
avs_result: { code: 'A' })
else
ActiveMerchant::Billing::Response.new(false, 'Bogus Gateway: Forced failure',
message: 'Bogus Gateway: Forced failure',
test: true)
end
end
end
end
end

View File

@@ -1,9 +0,0 @@
require 'spree/concerns/payment_method_distributors'
Spree::Gateway.class_eval do
include Spree::PaymentMethodDistributors
# Default to live
preference :server, :string, default: 'live'
preference :test_mode, :boolean, default: false
end

View File

@@ -0,0 +1,137 @@
# frozen_string_literal: true
require 'spree/concerns/payment_method_distributors'
module Spree
class PaymentMethod < ActiveRecord::Base
include Spree::Core::CalculatedAdjustments
include Spree::PaymentMethodDistributors
acts_as_taggable
acts_as_paranoid
DISPLAY = [:both, :front_end, :back_end].freeze
default_scope -> { where(deleted_at: nil) }
has_many :credit_cards, class_name: "Spree::CreditCard"
validates :name, presence: true
validate :distributor_validation
after_initialize :init
scope :production, -> { where(environment: 'production') }
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
where(nil)
else
joins(:distributors).
where('distributors_payment_methods.distributor_id IN (?)',
user.enterprises.select(&:id)).
select('DISTINCT spree_payment_methods.*')
end
}
scope :for_distributors, ->(distributors) {
non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors })
where(id: non_unique_matches.map(&:id))
}
scope :for_distributor, lambda { |distributor|
joins(:distributors).
where('enterprises.id = ?', distributor)
}
scope :for_subscriptions, -> { where(type: Subscription::ALLOWED_PAYMENT_METHOD_TYPES) }
scope :by_name, -> { order('spree_payment_methods.name ASC') }
scope :available, lambda { |display_on = 'both'|
where(active: true).
where('spree_payment_methods.display_on=? OR spree_payment_methods.display_on=? OR spree_payment_methods.display_on IS NULL', display_on, '').
where('spree_payment_methods.environment=? OR spree_payment_methods.environment=? OR spree_payment_methods.environment IS NULL', Rails.env, '')
}
def self.providers
Rails.application.config.spree.payment_methods
end
def provider_class
raise 'You must implement provider_class method for this gateway.'
end
# The class that will process payments for this payment type, used for @payment.source
# e.g. CreditCard in the case of a the Gateway payment type
# nil means the payment method doesn't require a source e.g. check
def payment_source_class
raise 'You must implement payment_source_class method for this gateway.'
end
def self.active?
where(type: to_s, environment: Rails.env, active: true).count.positive?
end
def method_type
type.demodulize.downcase
end
def self.find_with_destroyed(*args)
unscoped { find(*args) }
end
def payment_profiles_supported?
false
end
def source_required?
true
end
def auto_capture?
Spree::Config[:auto_capture]
end
def supports?(_source)
true
end
def init
unless reflections.key?(:calculator)
self.class.include Spree::Core::CalculatedAdjustments
end
self.calculator ||= Calculator::FlatRate.new(preferred_amount: 0)
end
def has_distributor?(distributor)
distributors.include?(distributor)
end
def self.clean_name
case name
when "Spree::PaymentMethod::Check"
"Cash/EFT/etc. (payments for which automatic validation is not required)"
when "Spree::Gateway::Migs"
"MasterCard Internet Gateway Service (MIGS)"
when "Spree::Gateway::Pin"
"Pin Payments"
when "Spree::Gateway::StripeConnect"
"Stripe"
when "Spree::Gateway::StripeSCA"
"Stripe SCA"
when "Spree::Gateway::PayPalExpress"
"PayPal Express"
else
i = name.rindex('::') + 2
name[i..-1]
end
end
private
def distributor_validation
validates_with DistributorsValidator
end
end
end

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
module Spree
class PaymentMethod
class Check < Spree::PaymentMethod
def actions
%w{capture void}
end
# Indicates whether its possible to capture the payment
def can_capture?(payment)
['checkout', 'pending'].include?(payment.state)
end
# Indicates whether its possible to void the payment.
def can_void?(payment)
payment.state != 'void'
end
def capture(*_args)
ActiveMerchant::Billing::Response.new(true, "", {}, {})
end
def void(*_args)
ActiveMerchant::Billing::Response.new(true, "", {}, {})
end
def source_required?
false
end
end
end
end

View File

@@ -1,84 +0,0 @@
require 'spree/concerns/payment_method_distributors'
Spree::PaymentMethod.class_eval do
include Spree::Core::CalculatedAdjustments
include Spree::PaymentMethodDistributors
acts_as_taggable
has_many :credit_cards, class_name: "Spree::CreditCard" # from Spree v.2.3.0 d470b31798f37
after_initialize :init
validate :distributor_validation
# -- Scopes
scope :managed_by, lambda { |user|
if user.has_spree_role?('admin')
where(nil)
else
joins(:distributors).
where('distributors_payment_methods.distributor_id IN (?)', user.enterprises.select(&:id)).
select('DISTINCT spree_payment_methods.*')
end
}
scope :for_distributors, ->(distributors) {
non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors })
where(id: non_unique_matches.map(&:id))
}
scope :for_distributor, lambda { |distributor|
joins(:distributors).
where('enterprises.id = ?', distributor)
}
scope :for_subscriptions, -> { where(type: Subscription::ALLOWED_PAYMENT_METHOD_TYPES) }
scope :by_name, -> { order('spree_payment_methods.name ASC') }
# Rewrite Spree's ruby-land class method as a scope
scope :available, lambda { |display_on = 'both'|
where(active: true).
where('spree_payment_methods.display_on=? OR spree_payment_methods.display_on=? OR spree_payment_methods.display_on IS NULL', display_on, '').
where('spree_payment_methods.environment=? OR spree_payment_methods.environment=? OR spree_payment_methods.environment IS NULL', Rails.env, '')
}
def init
unless reflections.key?(:calculator)
self.class.include Spree::Core::CalculatedAdjustments
end
self.calculator ||= Calculator::FlatRate.new(preferred_amount: 0)
end
def has_distributor?(distributor)
distributors.include?(distributor)
end
def self.clean_name
case name
when "Spree::PaymentMethod::Check"
"Cash/EFT/etc. (payments for which automatic validation is not required)"
when "Spree::Gateway::Migs"
"MasterCard Internet Gateway Service (MIGS)"
when "Spree::Gateway::Pin"
"Pin Payments"
when "Spree::Gateway::StripeConnect"
"Stripe"
when "Spree::Gateway::StripeSCA"
"Stripe SCA"
when "Spree::Gateway::PayPalExpress"
"PayPal Express"
else
i = name.rindex('::') + 2
name[i..-1]
end
end
private
def distributor_validation
validates_with DistributorsValidator
end
end

View File

@@ -18,9 +18,6 @@ Spree::Gateway.class_eval do
acts_as_taggable
end
require "#{Rails.root}/app/models/spree/payment_method_decorator"
require "#{Rails.root}/app/models/spree/gateway_decorator"
Spree.config do |config|
config.shipping_instructions = true
config.address_requires_state = true

View File

@@ -81,7 +81,8 @@ feature '
end
scenario "updating a payment method", js: true do
payment_method = create(:payment_method, distributors: [@distributors[0]])
payment_method = create(:payment_method, distributors: [@distributors[0]],
calculator: build(:calculator_flat_rate))
login_as_admin_and_visit spree.edit_admin_payment_method_path payment_method
fill_in 'payment_method_name', with: 'New PM Name'

View File

@@ -2,6 +2,220 @@ require 'spec_helper'
module Spree
describe CreditCard do
describe "original specs from Spree" do
let(:valid_credit_card_attributes) {
{
number: '4111111111111111',
verification_value: '123',
month: 12,
year: Time.zone.now.year + 1
}
}
def self.payment_states
Spree::Payment.state_machine.states.keys
end
def stub_rails_env(environment)
allow(Rails).to receive_messages(env: ActiveSupport::StringInquirer.new(environment))
end
let(:credit_card) { Spree::CreditCard.new }
before(:each) do
@order = create(:order)
@payment = create(:payment, amount: 100, order: @order)
@success_response = double('gateway_response', success?: true,
authorization: '123',
avs_result: { 'code' => 'avs-code' })
@fail_response = double('gateway_response', success?: false)
@payment_gateway = create(:payment_method,
environment: 'test')
allow(@payment_gateway).to receive_messages :payment_profiles_supported? => true,
:authorize => @success_response,
:purchase => @success_response,
:capture => @success_response,
:void => @success_response,
:credit => @success_response
allow(@payment).to receive_messages payment_method: @payment_gateway
end
context "#can_capture?" do
it "should be true if payment is pending" do
payment = create(:payment, created_at: Time.zone.now)
allow(payment).to receive(:pending?) { true }
expect(credit_card.can_capture?(payment)).to be_truthy
end
it "should be true if payment is checkout" do
payment = create(:payment, created_at: Time.zone.now)
allow(payment).to receive_messages :pending? => false,
:checkout? => true
expect(credit_card.can_capture?(payment)).to be_truthy
end
end
context "#can_void?" do
it "should be true if payment is not void" do
payment = create(:payment)
allow(payment).to receive(:void?) { false }
expect(credit_card.can_void?(payment)).to be_truthy
end
end
context "#can_credit?" do
it "should be false if payment is not completed" do
payment = create(:payment)
allow(payment).to receive(:completed?) { false }
expect(credit_card.can_credit?(payment)).to be_falsy
end
it "should be false when order payment_state is not 'credit_owed'" do
payment = create(:payment,
order: create(:order, payment_state: 'paid'))
allow(payment).to receive(:completed?) { true }
expect(credit_card.can_credit?(payment)).to be_falsy
end
it "should be false when credit_allowed is zero" do
payment = create(:payment,
order: create(:order, payment_state: 'credit_owed'))
allow(payment).to receive_messages :completed? => true,
:credit_allowed => 0
expect(credit_card.can_credit?(payment)).to be_falsy
end
end
context "#valid?" do
it "should validate presence of number" do
credit_card.attributes = valid_credit_card_attributes.except(:number)
expect(credit_card).to_not be_valid
expect(credit_card.errors[:number]).to eq ["can't be blank"]
end
it "should validate presence of security code" do
credit_card.attributes = valid_credit_card_attributes.except(:verification_value)
expect(credit_card).to_not be_valid
expect(credit_card.errors[:verification_value]).to eq ["can't be blank"]
end
it "should validate expiration is not in the past" do
credit_card.month = 1.month.ago.month
credit_card.year = 1.month.ago.year
expect(credit_card).to_not be_valid
expect(credit_card.errors[:base]).to eq ["has expired"]
end
it "does not run expiration in the past validation if month is not set" do
credit_card.month = nil
credit_card.year = Time.zone.now.year
expect(credit_card).to_not be_valid
expect(credit_card.errors[:base]).to be_blank
end
it "does not run expiration in the past validation if year is not set" do
credit_card.month = Time.zone.now.month
credit_card.year = nil
expect(credit_card).to_not be_valid
expect(credit_card.errors[:base]).to be_blank
end
it "does not run expiration in the past validation if year and month are empty" do
credit_card.year = ""
credit_card.month = ""
expect(credit_card).to_not be_valid
expect(credit_card.errors[:card]).to be_blank
end
it "should only validate on create" do
credit_card.attributes = valid_credit_card_attributes
credit_card.save
expect(credit_card).to be_valid
end
end
context "#save" do
before do
credit_card.attributes = valid_credit_card_attributes
credit_card.save!
end
let!(:persisted_card) { Spree::CreditCard.find(credit_card.id) }
it "should not actually store the number" do
expect(persisted_card.number).to be_blank
end
it "should not actually store the security code" do
expect(persisted_card.verification_value).to be_blank
end
end
context "#number=" do
it "should strip non-numeric characters from card input" do
credit_card.number = "6011000990139424"
expect(credit_card.number).to eq "6011000990139424"
credit_card.number = " 6011-0009-9013-9424 "
expect(credit_card.number).to eq "6011000990139424"
end
it "should not raise an exception on non-string input" do
credit_card.number = ({})
expect(credit_card.number).to be_nil
end
end
context "#cc_type=" do
it "converts between the different types" do
credit_card.cc_type = 'mastercard'
expect(credit_card.cc_type).to eq 'master'
credit_card.cc_type = 'maestro'
expect(credit_card.cc_type).to eq 'master'
credit_card.cc_type = 'amex'
expect(credit_card.cc_type).to eq 'american_express'
credit_card.cc_type = 'dinersclub'
expect(credit_card.cc_type).to eq 'diners_club'
credit_card.cc_type = 'some_outlandish_cc_type'
expect(credit_card.cc_type).to eq 'some_outlandish_cc_type'
end
end
context "#associations" do
it "should be able to access its payments" do
expect { credit_card.payments.to_a }.not_to raise_error
end
end
context "#to_active_merchant" do
before do
credit_card.number = "4111111111111111"
credit_card.year = Time.zone.now.year
credit_card.month = Time.zone.now.month
credit_card.first_name = "Bob"
credit_card.last_name = "Boblaw"
credit_card.verification_value = 123
end
it "converts to an ActiveMerchant::Billing::CreditCard object" do
am_card = credit_card.to_active_merchant
expect(am_card.number).to eq "4111111111111111"
expect(am_card.year).to eq Time.zone.now.year
expect(am_card.month).to eq Time.zone.now.month
expect(am_card.first_name).to eq "Bob"
am_card.last_name = "Boblaw"
expect(am_card.verification_value).to eq 123
end
end
end
describe "setting default credit card for a user" do
let(:user) { create(:user) }
let(:onetime_card_attrs) do

View File

@@ -0,0 +1,23 @@
# frozen_string_literal: true
require 'spec_helper'
describe Spree::Gateway do
class Provider
def initialize(options); end
def imaginary_method; end
end
class TestGateway < Spree::Gateway
def provider_class
Provider
end
end
it "passes through all arguments on a method_missing call" do
gateway = TestGateway.new
expect(gateway.provider).to receive(:imaginary_method).with('foo')
gateway.imaginary_method('foo')
end
end

View File

@@ -1,7 +1,46 @@
require 'spec_helper'
class Spree::Gateway::Test < Spree::Gateway
end
module Spree
describe PaymentMethod do
describe "#available" do
let(:enterprise) { create(:enterprise) }
before do
Spree::PaymentMethod.delete_all
[nil, 'both', 'front_end', 'back_end'].each do |display_on|
Spree::Gateway::Test.create(
name: 'Display Both',
display_on: display_on,
active: true,
environment: 'test',
description: 'foofah',
distributors: [enterprise]
)
end
expect(Spree::PaymentMethod.all.size).to eq 4
end
it "should return all methods available to front-end/back-end when no parameter is passed" do
expect(Spree::PaymentMethod.available.size).to eq 2
end
it "should return all methods available to front-end/back-end when display_on = :both" do
expect(Spree::PaymentMethod.available(:both).size).to eq 2
end
it "should return all methods available to front-end when display_on = :front_end" do
expect(Spree::PaymentMethod.available(:front_end).size).to eq 2
end
it "should return all methods available to back-end when display_on = :back_end" do
expect(Spree::PaymentMethod.available(:back_end).size).to eq 2
end
end
it "orders payment methods by name" do
pm1 = create(:payment_method, name: 'ZZ')
pm2 = create(:payment_method, name: 'AA')