spree_batch_capture 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ # Add your extension routes here
3
+ end
@@ -0,0 +1,10 @@
1
+ class AddLastProcessingErrorToPayments < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :payments, :last_processing_error, :string
4
+ end
5
+
6
+ def self.down
7
+ remove_column :payments, :last_processing_error
8
+
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ module SpreeBatchCapture
2
+ module Error
3
+ class InvalidWorker < StandardError; end
4
+ class UnexpectedWorkerError < StandardError; end
5
+ end
6
+ end
@@ -0,0 +1,98 @@
1
+ require 'resque'
2
+ #require 'resque/plugins/lock'
3
+
4
+ module SpreeBatchCapture
5
+ class Worker::Base
6
+ #extend Resque::Plugins::Lock
7
+
8
+ # Actual method called by Resque.
9
+ # This method cleans up any options and allows a consistent interface
10
+ # for the worker's run method.
11
+ def self.perform(options={})
12
+ begin
13
+ options.symbolize_keys!
14
+ if before_run(options)
15
+ result = run(options)
16
+ return after_run(result, options)
17
+ else
18
+ return false
19
+ end
20
+ rescue => e
21
+ handle_error(e)
22
+ end
23
+ end
24
+
25
+ # Override to do any modifications or validation
26
+ # before running the job. Job will fail if before_run
27
+ # returns false.
28
+ def self.before_run(options)
29
+ return true
30
+ end
31
+
32
+ # Override to do any post run checking. Receives the
33
+ # result (true/false) of the run and the options
34
+ # which may have been altered by the run. Job will fail if
35
+ # after_run returns false
36
+ def self.after_run(result, options)
37
+ return true
38
+ end
39
+
40
+ # Override to handle any exceptions that come up during the execution of
41
+ # the job. Returning false will fail the job, while returning true
42
+ # will indicate that the job was successful.
43
+ def self.handle_error(exception)
44
+ return false
45
+ end
46
+
47
+ # Implemented by subclasses and performs the actual work of the worker.
48
+ def self.run(options)
49
+ return true
50
+ end
51
+
52
+ # Use enqueue to add a job to the queue to be captured.
53
+ # Returns the result of the enqueue and the queue name as an array.
54
+ def self.enqueue(options, custom_queue_name=nil)
55
+ queue_name = custom_queue_name || default_queue_name || worker_klass_name
56
+
57
+ # Resque.enqueue_to is currently supported only in the master branch
58
+ # of the gem and not included in any gem. When it is, the following line
59
+ # should work.
60
+ #added = ::Resque.enqueue_to(queue_name, worker_class, options)
61
+
62
+ #Until then, we have to do this work-around:
63
+ @queue = queue_name
64
+
65
+ added = ::Resque.enqueue(worker_class, options)
66
+ [ added, queue_name ]
67
+ end
68
+
69
+ # Override this in the subclass to provide the name of the queue
70
+ def self.worker_klass_name
71
+ return "Base"
72
+ end
73
+
74
+ # Provides a default queue name. Returning nil will default to the class name.
75
+ def self.default_queue_name
76
+ return nil
77
+ end
78
+
79
+ private
80
+
81
+ def self.worker_class
82
+ begin
83
+ @worker_class = "SpreeBatchCapture::Worker::#{worker_klass_name.camelize}".constantize
84
+ rescue
85
+ raise Error::InvalidWorker.new "Worker class name (#{worker_klass_name.camelize}) doesn't match a valid worker."
86
+ end
87
+ end
88
+
89
+
90
+ # Override the default lock for resque-lock. The out-of-the-box
91
+ # lock doesn't work for this case.
92
+ def self.lock(options)
93
+ "lock:#{default_queue_name || worker_klass_name}::#{options}"
94
+ end
95
+
96
+
97
+ end
98
+ end
@@ -0,0 +1,14 @@
1
+ class SpreeBatchCapture::Worker::Bogus < SpreeBatchCapture::Worker::Base
2
+
3
+ def self.run(options)
4
+ return true
5
+ end
6
+
7
+ def self.worker_klass_name
8
+ return "Bogus"
9
+ end
10
+
11
+ def self.default_queue_name
12
+ return "bogus"
13
+ end
14
+ end
@@ -0,0 +1,53 @@
1
+ module SpreeBatchCapture
2
+ class Worker::Capture < Worker::Base
3
+
4
+ def self.run(options)
5
+ order = options[:order]
6
+
7
+ return true unless order.payment_state == "balance_due"
8
+
9
+ if order.payments.nil? || ( order.payments && order.payments.empty? )
10
+ raise UnexpectedWorkerError.new "Attempted to capture an order without any payments."
11
+ else
12
+
13
+ order.payments.each do |payment|
14
+ payment_source = payment.source
15
+ if payment_source.can_capture? payment
16
+ begin
17
+ payment_source.capture(payment)
18
+ rescue => e
19
+ payment.fail
20
+ log_payment_error payment, "Error capturing payment for order #{order.number}. #{e.class} :: #{e.message}"
21
+ end
22
+
23
+ else
24
+ log_payment_error payment, "Order #{order.number} is not eligible for capture with payment #{payment.source_type} for #{payment.amount}."
25
+ end
26
+ end
27
+ end
28
+
29
+ return true
30
+
31
+ end
32
+
33
+ def self.before_run(options)
34
+ options[:order] = Order.find(options[:order_id])
35
+ end
36
+
37
+ def self.worker_klass_name
38
+ return "Capture"
39
+ end
40
+
41
+ def self.default_queue_name
42
+ return "capture"
43
+ end
44
+
45
+ private
46
+
47
+ def self.log_payment_error(payment, error)
48
+ payment.last_processing_error = error
49
+ payment.save!
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,18 @@
1
+ require 'spree_core'
2
+ require 'spree_batch_capture_hooks'
3
+
4
+ module SpreeBatchCapture
5
+ class Engine < Rails::Engine
6
+
7
+ config.autoload_paths += %W(#{config.root}/lib)
8
+
9
+ def self.activate
10
+ Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
11
+ Rails.env.production? ? require(c) : load(c)
12
+ end
13
+
14
+ end
15
+
16
+ config.to_prepare &method(:activate).to_proc
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ class BatchProcessHooks < Spree::ThemeSupport::HookListener
2
+ # custom hooks go here
3
+ end
@@ -0,0 +1,25 @@
1
+ namespace :spree_batch_capture do
2
+ desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
3
+ task :install do
4
+ Rake::Task['spree_batch_capture:install:migrations'].invoke
5
+ Rake::Task['spree_batch_capture:install:assets'].invoke
6
+ end
7
+
8
+ namespace :install do
9
+ desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
10
+ task :migrations do
11
+ source = File.join(File.dirname(__FILE__), '..', '..', 'db')
12
+ destination = File.join(Rails.root, 'db')
13
+ Spree::FileUtilz.mirror_files(source, destination)
14
+ end
15
+
16
+ desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
17
+ task :assets do
18
+ source = File.join(File.dirname(__FILE__), '..', '..', 'public')
19
+ destination = File.join(Rails.root, 'public')
20
+ puts "INFO: Mirroring assets from #{source} to #{destination}"
21
+ Spree::FileUtilz.mirror_files(source, destination)
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1 @@
1
+ # add custom rake tasks here
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spree_batch_capture
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mike Farmer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: spree_core
16
+ requirement: &16020680 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.60.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *16020680
25
+ - !ruby/object:Gem::Dependency
26
+ name: resque
27
+ requirement: &16020220 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.19.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *16020220
36
+ - !ruby/object:Gem::Dependency
37
+ name: resque-lock
38
+ requirement: &16019760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *16019760
47
+ description: Adds batch processing to Spree. Includes batch capture and batch export
48
+ of orders.
49
+ email: ''
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - config/routes.rb
55
+ - lib/spree_batch_capture_hooks.rb
56
+ - lib/tasks/install.rake
57
+ - lib/tasks/spree_batch_capture.rake
58
+ - lib/spree_batch_capture/worker/bogus.rb
59
+ - lib/spree_batch_capture/worker/capture.rb
60
+ - lib/spree_batch_capture/worker/base.rb
61
+ - lib/spree_batch_capture/error.rb
62
+ - lib/spree_batch_capture.rb
63
+ - db/migrate/20111129223646_add_last_processing_error_to_payments.rb
64
+ homepage: http://vitrue.com
65
+ licenses: []
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: 1.8.7
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements:
83
+ - none
84
+ rubyforge_project: ''
85
+ rubygems_version: 1.8.10
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Adds batch capture and export to Spree
89
+ test_files: []