diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..5800638
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Rails Dog LLC nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/Rakefile b/Rakefile
index 2070887..09dbc4e 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,120 +1,31 @@
-# I think this is the one that should be moved to the extension Rakefile template
-
-# In rails 1.2, plugins aren't available in the path until they're loaded.
-# Check to see if the rspec plugin is installed first and require
-# it if it is. If not, use the gem version.
-
-# Determine where the RSpec plugin is by loading the boot
-unless defined? SPREE_ROOT
- ENV["RAILS_ENV"] = "test"
- case
- when ENV["SPREE_ENV_FILE"]
- require File.dirname(ENV["SPREE_ENV_FILE"]) + "/boot"
- when File.dirname(__FILE__) =~ %r{vendor/SPREE/vendor/extensions}
- require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
- else
- require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
- end
-end
+require File.expand_path('../../config/application', __FILE__)
+require 'rubygems'
require 'rake'
-require 'rake/rdoctask'
require 'rake/testtask'
+require 'rake/packagetask'
+require 'rake/gempackagetask'
-rspec_base = File.expand_path(SPREE_ROOT + '/vendor/plugins/rspec/lib')
-$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
-require 'spec/rake/spectask'
-# require 'spec/translator'
+spec = eval(File.read('spree_paypal_express.gemspec'))
-# Cleanup the SPREE_ROOT constant so specs will load the environment
-Object.send(:remove_const, :SPREE_ROOT)
-
-extension_root = File.expand_path(File.dirname(__FILE__))
-
-task :default => :spec
-task :stats => "spec:statsetup"
-
-desc "Run all specs in spec directory"
-Spec::Rake::SpecTask.new(:spec) do |t|
- t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
- t.spec_files = FileList["#{extension_root}/spec/**/*_spec.rb"]
+Rake::GemPackageTask.new(spec) do |p|
+ p.gem_spec = spec
end
-namespace :spec do
- desc "Run all specs in spec directory with RCov"
- Spec::Rake::SpecTask.new(:rcov) do |t|
- t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
- t.spec_files = FileList['spec/**/*_spec.rb']
- t.rcov = true
- t.rcov_opts = ['--exclude', 'spec', '--rails']
- end
-
- desc "Print Specdoc for all specs"
- Spec::Rake::SpecTask.new(:doc) do |t|
- t.spec_opts = ["--format", "specdoc", "--dry-run"]
- t.spec_files = FileList['spec/**/*_spec.rb']
- end
-
- [:models, :controllers, :views, :helpers].each do |sub|
- desc "Run the specs under spec/#{sub}"
- Spec::Rake::SpecTask.new(sub) do |t|
- t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
- t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
- end
- end
-
- # Hopefully no one has written their extensions in pre-0.9 style
- # desc "Translate specs from pre-0.9 to 0.9 style"
- # task :translate do
- # translator = ::Spec::Translator.new
- # dir = RAILS_ROOT + '/spec'
- # translator.translate(dir, dir)
- # end
-
- # Setup specs for stats
- task :statsetup do
- require 'code_statistics'
- ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
- ::STATS_DIRECTORIES << %w(View\ specs spec/views)
- ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
- ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
- ::CodeStatistics::TEST_TYPES << "Model specs"
- ::CodeStatistics::TEST_TYPES << "View specs"
- ::CodeStatistics::TEST_TYPES << "Controller specs"
- ::CodeStatistics::TEST_TYPES << "Helper specs"
- ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
- end
-
- namespace :db do
- namespace :fixtures do
- desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
- task :load => :environment do
- require 'active_record/fixtures'
- ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
- (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
- Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
- end
- end
- end
- end
+desc "Release to gemcutter"
+task :release => :package do
+ require 'rake/gemcutter'
+ Rake::Gemcutter::Tasks.new(spec).define
+ Rake::Task['gem:push'].invoke
end
-desc 'Generate documentation for the paypal_express extension.'
-Rake::RDocTask.new(:rdoc) do |rdoc|
- rdoc.rdoc_dir = 'rdoc'
- rdoc.title = 'PaypalExpressExtension'
- rdoc.options << '--line-numbers' << '--inline-source'
- rdoc.rdoc_files.include('README')
- rdoc.rdoc_files.include('lib/**/*.rb')
-end
+desc "Default Task"
+task :default => [ :spec ]
-# For extensions that are in transition
-desc 'Test the paypal_express extension.'
-Rake::TestTask.new(:test) do |t|
- t.libs << 'lib'
- t.pattern = 'test/**/*_test.rb'
- t.verbose = true
-end
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new
-# Load any custom rakefiles for extension
-Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
\ No newline at end of file
+# require 'cucumber/rake/task'
+# Cucumber::Rake::Task.new do |t|
+# t.cucumber_opts = %w{--format pretty}
+# end
\ No newline at end of file
diff --git a/app/models/paypal_account.rb b/app/models/paypal_account.rb
index 0bbdc8d..e58d28f 100644
--- a/app/models/paypal_account.rb
+++ b/app/models/paypal_account.rb
@@ -8,23 +8,10 @@ class PaypalAccount < ActiveRecord::Base
def capture(payment)
authorization = find_authorization(payment)
- ppx_response = payment.payment_method.provider.capture((100 * payment.amount).to_i, authorization.transaction_id)
- if ppx_response.success?
- PaypalTxn.create(:payment => payment,
- :txn_type => PaypalTxn::TxnType::CAPTURE,
- :amount => ppx_response.params["gross_amount"].to_f,
- :message => ppx_response.params["message"],
- :payment_status => ppx_response.params["payment_status"],
- :pending_reason => ppx_response.params["pending_reason"],
- :transaction_id => ppx_response.params["transaction_id"],
- :transaction_type => ppx_response.params["transaction_type"],
- :payment_type => ppx_response.params["payment_type"],
- :response_code => ppx_response.params["ack"],
- :token => ppx_response.params["token"],
- :avs_response => ppx_response.avs_result["code"],
- :cvv_response => ppx_response.cvv_result["code"])
-
- payment.finalize!
+ ppx_response = payment.payment_method.provider.capture((100 * payment.amount).to_i, authorization.params["transaction_id"])
+ if ppx_response.success?
+ record_log payment, ppx_response
+ payment.complete
else
gateway_error(ppx_response.message)
end
@@ -32,37 +19,30 @@ class PaypalAccount < ActiveRecord::Base
end
def can_capture?(payment)
- !echeck?(payment) && find_capture(payment).nil?
+ !echeck?(payment) && payment.state == "pending"
end
def credit(payment, amount=nil)
authorization = find_capture(payment)
- amount ||= payment.order.outstanding_credit
- ppx_response = payment.payment_method.provider.credit(amount.nil? ? (100 * amount).to_i : (100 * amount).to_i, authorization.transaction_id)
+
+ amount = payment.credit_allowed >= payment.order.outstanding_balance.abs ? payment.order.outstanding_balance : payment.credit_allowed
+
+ ppx_response = payment.payment_method.provider.credit(amount.nil? ? (100 * amount).to_i : (100 * amount).to_i, authorization.params['transaction_id'])
if ppx_response.success?
- PaypalTxn.new(:payment => payment,
- :txn_type => PaypalTxn::TxnType::CREDIT,
- :amount => ppx_response.params["gross_refund_amount"].to_f,
- :message => ppx_response.params["message"],
- :payment_status => "Refunded",
- :pending_reason => ppx_response.params["pending_reason"],
- :transaction_id => ppx_response.params["refund_transaction_id"],
- :transaction_type => ppx_response.params["transaction_type"],
- :payment_type => ppx_response.params["payment_type"],
- :response_code => ppx_response.params["ack"],
- :token => ppx_response.params["token"],
- :avs_response => ppx_response.avs_result["code"],
- :cvv_response => ppx_response.cvv_result["code"])
-
+ record_log payment, ppx_response
payment.update_attribute(:amount, payment.amount - amount)
- payment.order.update_totals!
+ payment.complete
+ payment.order.update!
else
gateway_error(ppx_response.message)
end
end
def can_credit?(payment)
+ return false unless payment.state == "completed"
+ return false unless payment.order.payment_state == "credit_owed"
+ payment.credit_allowed > 0
!find_capture(payment).nil?
end
@@ -70,24 +50,44 @@ class PaypalAccount < ActiveRecord::Base
def payment_gateway
false
end
-
+
+ def record_log(payment, response)
+ payment.log_entries.create(:details => response.to_yaml)
+ end
+
private
def find_authorization(payment)
- #find the transaction associated with the original authorization/capture
- payment.txns.find(:first,
- :conditions => {:pending_reason => "authorization", :payment_status => "Pending", :txn_type => PaypalTxn::TxnType::AUTHORIZE.to_s},
- :order => 'created_at DESC')
+ logs = payment.log_entries.all(:order => 'created_at DESC')
+ logs.each do |log|
+ details = YAML.load(log.details) # return the transaction details
+ if (details.params['payment_status'] == 'Pending' && details.params['pending_reason'] == 'authorization')
+ return details
+ end
+ end
+ return nil
end
def find_capture(payment)
#find the transaction associated with the original authorization/capture
- payment.txns.find(:first,
- :conditions => {:payment_status => "Completed", :txn_type => PaypalTxn::TxnType::CAPTURE.to_s},
- :order => 'created_at DESC')
+ logs = payment.log_entries.all(:order => 'created_at DESC')
+ logs.each do |log|
+ details = YAML.load(log.details) # return the transaction details
+ if details.params['payment_status'] == 'Completed'
+ return details
+ end
+ end
+ return nil
end
-
+
def echeck?(payment)
- payment.txns.exists?(:payment_type => "echeck")
+ logs = payment.log_entries.all(:order => 'created_at DESC')
+ logs.each do |log|
+ details = YAML.load(log.details) # return the transaction details
+ if details.params['payment_type'] == 'echeck'
+ return true
+ end
+ end
+ return false
end
def gateway_error(text)
diff --git a/app/views/admin/payments/source_views/_paypalexpress.html.erb b/app/views/admin/payments/source_views/_paypalexpress.html.erb
index a5b79a0..0b349b9 100644
--- a/app/views/admin/payments/source_views/_paypalexpress.html.erb
+++ b/app/views/admin/payments/source_views/_paypalexpress.html.erb
@@ -31,40 +31,41 @@