supercharged 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Alexander Balashov
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # Supercharged
2
+
3
+ [![Build Status](https://travis-ci.org/divineforest/supercharged.png?branch=master)](https://travis-ci.org/divineforest/supercharged)
4
+ [![CodeClimate](https://codeclimate.com/github/divineforest/supercharged.png)](https://codeclimate.com/github/divineforest/supercharged)
5
+
6
+ Complete MVC solution to accept charges from users on your Ruby on Rails site
7
+
8
+ ## Installation
9
+
10
+ Add to Gemfile:
11
+
12
+ ```ruby
13
+ gem 'supercharged'
14
+ ```
15
+
16
+ run
17
+
18
+ rails g supercharged:migrations
19
+ rails db:migrate
20
+ rails g supercharged:views
21
+
22
+ In your application.js manifest:
23
+
24
+ ```
25
+ //= require supercharged
26
+ ```
27
+
28
+ Create config/initializers/supercharged.rb
29
+
30
+ ```ruby
31
+ ActiveMerchant::Billing::Base.integration_mode = Rails.env.production? ? :production : :test
32
+ ```
33
+
34
+ Add
35
+
36
+ ```ruby
37
+ supercharged
38
+ ```
39
+
40
+ to your routes.rb somewhere in draw block.
41
+
42
+ # Using
43
+
44
+ Create view in app/views/supercharged/charges/new.html.haml
45
+
46
+ ```haml
47
+ = charge_form_for(:paypal, account: 'yourpaypalaccountid', html: {}) do |service|
48
+ - service.description 'Write here description that will be shown in paymennt form'
49
+ = charge_form_amount_field(service)
50
+ = submit_tag 'Pay now'
51
+ ```
52
+
53
+ # Customization
54
+
55
+ ## Controller
56
+
57
+ Create controller in app/controllers/charges_controller.rb and inherit from Supercharged::ChargesController.
58
+ Then add what you need or change existing methods with 'super'.
59
+
60
+ ```ruby
61
+ class ChargesController < Supercharged::ChargesController
62
+ before_filter :authenticate_user! # this is Devise's authenticate method
63
+ end
64
+ ```
65
+
66
+ If you create your own controllers then you need to customize routing method:
67
+
68
+ ```
69
+ supercharged controllers: {charges: :charges, gateway_notifications: :gateway_notifications}
70
+ ```
71
+
72
+ ## Model
73
+
74
+ Create model in app/models/charge.rb and inherit from Supercharged::Charge::Base
75
+
76
+ ```ruby
77
+ class Charge < Supercharged::Charge::Base
78
+ # your custom code here
79
+
80
+ def approve(real_amount)
81
+ transaction do
82
+ # update user balance with your own update_balance method or other things you want to do after charged approved
83
+ user.update_balance(real_amount)
84
+ super
85
+ end
86
+ end
87
+ end
88
+ ```
89
+
90
+ # Contributing
91
+
92
+ The example app is at https://github.com/divineforest/supercharged-example-app
93
+
94
+ # License
95
+
96
+ Supercharged is released under the MIT License
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ task :default => :test
7
+
8
+ Rake::TestTask.new do |t|
9
+ t.libs << "lib"
10
+ t.libs << "test"
11
+ t.test_files = FileList["test/**/*_test.rb"]
12
+ t.verbose = true
13
+ end
@@ -0,0 +1,43 @@
1
+ class ChargeForm
2
+ constructor: (selector, options = {}) ->
3
+ @form = $(selector)
4
+ return if @form.length == 0
5
+
6
+ @amount_input = @form.find("[role='charge-amount']")
7
+ @id_input = @form.find("[value='<%= Supercharged::ChargesHelper::FAKE_ORDER_ID %>']")
8
+
9
+ @form.submit =>
10
+ @start_payment()
11
+
12
+ unless parseInt(@id_input.val())
13
+ alert("Error: undefined charge id")
14
+ return false
15
+
16
+ start_payment: ->
17
+ @create_internal_transaction(
18
+ success: (charge) =>
19
+ @prepare_gateway_form(charge)
20
+ )
21
+
22
+ create_internal_transaction: (options) ->
23
+ charge_attributes = @get_charge_attributes()
24
+ $.ajax(
25
+ url: "/charges.json",
26
+ type: "POST",
27
+ async: false,
28
+ data: { charge: charge_attributes},
29
+ success: (response, a) ->
30
+ options.success(response)
31
+ )
32
+
33
+ get_charge_attributes: ->
34
+ {
35
+ amount: @amount_input.val()
36
+ }
37
+
38
+ prepare_gateway_form: (charge) ->
39
+ @id_input.val(charge.id)
40
+
41
+ $ ->
42
+ window.widgets ||= {}
43
+ window.widgets.charge_form = new ChargeForm("[role='gateway-charge-form']")
@@ -0,0 +1 @@
1
+ //= require_directory .
@@ -0,0 +1,19 @@
1
+ class Supercharged::ChargesController < ApplicationController
2
+
3
+ def new
4
+ end
5
+
6
+ def create
7
+ @charge = Charge.new(charge_params)
8
+ @charge.user = current_user
9
+ @charge.save!
10
+ render json: @charge.as_json(only: [:id])
11
+ end
12
+
13
+ private
14
+
15
+ def charge_params
16
+ params.require(:charge).permit(:amount)
17
+ end
18
+
19
+ end
@@ -0,0 +1,53 @@
1
+ class Supercharged::GatewayNotificationsController < ApplicationController
2
+ skip_before_filter :verify_authenticity_token
3
+
4
+ def create
5
+ persistent_logger.info("Notification for #{params[:gateway]}")
6
+ persistent_logger.info("params = #{params.inspect}")
7
+
8
+ @notification = GatewayNotification.create!(params: params, gateway: params[:gateway], raw_post: request.raw_post)
9
+ @notification.logger = persistent_logger
10
+
11
+ error = if !@notification.complete?
12
+ "not_completed"
13
+ elsif !@notification.acknowledge
14
+ "acknowledge_failed"
15
+ elsif !@notification.charge
16
+ "charge not found"
17
+ end
18
+
19
+ if error
20
+ persistent_logger.error("Error: #{error.inspect}")
21
+ if @notification.charge
22
+ @notification.charge.failed!
23
+ @notification.charge.update_attribute(:error, error)
24
+ end
25
+ head :bad_request
26
+ else
27
+ persistent_logger.info("Success")
28
+ @notification.approve
29
+ if @notification.need_response?
30
+ persistent_logger.info("Need need_response: #{@notification.success_response.inspect}")
31
+ render text: @notification.success_response
32
+ else
33
+ persistent_logger.info("Redirecting")
34
+ redirect_to root_url
35
+ end
36
+ end
37
+ end
38
+
39
+ def success
40
+ redirect_to root_url, notice: "Success"
41
+ end
42
+
43
+ def fail
44
+ redirect_to root_url, error: "Fail"
45
+ end
46
+
47
+ private
48
+
49
+ def persistent_logger
50
+ @persistent_logger ||= Logger.new("log/supercharged/gateway_notifications.log")
51
+ end
52
+
53
+ end
@@ -0,0 +1,45 @@
1
+ module Supercharged::ChargesHelper
2
+ # No order id while generating form. It will be added later via JS
3
+ # JS finds order input by this fake id because id and name will be integration specific
4
+ FAKE_ORDER_ID = "[payment_order_id]"
5
+
6
+ DEFAULT_AMOUNT_FIELD_OPTIONS = {
7
+ role: "charge-amount",
8
+ required: true,
9
+ min: 0
10
+ }
11
+
12
+ def charge_form_for(service_name, options = {}, &block)
13
+ raise ArgumentError, "Missing block" unless block_given?
14
+
15
+ default_options = {service: service_name}
16
+ options.merge!(default_options)
17
+
18
+ options = with_default_html_options(options)
19
+
20
+ account = options.delete(:account)
21
+ notify_url = gateways_result_url(service_name)
22
+
23
+ payment_service_for(FAKE_ORDER_ID, account, options) do |service|
24
+ service.notify_url notify_url
25
+ block.call(service)
26
+ end
27
+ end
28
+
29
+ def charge_form_amount_field(service, options = {})
30
+ amount_field_name = service.mappings[:amount] || raise("Undefined amount field mapping")
31
+
32
+ options = options.merge(DEFAULT_AMOUNT_FIELD_OPTIONS)
33
+
34
+ number_field_tag amount_field_name, nil, options
35
+ end
36
+
37
+ private
38
+
39
+ def with_default_html_options(options)
40
+ options[:html] ||= {}
41
+ options[:html].merge!(role: "gateway-charge-form")
42
+ options
43
+ end
44
+
45
+ end
@@ -0,0 +1,2 @@
1
+ class Charge < Supercharged::Charge::Base
2
+ end
@@ -0,0 +1,55 @@
1
+ require 'active_merchant'
2
+
3
+ class GatewayNotification < ActiveRecord::Base
4
+ class EmptyChargeIdError < ArgumentError;end
5
+
6
+ belongs_to :charge
7
+
8
+ serialize :params
9
+
10
+ before_create :set_charge_id
11
+
12
+ attr_accessor :raw_post, :logger
13
+
14
+ def acknowledge
15
+ adapter.acknowledge
16
+ end
17
+
18
+ def complete?
19
+ adapter.complete?
20
+ end
21
+
22
+ def need_response?
23
+ adapter.respond_to?(:success_response)
24
+ end
25
+
26
+ def success_response
27
+ adapter.respond_to?(:success_response) ? adapter.success_response : "OK"
28
+ end
29
+
30
+ def approve
31
+ logger.info "real amount = #{real_amount}"
32
+ charge.approve(real_amount) unless charge.ok?
33
+ end
34
+
35
+ def real_amount
36
+ params[service.mappings[:amount]]
37
+ end
38
+
39
+ private
40
+
41
+ def adapter
42
+ @adapter ||= "ActiveMerchant::Billing::Integrations::#{gateway.classify}::Notification".classify.constantize.new(raw_post)
43
+ rescue NameError
44
+ raise "Unknown integration '#{gateway}'"
45
+ end
46
+
47
+ def service
48
+ "ActiveMerchant::Billing::Integrations::#{gateway.classify}::Helper".classify.constantize
49
+ end
50
+
51
+ def set_charge_id
52
+ self.charge_id = adapter.item_id || raise(EmptyChargeIdError)
53
+ end
54
+
55
+ end
@@ -0,0 +1,3 @@
1
+ class PaymentStateTransition < ActiveRecord::Base
2
+ belongs_to :payment
3
+ end
@@ -0,0 +1,45 @@
1
+ module Supercharged
2
+ module Charge
3
+ class Base < ActiveRecord::Base
4
+ include ActiveModel::ForbiddenAttributesProtection
5
+
6
+ self.table_name = "charges"
7
+ self.abstract_class = true
8
+
9
+ belongs_to :user
10
+ has_many :gateway_input_notifications
11
+
12
+ validates :amount, presence: true
13
+
14
+ scope :latest, order("created_at DESC")
15
+
16
+ state_machine :state, initial: :new do
17
+ # store_audit_trail
18
+
19
+ state :new
20
+ state :rejected
21
+ state :ok
22
+ state :error
23
+
24
+ event :set_ok do
25
+ transition [:new, :error] => :ok
26
+ end
27
+
28
+ event :failed do
29
+ transition [:new] => :error
30
+ end
31
+
32
+ event :reject do
33
+ transition [:new, :error] => :rejected
34
+ end
35
+ end
36
+
37
+ # require implicit amount from gateway, not from user
38
+ def approve(real_amount)
39
+ self.real_amount = real_amount
40
+ set_ok!
41
+ end
42
+
43
+ end
44
+ end
45
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,17 @@
1
+ module ActionDispatch::Routing
2
+ class Mapper
3
+
4
+ def supercharged(options = {})
5
+ controllers = {
6
+ charges: "supercharged/charges",
7
+ gateway_notifications: "supercharged/gateway_notifications"
8
+ }
9
+ controllers.merge!(options[:controllers]) if options[:controllers]
10
+
11
+ resources :charges, only: [:new, :create], controller: controllers[:charges]
12
+
13
+ match "gateways/:gateway/result" => "#{controllers[:gateway_notifications]}#create", as: :gateways_result
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ require 'active_merchant'
2
+ require 'active_merchant/billing/integrations/action_view_helper'
3
+
4
+ ActionView::Base.send(:include, ActiveMerchant::Billing::Integrations::ActionViewHelper)
@@ -0,0 +1,3 @@
1
+ module Supercharged
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config/routes'))
2
+ require 'supercharged/activemerchant'
3
+
4
+ require 'state_machine'
5
+
6
+ module Supercharged
7
+ class Engine < Rails::Engine
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :supercharged do
3
+ # # Task goes here
4
+ # end
data/test/fake_app.rb ADDED
@@ -0,0 +1,94 @@
1
+ require 'active_record'
2
+ require 'action_controller/railtie'
3
+
4
+ # database
5
+ if ENV['TRAVIS'].present?
6
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'postgresql', :database => 'supercharged_test', :username => "postgres"}}
7
+ else
8
+ ActiveRecord::Base.configurations = {'test' => {:adapter => 'sqlite3', :database => ':memory:'}}
9
+ end
10
+ ActiveRecord::Base.establish_connection('test')
11
+
12
+ # config
13
+ app = Class.new(Rails::Application)
14
+ app.config.secret_token = "3b7cd727ee24e8444053437c36cc66c4"
15
+ app.config.session_store :cookie_store, :key => "_fakeapp_session"
16
+ app.config.active_support.deprecation = :log
17
+ app.initialize!
18
+
19
+ Rails.application.routes.draw do
20
+ supercharged
21
+
22
+ root to: "empty#index"
23
+ end
24
+
25
+ # migrations
26
+ ActiveRecord::Base.silence do
27
+ ActiveRecord::Migration.verbose = false
28
+ ActiveRecord::Schema.define :version => 0 do
29
+
30
+ create_table "gateway_notifications", :force => true do |t|
31
+ t.text "params"
32
+ t.string "status"
33
+ t.string "external_transaction_id"
34
+ t.integer "charge_id"
35
+ t.datetime "created_at", :null => false
36
+ t.datetime "updated_at", :null => false
37
+ t.string "gateway"
38
+ end
39
+
40
+ add_index "gateway_notifications", ["charge_id"], :name => "index_gateway_input_notifications_on_charge_id"
41
+
42
+ create_table "charges_state_transitions", :force => true do |t|
43
+ t.integer "charges_id"
44
+ t.string "charges_type"
45
+ t.string "event"
46
+ t.string "from"
47
+ t.string "to"
48
+ t.datetime "created_at"
49
+ end
50
+
51
+ add_index "charges_state_transitions", ["charges_id"], :name => "index_charges_state_transitions_on_charges_id"
52
+
53
+ create_table "charges", :force => true do |t|
54
+ t.integer "amount", :null => false
55
+ t.integer "user_id", :null => false
56
+ t.string "external_transaction_id"
57
+ t.text "params"
58
+ t.string "state", :default => "new", :null => false
59
+ t.datetime "created_at", :null => false
60
+ t.datetime "updated_at", :null => false
61
+ t.integer "user_transaction_id"
62
+ t.string "error"
63
+ t.integer "approved_by"
64
+ t.text "reject_reason"
65
+ t.decimal "real_amount"
66
+ end
67
+
68
+ add_index "charges", ["approved_by"], :name => "index_charges_on_approved_by"
69
+ add_index "charges", ["state"], :name => "index_charges_on_state"
70
+ add_index "charges", ["user_id"], :name => "index_charges_on_user_id"
71
+
72
+ end
73
+ end
74
+
75
+ class ApplicationController < ActionController::Base
76
+ protect_from_forgery
77
+
78
+ helper_method :current_user
79
+
80
+ private
81
+
82
+ def current_user
83
+ raise "stub me"
84
+ end
85
+ end
86
+
87
+ class EmptyController < ApplicationController
88
+ def index
89
+ render empty: true
90
+ end
91
+ end
92
+
93
+ # helpers
94
+ Object.const_set(:ApplicationHelper, Module.new)
@@ -0,0 +1,62 @@
1
+ require 'test_helper'
2
+
3
+ describe Supercharged::GatewayNotificationsController do
4
+ describe "create action" do
5
+ let(:charge) { Charge.create!({user_id: 1, amount: 10}, without_protection: true) }
6
+
7
+ context "authorized" do
8
+ let(:fake_user) { stub(id: 1) }
9
+
10
+ before do
11
+ GatewayNotification.any_instance.stubs(:current_user).returns(fake_user)
12
+ end
13
+
14
+ context "correct conditions" do
15
+ it "works with good notification" do
16
+ adapter = stub(item_id: 1, "complete?" => true, acknowledge: true, charge: charge)
17
+
18
+ GatewayNotification.any_instance.stubs(:adapter).returns(adapter)
19
+
20
+ post :create, gateway: "webmoney"
21
+
22
+ charge.reload
23
+ charge.state_name.must_equal :ok
24
+
25
+ assert_response :redirect, "/"
26
+ end
27
+ end
28
+
29
+ context "bad conditions" do
30
+
31
+ it "completed = false" do
32
+ adapter = stub(item_id: 1, "complete?" => false, acknowledge: true, charge: charge)
33
+
34
+ GatewayNotification.any_instance.stubs(:adapter).returns(adapter)
35
+
36
+ post :create, gateway: "webmoney"
37
+
38
+ charge.reload
39
+ charge.state_name.must_equal :error
40
+ charge.error.must_equal "not_completed"
41
+
42
+ assert_response :bad_request
43
+ end
44
+
45
+ it "acknowledge = false" do
46
+ adapter = stub(item_id: 1, "complete?" => true, acknowledge: false, charge: charge)
47
+
48
+ GatewayNotification.any_instance.stubs(:adapter).returns(adapter)
49
+
50
+ post :create, gateway: "webmoney"
51
+
52
+ charge.reload
53
+ charge.state_name.must_equal :error
54
+ charge.error.must_equal "acknowledge_failed"
55
+
56
+ assert_response :bad_request
57
+ end
58
+
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ describe Charge do
4
+ describe "validations" do
5
+ subject { Charge.new }
6
+ it "amount is required" do
7
+ subject.valid?
8
+
9
+ subject.errors[:amount][0].must_equal "can't be blank"
10
+ end
11
+ end
12
+
13
+ describe "states" do
14
+ subject { Charge.create!({user_id: 1, amount: 10}, without_protection: true) }
15
+
16
+ describe "#approve" do
17
+ it "changes state and real_amount" do
18
+ subject.approve(5)
19
+
20
+ subject.real_amount.must_equal 5
21
+ subject.state_name.must_equal :ok
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ describe GatewayNotification do
4
+ describe "create" do
5
+ it "raise EmptyChargeId if charge_id = nil" do
6
+ ->{
7
+ GatewayNotification.create!(gateway: "webmoney")
8
+ }.must_raise GatewayNotification::EmptyChargeIdError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+
3
+ require "minitest/autorun"
4
+ require "minitest/spec"
5
+ require "minitest/pride"
6
+ require "minitest-spec-context"
7
+ require "mocha/setup"
8
+
9
+ require 'rails'
10
+ require 'active_record'
11
+ require 'action_view'
12
+ # require 'action_controller'
13
+
14
+ require "rails/test_help"
15
+ require "minitest/rails"
16
+
17
+ require 'state_machine'
18
+ require 'state_machine-audit_trail'
19
+ require 'strong_parameters'
20
+
21
+ require "supercharged"
22
+ require "fake_app"
metadata ADDED
@@ -0,0 +1,203 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: supercharged
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - divineforest
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2013-05-07 00:00:00 +04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :runtime
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 3
28
+ - 1
29
+ version: "3.1"
30
+ name: rails
31
+ requirement: *id001
32
+ prerelease: false
33
+ - !ruby/object:Gem::Dependency
34
+ type: :runtime
35
+ version_requirements: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ name: state_machine
43
+ requirement: *id002
44
+ prerelease: false
45
+ - !ruby/object:Gem::Dependency
46
+ type: :runtime
47
+ version_requirements: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ name: state_machine-audit_trail
55
+ requirement: *id003
56
+ prerelease: false
57
+ - !ruby/object:Gem::Dependency
58
+ type: :runtime
59
+ version_requirements: &id004 !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ name: activemerchant
67
+ requirement: *id004
68
+ prerelease: false
69
+ - !ruby/object:Gem::Dependency
70
+ type: :runtime
71
+ version_requirements: &id005 !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ name: strong_parameters
79
+ requirement: *id005
80
+ prerelease: false
81
+ - !ruby/object:Gem::Dependency
82
+ type: :development
83
+ version_requirements: &id006 !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ name: sqlite3
91
+ requirement: *id006
92
+ prerelease: false
93
+ - !ruby/object:Gem::Dependency
94
+ type: :development
95
+ version_requirements: &id007 !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ~>
98
+ - !ruby/object:Gem::Version
99
+ segments:
100
+ - 3
101
+ - 0
102
+ version: "3.0"
103
+ name: minitest
104
+ requirement: *id007
105
+ prerelease: false
106
+ - !ruby/object:Gem::Dependency
107
+ type: :development
108
+ version_requirements: &id008 !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ segments:
113
+ - 0
114
+ version: "0"
115
+ name: minitest-spec-context
116
+ requirement: *id008
117
+ prerelease: false
118
+ - !ruby/object:Gem::Dependency
119
+ type: :development
120
+ version_requirements: &id009 !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ segments:
125
+ - 0
126
+ version: "0"
127
+ name: minitest-rails
128
+ requirement: *id009
129
+ prerelease: false
130
+ - !ruby/object:Gem::Dependency
131
+ type: :development
132
+ version_requirements: &id010 !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ segments:
137
+ - 0
138
+ version: "0"
139
+ name: mocha
140
+ requirement: *id010
141
+ prerelease: false
142
+ description:
143
+ email:
144
+ executables: []
145
+
146
+ extensions: []
147
+
148
+ extra_rdoc_files: []
149
+
150
+ files:
151
+ - app/assets/javascripts/charge_form.js.coffee.erb
152
+ - app/assets/javascripts/supercharged.js
153
+ - app/controllers/supercharged/charges_controller.rb
154
+ - app/controllers/supercharged/gateway_notifications_controller.rb
155
+ - app/helpers/supercharged/charges_helper.rb
156
+ - app/models/charge.rb
157
+ - app/models/gateway_notification.rb
158
+ - app/models/payment_state_transition.rb
159
+ - app/models/supercharged/charge/base.rb
160
+ - config/routes.rb
161
+ - lib/supercharged/activemerchant.rb
162
+ - lib/supercharged/version.rb
163
+ - lib/supercharged.rb
164
+ - lib/tasks/supercharged_tasks.rake
165
+ - MIT-LICENSE
166
+ - Rakefile
167
+ - README.md
168
+ has_rdoc: true
169
+ homepage:
170
+ licenses: []
171
+
172
+ post_install_message:
173
+ rdoc_options: []
174
+
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ segments:
182
+ - 0
183
+ version: "0"
184
+ required_rubygems_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ segments:
189
+ - 0
190
+ version: "0"
191
+ requirements: []
192
+
193
+ rubyforge_project:
194
+ rubygems_version: 1.3.6
195
+ signing_key:
196
+ specification_version: 3
197
+ summary: MVC solution for charges in rails
198
+ test_files:
199
+ - test/fake_app.rb
200
+ - test/supercharged/controllers/gateway_notifications_controller_test.rb
201
+ - test/supercharged/models/charge_test.rb
202
+ - test/supercharged/models/geneway_notification_test.rb
203
+ - test/test_helper.rb