nimbleshop_splitable 0.0.1.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # nimbleshop_splitable extension
2
+
3
+ This is Splitable extension for [nimbleShop](http://nimbleShop.org) .
4
+
5
+ # Documentation
6
+
7
+ Documentation is available at [http://nimbleshop.org/](http://nimbleshop.org) .
8
+
9
+ # License
10
+
11
+ nimbleshop_splitable uses [MIT license](http://www.opensource.org/licenses/mit-license.php) .
Binary file
Binary file
@@ -0,0 +1,17 @@
1
+ module NimbleshopSplitable
2
+ class PaymentsController < ::ActionController::Base
3
+
4
+ def create
5
+ order = Order.find_by_id(session[:order_id])
6
+ processor = NimbleshopSplitable::Processor.new(order: order)
7
+ error, url = processor.create_split(request: request)
8
+
9
+ respond_to do |format|
10
+ format.html do
11
+ error ? render(text: error) : redirect_to(url)
12
+ end
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,60 @@
1
+ module NimbleshopSplitable
2
+ class SplitablesController < ::Admin::PaymentMethodsController
3
+
4
+ protect_from_forgery except: [:notify]
5
+
6
+ before_filter :load_payment_method
7
+
8
+ def notify
9
+ Rails.logger.info "splitable callback received: #{params.to_yaml}"
10
+
11
+ processor = NimbleshopSplitable::Processor.new(invoice: params[:invoice])
12
+
13
+ if processor.acknowledge(params)
14
+ render nothing: true
15
+ else
16
+ Rails.logger.info "webhook with data #{params.to_yaml} was rejected. error: #{processor.errors.join(',')}"
17
+ render "error: #{error}", status: 403
18
+ end
19
+ end
20
+
21
+ def update
22
+ respond_to do |format|
23
+ if @payment_method.update_attributes(post_params[:splitable])
24
+ format.js {
25
+ flash[:notice] = "Splitable record was successfully updated"
26
+ render js: "window.location = '/admin/payment_methods'"
27
+ }
28
+ else
29
+ msg = @payment_method.errors.full_messages.first
30
+ error = %Q[alert("#{msg}")]
31
+ format.js { render js: error }
32
+ end
33
+ end
34
+ end
35
+
36
+ def destroy
37
+ respond_to do |format|
38
+ if @payment_method.destroy
39
+ format.js {
40
+ flash[:notice] = "Splitable record was successfully deleted"
41
+ render js: "window.location = '/admin/payment_methods'" #TODO hardcoded url
42
+ }
43
+ else
44
+ format.js { render js: 'Splitable record could not be deleted. Please try again later.' }
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def post_params
52
+ params.permit(splitable: [ :api_key, :api_secret, :expires_in, :mode] )
53
+ end
54
+
55
+ def load_payment_method
56
+ @payment_method = NimbleshopSplitable::Splitable.first
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,36 @@
1
+ module NimbleshopSplitable
2
+ module ExposedHelper
3
+
4
+ def nimbleshop_splitable_small_image( options = {} )
5
+ image_tag "engines/nimbleshop_splitable/splitable_small.png", {alt: 'splitable icon'}.merge(options)
6
+ end
7
+
8
+ def nimbleshop_splitable_big_image(options = {})
9
+ image_tag "engines/nimbleshop_splitable/splitable_big.png", { alt: 'splitable logo' }.merge(options)
10
+ end
11
+
12
+ def nimbleshop_splitable_image()
13
+ image_tag "engines/nimbleshop_splitable/splitable.png", alt: 'splitable logo'
14
+ end
15
+
16
+ def nimbleshop_splitable_available_payment_options_icons
17
+ return unless NimbleshopSplitable::Splitable.first
18
+ nimbleshop_splitable_small_image
19
+ end
20
+
21
+ def nimbleshop_splitable_payment_form(order)
22
+ return unless NimbleshopSplitable::Splitable.first
23
+ render partial: '/nimbleshop_splitable/payments/new', locals: {order: order}
24
+ end
25
+
26
+ def nimbleshop_splitable_crud_form
27
+ return unless NimbleshopSplitable::Splitable.first
28
+ render partial: '/nimbleshop_splitable/splitables/edit'
29
+ end
30
+
31
+ def nimbleshop_splitable_icon_for_order_payment(order)
32
+ nimbleshop_splitable_small_image height: '10px'
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ module NimbleshopSplitable
2
+ class Splitable < PaymentMethod
3
+
4
+ store_accessor :metadata, :api_key, :api_secret, :expires_in, :mode
5
+
6
+ validates_presence_of :api_key
7
+
8
+ before_save :set_mode
9
+
10
+ private
11
+
12
+ def set_mode
13
+ self.mode ||= 'test'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ <label class='radio'>
2
+ <%= radio_button_tag 'payment_choice', 'splitable' %>
3
+ <%= nimbleshop_splitable_image() %>
4
+ </label>
5
+
6
+ <%= form_for NimbleshopSplitable::Splitable.new, url: nimbleshop_splitable.payment_path, html: { id: 'splitable-payment-form',
7
+ class: 'form-horizontal' } do |f| %>
8
+ <% end %>
9
+
10
+ <%= javascript_tag do %>
11
+ $(function() {
12
+ $("input#payment_choice_splitable:radio").change(function() {
13
+ var $this, val;
14
+ $this = $(this);
15
+ val = $this.val();
16
+
17
+ if (val === "splitable") {
18
+ $("form#splitable-payment-form").submit();
19
+ }
20
+
21
+ });
22
+ });
23
+ <% end %>
@@ -0,0 +1,36 @@
1
+ <div class='payment-method-engine-well'>
2
+
3
+ <div>
4
+ <h2> Splitable </h2>
5
+
6
+ <div class="edit_link">
7
+ <%= link_to 'Edit', '#', class: "nimbleshop-payment-method-edit", id: "nimbleshop-splitable-payment-method-edit" %>
8
+ <%= link_to nimbleshop_splitable.splitable_path, confirm: 'Do you really want to delete Authorize.net payment method',
9
+ class: 'nimbleshop-payment-method-delete',
10
+ method: :delete,
11
+ remote: true do %>
12
+ <i class='icon-remove icon-white'></i>
13
+ <% end %>
14
+ </div>
15
+
16
+ <%= nimbleshop_splitable_big_image %>
17
+
18
+ <div class='clear'></div>
19
+ </div>
20
+
21
+
22
+ <%= render partial: '/nimbleshop_splitable/splitables/form' %>
23
+
24
+ </div>
25
+
26
+ <script>
27
+ $(function(){
28
+
29
+ $('#nimbleshop-splitable-payment-method-edit').toggle(function(){
30
+ $('#nimbleshop-splitable-form-well').show();
31
+ }, function(){
32
+ $('#nimbleshop-splitable-form-well').hide();
33
+ });
34
+
35
+ })
36
+ </script>
@@ -0,0 +1,47 @@
1
+ <div class='well nimbleshop-payment-method-form-well' id='nimbleshop-splitable-form-well' style='display:none;'>
2
+
3
+ <%= form_for NimbleshopSplitable::Splitable.first, url: '/nimbleshop_splitable/splitable',
4
+ remote: true,
5
+ html: { method: 'put',
6
+ id: 'nimbleshop-splitable-form',
7
+ class: 'nimbleshop-payment-method-form form-horizontal'} do |f| %>
8
+
9
+ <fieldset>
10
+ <div class="control-group">
11
+ <%= f.label :api_key, nil, class: 'control-label' %>
12
+ <div class="controls">
13
+ <%= f.text_field :api_key, class: 'span6' %>
14
+ </div>
15
+ </div>
16
+
17
+ <div class="control-group">
18
+ <%= f.label :api_secret, nil, class: 'control-label' %>
19
+ <div class="controls">
20
+ <%= f.text_field :api_secret, class: 'span6' %>
21
+ </div>
22
+ </div>
23
+
24
+ <div class="control-group">
25
+ <%= f.label :expires_in, nil, class: 'control-label' %>
26
+ <div class="controls">
27
+ <%= f.text_field :expires_in, class: 'span6' %>
28
+ </div>
29
+ </div>
30
+
31
+ <div class="control-group">
32
+ <div class="controls">
33
+ <label class='checkbox'>
34
+ <%= f.check_box :mode, {}, 'test', 'production' %> Enable test mode
35
+ </label>
36
+ </div>
37
+ </div>
38
+
39
+ </fieldset>
40
+
41
+ <div class="form-actions">
42
+ <%= f.submit('Submit', class: 'btn btn-primary') %>
43
+ &nbsp;
44
+ <%= link_to t(:cancel), nimbleshop_splitable.splitable_path, class: 'cancel btn' %>
45
+ </div>
46
+ <% end %>
47
+ </div>
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ NimbleshopSplitable::Engine.routes.draw do
2
+ resource :splitable do
3
+ collection do
4
+ post :notify
5
+ end
6
+ end
7
+ resource :payment
8
+ end
@@ -0,0 +1,17 @@
1
+ module NimbleshopSplitable
2
+ class Engine < ::Rails::Engine
3
+
4
+ isolate_namespace NimbleshopSplitable
5
+
6
+ config.to_prepare do
7
+ ::NimbleshopSplitable::Splitable
8
+ end
9
+
10
+ initializer 'nimbleshop_splitable_engine.action_controller' do |app|
11
+ ActiveSupport.on_load :action_controller do
12
+ helper NimbleshopSplitable::ExposedHelper
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,74 @@
1
+ module NimbleshopSplitable
2
+ class Gateway
3
+ include ActiveMerchant::PostsData
4
+
5
+ class_attribute :live_url, :test_url
6
+ self.live_url = 'https://www.splitable.com/api/splits'
7
+ self.test_url = 'https://www.splitable-draft.com/api/splits'
8
+
9
+ def initialize(splitable)
10
+ @api_key = splitable.api_key
11
+ @expires_in = splitable.expires_in
12
+ @mode = splitable.mode
13
+ end
14
+
15
+ def api_notify_url(request)
16
+ Util.localhost2public_url( '/nimbleshop_splitable/splitable/notify', 'http' )
17
+ end
18
+
19
+ def create(order, request)
20
+ params = build_params(order, request)
21
+
22
+ params[:api_key] = @api_key
23
+ params[:api_notify_url] = api_notify_url(request)
24
+ params[:expires_in] = @expires_in
25
+
26
+ unless Rails.env.production?
27
+ Rails.logger.info "params to be posted: #{params.inspect}"
28
+ end
29
+
30
+ url = test? ? self.test_url : self.live_url
31
+ params = params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
32
+
33
+ ssl_post(url, params)
34
+ end
35
+
36
+ def build_params(order, request)
37
+ params = {}
38
+ add_order_data(params, order)
39
+ add_product_data(params, order.line_items, request)
40
+ params
41
+ end
42
+
43
+ def add_order_data(params, order)
44
+ params[:total_amount] = order.total_amount_in_cents
45
+ params[:invoice] = order.number
46
+ params[:shipping] = Util.in_cents(ShippingCostCalculator.new(order).shipping_cost)
47
+ params[:tax] = Util.in_cents(TaxCalculator.new(order).tax)
48
+ params[:description] = 'See Splitable integrates nicely with nimbleShop'
49
+ end
50
+
51
+ def add_product_data(params, products, request)
52
+ products.each.with_index(1) do | item, index |
53
+ params.update(to_param(item, index, request))
54
+ end
55
+ end
56
+
57
+ def product_url(item, request)
58
+ request.protocol + request.host_with_port + "/products/#{item.product_permalink}"
59
+ end
60
+
61
+ def to_param(item, index, request)
62
+ {
63
+ "amount_#{index}" => (item.price * 100).to_i,
64
+ "item_name_#{index}" => item.product_name,
65
+ "quantity_#{index}" => item.quantity,
66
+ "url_#{index}" => product_url(item, request)
67
+ }
68
+ end
69
+
70
+ def test?
71
+ @mode == 'test'
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,96 @@
1
+ module NimbleshopSplitable
2
+ class Processor < ::Processor::Base
3
+
4
+ attr_reader :errors, :order, :payment_method
5
+
6
+ def gateway
7
+ ::NimbleshopSplitable::Gateway.new(NimbleshopSplitable::Splitable.first)
8
+ end
9
+
10
+ def initialize(options = {})
11
+
12
+ unless @order = options[:order]
13
+ invoice = options[:invoice].try(:to_s)
14
+ @order = Order.find_by_number(invoice)
15
+ end
16
+
17
+ @errors = []
18
+ @payment_method = NimbleshopSplitable::Splitable.first
19
+ end
20
+
21
+ def create_split(options = {})
22
+ options.symbolize_keys!
23
+ options.assert_valid_keys(:request)
24
+
25
+ response = gateway.create(order, options[:request])
26
+ json = ActiveSupport::JSON.decode(response)
27
+ result = json.values_at('error','split_url')
28
+ if result.last
29
+ order.update_attributes(payment_method: payment_method)
30
+ order.pending
31
+ end
32
+ result
33
+ end
34
+
35
+ def acknowledge(params = {})
36
+ if valid?(params)
37
+ send(resolve_payment_kind(params[:payment_status]), params)
38
+ else
39
+ false
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def resolve_payment_kind(payment_status)
46
+ payment_status == 'paid' ? 'purchase' : 'void'
47
+ end
48
+
49
+ def valid?(params)
50
+ @errors.clear
51
+ validate_order
52
+ validate_params(params)
53
+ @errors.empty?
54
+ end
55
+
56
+ def validate_order
57
+ unless order
58
+ @errors << "Unknown invoice number"
59
+ end
60
+ end
61
+
62
+ def validate_params(params = {})
63
+
64
+ unless params[:transaction_id]
65
+ @errors << "transaction_id is blank"
66
+ end
67
+
68
+ unless params[:payment_status]
69
+ @errors << "Parameter payment_status is blank"
70
+ end
71
+ end
72
+
73
+ def do_purchase(options = {})
74
+ add_to_order(options, 'purchased')
75
+ order.update_attributes(payment_method: payment_method)
76
+ order.purchase!
77
+
78
+ true
79
+ end
80
+
81
+ def do_void(options = {})
82
+ add_to_order(options, 'voided')
83
+ order.update_attributes(payment_method: payment_method)
84
+ order.void!
85
+
86
+ true
87
+ end
88
+
89
+ def add_to_order(params, operation)
90
+ order.payment_transactions.create(operation: operation,
91
+ success: true,
92
+ transaction_gid: params[:transaction_id],
93
+ params: params)
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,3 @@
1
+ module NimbleshopSplitable
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "nimbleshop_splitable/engine"
2
+
3
+ module NimbleshopSplitable
4
+ autoload :Processor, 'nimbleshop_splitable/processor'
5
+ autoload :Gateway, 'nimbleshop_splitable/gateway'
6
+ end
@@ -0,0 +1,29 @@
1
+ # This is a rake task that simulates what splitable will POST as callback.
2
+ #
3
+
4
+ desc "sends callback"
5
+
6
+ namespace :nimbleshop_splitable do
7
+ task :mock_callback => :environment do
8
+
9
+ unless order_number = ENV['order_number']
10
+ puts "Usage: rake mock_callcak order_number=xxxxxxx"
11
+ abort
12
+ end
13
+
14
+ base_url = 'http://localhost:3000'
15
+ endpoint = base_url + '/nimbleshop_splitable/splitable/notify'
16
+
17
+
18
+ params = { invoice: order_number,
19
+ payment_status: "cancelled",
20
+ api_secret: "540f0849518d83d6",
21
+ transaction_id: "49c380175f3c5603287698a4" }
22
+
23
+ require "net/http"
24
+ require "uri"
25
+ uri = URI.parse(endpoint)
26
+ response = Net::HTTP.post_form(uri, params)
27
+
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ namespace :nimbleshop_splitable do
2
+
3
+ desc 'load splitable record'
4
+ task :load_record => :environment do
5
+ if NimbleshopSplitable::Splitable.find_by_permalink('splitable')
6
+ puts "Splitable record already exists"
7
+ else
8
+ NimbleshopSplitable::Splitable.create!(
9
+ {
10
+ api_secret: '92746e4d66cb8993',
11
+ expires_in: 24,
12
+ api_key: '92746e4d66cb8993',
13
+ name: 'Splitable',
14
+ permalink: 'splitable',
15
+ description: %Q[<p> Splitable helps split the cost of product with friends and family. </p> <p> <a href="http://splitable.com"> more information </a> </p>]
16
+ })
17
+ puts "Splitable record was successfuly created"
18
+ end
19
+ end
20
+
21
+ desc 'copies images from engine to main rails application'
22
+ task :copy_images do
23
+ engine_name = 'nimbleshop_splitable'
24
+ origin = File.expand_path('../../app/assets/images', File.dirname(__FILE__))
25
+ destination = Rails.root.join('app', 'assets', 'images', 'engines', engine_name)
26
+ FileUtils.mkdir_p(destination) if !File.exist?(destination)
27
+ Dir[File.join(origin, '**/*')].each { |file| FileUtils.cp(file, File.join(destination) ) unless File.directory?(file) }
28
+ end
29
+
30
+
31
+ end
32
+
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nimbleshop_splitable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.rc1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Neeraj Singh
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activemerchant
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Provides Splitable functionality to nimbleShop
31
+ email:
32
+ - neeraj@BigBinary.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - app/assets/images/splitable.png
38
+ - app/assets/images/splitable_big.png
39
+ - app/assets/images/splitable_small.png
40
+ - app/controllers/nimbleshop_splitable/payments_controller.rb
41
+ - app/controllers/nimbleshop_splitable/splitables_controller.rb
42
+ - app/helpers/nimbleshop_splitable/exposed_helper.rb
43
+ - app/models/nimbleshop_splitable/splitable.rb
44
+ - app/views/nimbleshop_splitable/payments/_new.html.erb
45
+ - app/views/nimbleshop_splitable/splitables/_edit.html.erb
46
+ - app/views/nimbleshop_splitable/splitables/_form.html.erb
47
+ - config/routes.rb
48
+ - lib/nimbleshop_splitable/engine.rb
49
+ - lib/nimbleshop_splitable/gateway.rb
50
+ - lib/nimbleshop_splitable/processor.rb
51
+ - lib/nimbleshop_splitable/version.rb
52
+ - lib/nimbleshop_splitable.rb
53
+ - lib/tasks/mock_callback.rake
54
+ - lib/tasks/nimbleshop_splitable_tasks.rake
55
+ - README.md
56
+ homepage: http://nimbleShop.org
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>'
72
+ - !ruby/object:Gem::Version
73
+ version: 1.3.1
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.23
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Splitable extension for Nimbleshop
80
+ test_files: []