diff --git a/app/models/spree/credit_card.rb b/app/models/spree/credit_card.rb index f075de0e14..7f6b41bcb4 100644 --- a/app/models/spree/credit_card.rb +++ b/app/models/spree/credit_card.rb @@ -11,9 +11,9 @@ module Spree before_save :set_last_digits - attr_accessor :number, :verification_value - # For holding customer preference in memory - attr_writer :save_requested_by_customer + 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 @@ -53,7 +53,7 @@ module Spree 'diners_club' else type - end + end self[:cc_type] = real_type end @@ -94,13 +94,13 @@ module Spree !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. + # 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 > 0 + payment.credit_allowed.positive? end # Allows us to use a gateway_payment_profile_id to store Stripe Tokens @@ -126,12 +126,12 @@ module Spree private def expiry_not_in_the_past - if year.present? && month.present? - time = "#{year}-#{month}-1".to_time - if time < Time.zone.now.to_time.beginning_of_month - errors.add(:base, :card_expired) - end - end + 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? diff --git a/app/models/spree/gateway.rb b/app/models/spree/gateway.rb index 283a8458de..216f0cfe6b 100644 --- a/app/models/spree/gateway.rb +++ b/app/models/spree/gateway.rb @@ -40,7 +40,7 @@ module Spree if @provider.nil? || !@provider.respond_to?(method) super else - provider.send(method, *args) + provider.__send__(method, *args) end end diff --git a/app/models/spree/gateway/bogus.rb b/app/models/spree/gateway/bogus.rb index 2efa234fe9..2a844a0ace 100644 --- a/app/models/spree/gateway/bogus.rb +++ b/app/models/spree/gateway/bogus.rb @@ -1,87 +1,102 @@ # frozen_string_literal: true module Spree - class Gateway::Bogus < 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 + module 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 + VALID_CCS = ['1', TEST_VISA, TEST_MC, TEST_AMEX, TEST_DISC].flatten - attr_accessor :test + 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) + def provider_class + self.class 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) + def preferences + {} 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) + 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 - 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.where(gateway_customer_profile_id: random).first + 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 - random end end end diff --git a/app/models/spree/gateway/bogus_simple.rb b/app/models/spree/gateway/bogus_simple.rb index 0a9d64c1a0..62938e438f 100644 --- a/app/models/spree/gateway/bogus_simple.rb +++ b/app/models/spree/gateway/bogus_simple.rb @@ -2,24 +2,34 @@ # Bogus Gateway that doesn't support payment profiles module Spree - class Gateway::BogusSimple < 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) + module Gateway + class BogusSimple < Spree::Gateway::Bogus + def payment_profiles_supported? + false 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) + 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 diff --git a/app/models/spree/payment_method.rb b/app/models/spree/payment_method.rb index c659c9a47a..a799eaebdd 100644 --- a/app/models/spree/payment_method.rb +++ b/app/models/spree/payment_method.rb @@ -28,7 +28,8 @@ module Spree where(nil) else joins(:distributors). - where('distributors_payment_methods.distributor_id IN (?)', user.enterprises.select(&:id)). + where('distributors_payment_methods.distributor_id IN (?)', + user.enterprises.select(&:id)). select('DISTINCT spree_payment_methods.*') end } @@ -78,7 +79,7 @@ module Spree end def self.active? - where(type: to_s, environment: Rails.env, active: true).count > 0 + where(type: to_s, environment: Rails.env, active: true).count.positive? end def method_type diff --git a/app/models/spree/payment_method/check.rb b/app/models/spree/payment_method/check.rb index 8ebdd19fc7..15be0202b1 100644 --- a/app/models/spree/payment_method/check.rb +++ b/app/models/spree/payment_method/check.rb @@ -1,31 +1,33 @@ # frozen_string_literal: true module Spree - class PaymentMethod::Check < PaymentMethod - def actions - %w{capture void} - end + module 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 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 + # 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 capture(*_args) + ActiveMerchant::Billing::Response.new(true, "", {}, {}) + end - def void(*_args) - ActiveMerchant::Billing::Response.new(true, "", {}, {}) - end + def void(*_args) + ActiveMerchant::Billing::Response.new(true, "", {}, {}) + end - def source_required? - false + def source_required? + false + end end end end diff --git a/spec/models/spree/credit_card_spec.rb b/spec/models/spree/credit_card_spec.rb index 930cefa995..87b5daf62d 100644 --- a/spec/models/spree/credit_card_spec.rb +++ b/spec/models/spree/credit_card_spec.rb @@ -3,7 +3,14 @@ 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 } } + 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 @@ -19,7 +26,9 @@ module Spree @order = create(:order) @payment = Spree::Payment.create(amount: 100, order: @order) - @success_response = double('gateway_response', success?: true, authorization: '123', avs_result: { 'code' => 'avs-code' }) + @success_response = double('gateway_response', success?: true, + authorization: '123', + avs_result: { 'code' => 'avs-code' }) @fail_response = double('gateway_response', success?: false) @payment_gateway = mock_model(Spree::PaymentMethod, @@ -41,7 +50,9 @@ module Spree end it "should be true if payment is checkout" do - payment = mock_model(Spree::Payment, pending?: false, checkout?: true, created_at: Time.zone.now) + payment = mock_model(Spree::Payment, pending?: false, + checkout?: true, + created_at: Time.zone.now) credit_card.can_capture?(payment).should be_true end end @@ -60,12 +71,16 @@ module Spree end it "should be false when order payment_state is not 'credit_owed'" do - payment = mock_model(Spree::Payment, completed?: true, order: mock_model(Spree::Order, payment_state: 'paid')) + payment = mock_model(Spree::Payment, + completed?: true, + order: mock_model(Spree::Order, payment_state: 'paid')) credit_card.can_credit?(payment).should be_false end it "should be false when credit_allowed is zero" do - payment = mock_model(Spree::Payment, completed?: true, credit_allowed: 0, order: mock_model(Spree::Order, payment_state: 'credit_owed')) + payment = mock_model(Spree::Payment, + completed?: true, credit_allowed: 0, + order: mock_model(Spree::Order, payment_state: 'credit_owed')) credit_card.can_credit?(payment).should be_false end end @@ -74,20 +89,20 @@ module Spree it "should validate presence of number" do credit_card.attributes = valid_credit_card_attributes.except(:number) credit_card.should_not be_valid - credit_card.errors[:number].should == ["can't be blank"] + 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) credit_card.should_not be_valid - credit_card.errors[:verification_value].should == ["can't be blank"] + 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 credit_card.should_not be_valid - credit_card.errors[:base].should == ["Card has expired"] + expect(credit_card.errors[:base]).to eq ["Card has expired"] end it "does not run expiration in the past validation if month is not set" do @@ -138,10 +153,10 @@ module Spree context "#number=" do it "should strip non-numeric characters from card input" do credit_card.number = "6011000990139424" - credit_card.number.should == "6011000990139424" + expect(credit_card.number).to eq "6011000990139424" credit_card.number = " 6011-0009-9013-9424 " - credit_card.number.should == "6011000990139424" + expect(credit_card.number).to eq "6011000990139424" end it "should not raise an exception on non-string input" do @@ -153,19 +168,19 @@ module Spree context "#cc_type=" do it "converts between the different types" do credit_card.cc_type = 'mastercard' - credit_card.cc_type.should == 'master' + expect(credit_card.cc_type).to eq 'master' credit_card.cc_type = 'maestro' - credit_card.cc_type.should == 'master' + expect(credit_card.cc_type).to eq 'master' credit_card.cc_type = 'amex' - credit_card.cc_type.should == 'american_express' + expect(credit_card.cc_type).to eq 'american_express' credit_card.cc_type = 'dinersclub' - credit_card.cc_type.should == 'diners_club' + expect(credit_card.cc_type).to eq 'diners_club' credit_card.cc_type = 'some_outlandish_cc_type' - credit_card.cc_type.should == 'some_outlandish_cc_type' + expect(credit_card.cc_type).to eq 'some_outlandish_cc_type' end end @@ -187,12 +202,12 @@ module Spree it "converts to an ActiveMerchant::Billing::CreditCard object" do am_card = credit_card.to_active_merchant - am_card.number.should == "4111111111111111" - am_card.year.should == Time.zone.now.year - am_card.month.should == Time.zone.now.month - am_card.first_name.should == "Bob" + 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" - am_card.verification_value.should == 123 + expect(am_card.verification_value).to eq 123 end end end