spree_omnikassa 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. data/.gitignore +11 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +17 -0
  4. data/Gemfile.lock +224 -0
  5. data/LICENSE +26 -0
  6. data/README.md +36 -0
  7. data/Rakefile +29 -0
  8. data/Versionfile +9 -0
  9. data/app/assets/javascripts/admin/spree_omnikassa.js +1 -0
  10. data/app/assets/javascripts/store/spree_omnikassa.js +1 -0
  11. data/app/assets/stylesheets/admin/spree_omnikassa.css +3 -0
  12. data/app/assets/stylesheets/store/spree_omnikassa.css +3 -0
  13. data/app/controllers/spree/checkout_controller_decorator.rb +10 -0
  14. data/app/controllers/spree/omnikassa_payments_controller.rb +97 -0
  15. data/app/models/spree/omnikassa_payment_request.rb +89 -0
  16. data/app/models/spree/omnikassa_payment_response.rb +129 -0
  17. data/app/models/spree/order_decorator.rb +33 -0
  18. data/app/models/spree/payment_method/omnikassa.rb +39 -0
  19. data/app/views/spree/checkout/omnikassa_edit.html.erb +36 -0
  20. data/config/locales/en.yml +5 -0
  21. data/config/routes.rb +5 -0
  22. data/lib/generators/spree_omnikassa/install/install_generator.rb +29 -0
  23. data/lib/spree_omnikassa.rb +26 -0
  24. data/script/rails +5 -0
  25. data/spec/controllers/spree/checkout_controller_spec.rb +28 -0
  26. data/spec/controllers/spree/omnikassa_payments_controller_spec.rb +198 -0
  27. data/spec/functional/spree_omnikassa_checkout_decorator_spec.rb +10 -0
  28. data/spec/integration/spree_omnikassa_checkout_spec.rb +10 -0
  29. data/spec/models/spree_omnikassa_payment_request_spec.rb +93 -0
  30. data/spec/models/spree_omnikassa_payment_response_spec.rb +144 -0
  31. data/spec/models/spree_payment_method_omnikassa_spec.rb +72 -0
  32. data/spec/spec_helper.rb +79 -0
  33. data/spree_omnikassa.gemspec +19 -0
  34. metadata +114 -0
@@ -0,0 +1,89 @@
1
+ module Spree
2
+ # OmnikassaPaymentRequest deals with the data
3
+ # for the actual request to and fro Omnikassa.
4
+ #
5
+ # Not a persistent object: will not interact or
6
+ # get saved in the database.
7
+ #
8
+ # It requires amount and order_id to be passed in
9
+ # on creation.
10
+ class OmnikassaPaymentRequest
11
+ include Spree::Core::Engine.routes.url_helpers
12
+ attr_accessor :amount, :order_id, :payment_method
13
+
14
+ def initialize(amount, transaction_reference, response_code = nil)
15
+ @payment_method = Spree::PaymentMethod::Omnikassa.fetch_payment_method
16
+ if transaction_reference.to_s.include? merchant_id
17
+ @amount = amount
18
+ @order_id = transaction_reference.to_s.match(merchant_id).post_match
19
+ @response_code = response_code
20
+ else
21
+ raise "transactionReference cannot be parsed"
22
+ end
23
+ end
24
+
25
+ # Generates datastring according to omnikassa
26
+ # requirements §9. name=value|name=value.
27
+ def data
28
+ "amount=#{amount}|orderId=#{order_id}|currencyCode=#{currency_code}|merchantId=#{merchant_id}|normalReturnUrl=#{normal_return_url}|automaticResponseUrl=#{automatic_response_url}|transactionReference=#{transaction_reference}|keyVersion=#{key_version}"
29
+ end
30
+
31
+ def interface_version
32
+ "HP_1.0"
33
+ end
34
+
35
+ def seal
36
+ ::Digest::SHA2.hexdigest(data + @payment_method.preferred_secret_key)
37
+ end
38
+
39
+ # to_s magic method simply wraps the data string generator.
40
+ def to_s
41
+ data
42
+ end
43
+
44
+ def self.build_transaction_reference order_id
45
+ @payment_method ||= Spree::PaymentMethod::Omnikassa.fetch_payment_method
46
+ @payment_method.preferred_merchant_id + order_id.to_s
47
+ end
48
+
49
+ private
50
+ # @TODO implement size and format validation acc to §9.2.
51
+
52
+ def amount
53
+ (@amount * 100).to_i
54
+ end
55
+
56
+ def order_id
57
+ @order_id
58
+ end
59
+
60
+ # @TODO implement currency lookup from locales and map to table in §9.3.
61
+ def currency_code *args
62
+ 978 #hardcoded to Euro.
63
+ end
64
+
65
+ def merchant_id
66
+ @payment_method.preferred_merchant_id
67
+ end
68
+
69
+ def normal_return_url
70
+ return_url_for_action "homecoming"
71
+ end
72
+
73
+ def automatic_response_url
74
+ return_url_for_action "reply"
75
+ end
76
+
77
+ def return_url_for_action action
78
+ url_for(:controller => 'spree/omnikassa_payments', :action => action, :host => Spree::Config.preferred_site_url)
79
+ end
80
+
81
+ def transaction_reference
82
+ Spree::OmnikassaPaymentRequest.build_transaction_reference order_id
83
+ end
84
+
85
+ def key_version
86
+ @payment_method.preferred_key_version
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,129 @@
1
+ module Spree
2
+ class OmnikassaPaymentResponse
3
+ attr_accessor :data
4
+ attr_reader :seal, :attributes, :payment_method
5
+
6
+ def initialize seal, data
7
+ @payment_method = Spree::PaymentMethod::Omnikassa.fetch_payment_method
8
+ @seal = seal
9
+ @data = data
10
+ @attributes = to_h
11
+ end
12
+
13
+ def valid?
14
+ return false unless @seal == ::Digest::SHA2.hexdigest(@data + @payment_method.preferred_secret_key)
15
+
16
+ required_attributes.each do |required_attribute|
17
+ return false unless @attributes.has_key? required_attribute.underscore.to_sym
18
+ end
19
+
20
+ true
21
+ end
22
+
23
+ # Finds a payment with provided parameters trough activeRecord.
24
+ def payment
25
+ Spree::Payment.find(:first, :conditions => {
26
+ :payment_method_id => @payment_method.id,
27
+ :order_id => @attributes[:order_id]} ) || raise(ActiveRecord::RecordNotFound)
28
+ end
29
+
30
+ # Finds the order trough ActiveRecord
31
+ def order
32
+ Spree::Order.find(@attributes[:order_id].to_i)
33
+ end
34
+
35
+ # Level can be :success, :pending, :cancelled or :failed
36
+ def response_level
37
+ response_codes.each do |level, codes|
38
+ if codes.include?(@attributes[:response_code].to_i)
39
+ return level
40
+ end
41
+ end
42
+
43
+ nil
44
+ end
45
+
46
+ private
47
+ def to_h
48
+ h = Hash.new
49
+ @data.split("|").each do |s|
50
+ k,v = s.split("=")
51
+ key = k.underscore
52
+ preparator = "prepare_#{key}"
53
+ if self.respond_to? preparator, true
54
+ v = self.send(preparator, v)
55
+ end
56
+ h[key.to_sym] = v if valid_attributes.include? k
57
+ end
58
+ h
59
+ end
60
+
61
+ # Callback for the to_h.
62
+ # Converts the amount to BigDecimal and from cents to currency.
63
+ def prepare_amount amount
64
+ BigDecimal.new(amount)/100
65
+ end
66
+
67
+ # As per "Tabel 5: Gegevenswoordenboek - beschrijving velden"
68
+ # from Rabo_OmniKassa_Integratiehandleiding_v200.pdf
69
+ def valid_attributes
70
+ %w[
71
+ amount
72
+ authorisationId
73
+ automaticResponseUrl
74
+ captureDay
75
+ captureMode
76
+ complementaryCode
77
+ complementaryInfo
78
+ currencyCode
79
+ customerLanguage
80
+ expirationdate
81
+ keyVersion
82
+ maskedPan
83
+ merchantId
84
+ normalReturnUrl
85
+ orderId
86
+ paymentMeanBrand
87
+ paymentMeanBrandList
88
+ paymentMeanType
89
+ responseCode
90
+ transactionDateTime
91
+ transactionReference
92
+ ]
93
+ end
94
+
95
+ # attributes required for working of the class.
96
+ def required_attributes
97
+ %w[
98
+ amount
99
+ transactionReference
100
+ orderId
101
+ responseCode
102
+ ]
103
+ end
104
+
105
+ def response_codes
106
+ {
107
+ :success => [00],
108
+ :pending => [
109
+ 90,
110
+ 99],
111
+ :cancelled => [
112
+ 14, #invalid CSC or CVV
113
+ 17, #cancelled by user
114
+ 75], #number attempts to enter cardnumer exceeded.
115
+ :failed => [
116
+ 02,
117
+ 03,
118
+ 05,
119
+ 12,
120
+ 30,
121
+ 34,
122
+ 40,
123
+ 63,
124
+ 94,
125
+ 97]
126
+ }
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,33 @@
1
+ Spree::Order.class_eval do
2
+ # StateMachine::Machine.ignore_method_conflicts = true
3
+ # Spree::Order.state_machines[:state] = StateMachine::Machine.new(Spree::Order, :initial => 'cart', :use_transactions => false) do
4
+ # event :next do
5
+ # transition :from => 'cart', :to => 'address'
6
+ # transition :from => 'address', :to => 'delivery'
7
+ # transition :from => 'delivery', :to => 'complete'
8
+ # transition :from => 'confirm', :to => 'complete'
9
+ # end
10
+
11
+ # event :cancel do
12
+ # transition :to => 'canceled', :if => :allow_cancel?
13
+ # end
14
+ # event :return do
15
+ # transition :to => 'returned', :from => 'awaiting_return'
16
+ # end
17
+ # event :resume do
18
+ # transition :to => 'resumed', :from => 'canceled', :if => :allow_resume?
19
+ # end
20
+ # event :authorize_return do
21
+ # transition :to => 'awaiting_return'
22
+ # end
23
+
24
+ # before_transition :to => ['delivery'] do |order|
25
+ # order.shipments.each { |s| s.destroy unless s.shipping_method.available_to_order?(order) }
26
+ # end
27
+
28
+ # after_transition :to => 'complete', :do => :finalize!
29
+ # after_transition :to => 'delivery', :do => :create_tax_charge!
30
+ # after_transition :to => 'resumed', :do => :after_resume
31
+ # after_transition :to => 'canceled', :do => :after_cancel
32
+ # end
33
+ end
@@ -0,0 +1,39 @@
1
+ module Spree
2
+ class PaymentMethod::Omnikassa < PaymentMethod
3
+ preference :merchant_id, :string, :default => "002020000000001"
4
+ preference :key_version, :integer, :default => 1
5
+ preference :secret_key, :string, :default => "002020000000001_KEY1"
6
+
7
+ def actions
8
+ %w{capture}
9
+ end
10
+
11
+ def can_capture?(payment)
12
+ ['checkout', 'pending'].include?(payment.state)
13
+ end
14
+
15
+ def capture(payment)
16
+ #payments with state "checkout" must be moved into state "pending" first:
17
+ payment.update_attribute(:state, "pending") if payment.state == "checkout"
18
+ payment.complete
19
+ true
20
+ end
21
+
22
+ def source_required?
23
+ false
24
+ end
25
+
26
+ def url
27
+ if self.environment == "production"
28
+ "https://payment-webinit.omnikassa.rabobank.nl/paymentServlet"
29
+ else
30
+ "https://payment-webinit.simu.omnikassa.rabobank.nl/paymentServlet"
31
+ end
32
+ end
33
+
34
+ def self.fetch_payment_method
35
+ name = "Omnikassa"
36
+ Spree::PaymentMethod.find(:first, :conditions => [ "lower(name) = ?", name.downcase ]) || raise(ActiveRecord::RecordNotFound)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ <% content_for :head do %>
2
+ <%= javascript_include_tag states_path %>
3
+ <% end %>
4
+ <div id="checkout" data-hook>
5
+ <%= render :partial => 'spree/shared/error_messages', :locals => { :target => @order } %>
6
+
7
+ <h1 data-hook="checkout_title"><%= t(:checkout) %></h1>
8
+ <ul id="checkout-steps-<%= @order.state %>" class="breadcrumbs progress-steps">
9
+ <% checkout_progress_states.each do |state| %>
10
+ <li class="<%= state.classes.join(" ") %>">
11
+ <%= state.text %>
12
+ </li>
13
+ <% end %>
14
+ </ul>
15
+
16
+ <%= form_tag(@payment_request.payment_method.url, :method => :post) do %>
17
+ <div class="row" data-hook="checkout_content">
18
+ <div class="six columns" data-hook="checkout_form_wrapper">
19
+ <p><%= t(:payment_options) %></p>
20
+ <div data-hook="checkout_payment_step">
21
+ <%= image_submit_tag("payment_logos.png") %>
22
+ <p class="note"><%= t(:payment_goes_offsite) %></p>
23
+ <%= hidden_field_tag "Data", @payment_request.data %>
24
+ <%= hidden_field_tag "InterfaceVersion", @payment_request.interface_version %>
25
+ <%= hidden_field_tag "Seal", @payment_request.seal %>
26
+ <div data-hook="coupon_code_field" data-hook></div>
27
+ </div>
28
+ </div>
29
+ <div class="six columns">
30
+ <%= render :partial => 'summary', :locals => { :order => @order } %>
31
+ <%= submit_tag t(:save_and_continue), :class => 'continue button fullwidth' %>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ <% end %>
36
+ </div>
@@ -0,0 +1,5 @@
1
+ # Sample localization file for English. Add more files in this directory for other locales.
2
+ # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3
+
4
+ en:
5
+ hello: "Hello world"
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ Spree::Core::Engine.routes.prepend do
2
+ # SpreeOmnikassa::Engine.routes.draw do
3
+ post 'omnikassa_payments/homecoming', :to => 'omnikassa_payments#homecoming'
4
+ post 'omnikassa_payments/reply', :to => 'omnikassa_payments#reply'
5
+ end
@@ -0,0 +1,29 @@
1
+ module SpreeOmnikassa
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+
5
+ def add_javascripts
6
+ append_file "app/assets/javascripts/store/all.js", "//= require store/spree_omnikassa\n"
7
+ append_file "app/assets/javascripts/admin/all.js", "//= require admin/spree_omnikassa\n"
8
+ end
9
+
10
+ def add_stylesheets
11
+ inject_into_file "app/assets/stylesheets/store/all.css", " *= require store/spree_omnikassa\n", :before => /\*\//, :verbose => true
12
+ inject_into_file "app/assets/stylesheets/admin/all.css", " *= require admin/spree_omnikassa\n", :before => /\*\//, :verbose => true
13
+ end
14
+
15
+ def add_migrations
16
+ run 'bundle exec rake railties:install:migrations FROM=spree_omnikassa'
17
+ end
18
+
19
+ def run_migrations
20
+ res = ask "Would you like to run the migrations now? [Y/n]"
21
+ if res == "" || res.downcase == "y"
22
+ run 'bundle exec rake db:migrate'
23
+ else
24
+ puts "Skiping rake db:migrate, don't forget to run it!"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,26 @@
1
+ require 'spree_core'
2
+
3
+ module SpreeOmnikassa
4
+ class Engine < Rails::Engine
5
+ engine_name 'spree_omnikassa'
6
+
7
+ config.autoload_paths += %W(#{config.root}/lib)
8
+
9
+ # use rspec for tests
10
+ config.generators do |g|
11
+ g.test_framework :rspec
12
+ end
13
+
14
+ def self.activate
15
+ Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
16
+ Rails.configuration.cache_classes ? require(c) : load(c)
17
+ end
18
+ end
19
+
20
+ config.to_prepare &method(:activate).to_proc
21
+
22
+ initializer "spree.register.payment_methods" do |app|
23
+ app.config.spree.payment_methods << Spree::PaymentMethod::Omnikassa
24
+ end
25
+ end
26
+ end
data/script/rails ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ ENGINE_PATH = File.expand_path('../..', __FILE__)
5
+ load File.expand_path('../../spec/dummy/script/rails', __FILE__)
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spree::CheckoutController do
4
+ before(:each) do
5
+ @pm = Spree::PaymentMethod::Omnikassa.new(:name => "Omnikassa", :environment => "test")
6
+ @pm.save
7
+ @pm.preferred_merchant_id = @merchant_id
8
+ @pm.preferred_key_version = @key_version
9
+ @pm.preferred_secret_key = @secret_key
10
+ @routes = Spree::Core::Engine.routes # render_views
11
+ end
12
+ let(:order) { mock_model(Spree::Order,
13
+ :checkout_allowed? => true,
14
+ :completed? => false,
15
+ :update_attributes => true,
16
+ :payment? => false,
17
+ :insufficient_stock_lines => [],
18
+ :coupon_code => nil,
19
+ :state => "payment",
20
+ :total => BigDecimal("123.45"),
21
+ :payments => []).as_null_object }
22
+ before { controller.stub :current_order => order, :current_user => Spree::User.anonymous! }
23
+
24
+ it 'should show omnikassa form on payment' do
25
+ get :edit, {:state => 'payment'}
26
+ response.should render_template('spree/checkout/omnikassa_edit')
27
+ end
28
+ end
@@ -0,0 +1,198 @@
1
+ require "spec_helper"
2
+
3
+ describe Spree::OmnikassaPaymentsController do
4
+
5
+ before(:each) do
6
+ @routes = Spree::Core::Engine.routes
7
+
8
+ @merchant_id = "123abc"
9
+ @key_version = "1"
10
+ @secret_key = "002020000000001_KEY1"
11
+
12
+ @pm = Spree::PaymentMethod::Omnikassa.new(:name => "Omnikassa", :environment => "test")
13
+ @pm.save
14
+ @pm.preferred_merchant_id = @merchant_id
15
+ @pm.preferred_key_version = @key_version
16
+ @pm.preferred_secret_key = @secret_key
17
+
18
+ Spree::Order.stub(:create_user)
19
+ Spree::Order.any_instance.stub(:payment_required?).and_return(true)
20
+ @order = Spree::Order.new(:email => "foo@example.com", :state => "delivery")
21
+ @order.save!
22
+
23
+ @data = "amount=24900|captureDay=0|captureMode=AUTHOR_CAPTURE|currencyCode=978|merchantId=002020000000001|orderId=#{@order.id}|transactionDateTime=2012-04-25T14:41:01+02:00|transactionReference=0020200000000011028|keyVersion=1|authorisationId=0020000006791167|paymentMeanBrand=IDEAL|paymentMeanType=CREDIT_TRANSFER|responseCode=00"
24
+ @seal = ::Digest::SHA2.hexdigest(@data + @secret_key)
25
+
26
+ @params = {
27
+ "InterfaceVersion" => "HP_1.0",
28
+ "Data" => @data,
29
+ "Encode" => "",
30
+ "Seal" => @seal
31
+ }
32
+ @payment_response = Spree::OmnikassaPaymentResponse.new(@params['Seal'], @params['Data'])
33
+ @payment = Spree::Payment.new(
34
+ :amount => @payment_response.attributes[:amount],
35
+ :payment_method_id => 200123
36
+ )
37
+ @payment.order_id = @payment_response.attributes[:order_id]
38
+ @payment.id = 1234
39
+
40
+ Spree::Payment.stub(:new).and_return(@payment)
41
+
42
+ Spree::OmnikassaPaymentResponse.any_instance.stub(:payment).and_return(@payment)
43
+ end
44
+
45
+ response_args = %w[
46
+ Data
47
+ Seal
48
+ ]
49
+
50
+ response_codes = {
51
+ :success => [00],
52
+ :pending => [
53
+ 90,
54
+ 99],
55
+ :cancelled => [
56
+ 14, #invalid CSC or CVV
57
+ 17, #cancelled by user
58
+ 75], #number attempts to enter cardnumer exceeded.
59
+ :failed => [
60
+ 02,
61
+ 03,
62
+ 05,
63
+ 12,
64
+ 30,
65
+ 34,
66
+ 40,
67
+ 63,
68
+ 94,
69
+ 97]
70
+ }
71
+
72
+ describe "#homecoming" do
73
+ it 'should redirect to root_url' do
74
+ post :homecoming, @params
75
+ response.should redirect_to(root_url)
76
+ end
77
+
78
+ describe "fields" do
79
+ describe "success" do
80
+ before :each do
81
+ Spree::OmnikassaPaymentResponse.any_instance.stub(:response_level).and_return(:success)
82
+ end
83
+ it 'should set a flash' do
84
+ post :homecoming, @params
85
+ flash[:info].should_not be_nil
86
+ flash[:info].downcase.should match /success/
87
+ end
88
+ end
89
+ end
90
+
91
+ it 'should remove order_id from session' do
92
+ session[:order_id] = 123
93
+ post :homecoming, @params
94
+ session[:order_id].should be_nil
95
+ end
96
+ end
97
+
98
+ describe '#reply' do
99
+ it 'should handle a post' do
100
+ post :reply, @params
101
+ response.status.should == 200
102
+ end
103
+
104
+ response_args.each do |field|
105
+ it "should recieve param #{field}" do
106
+ post :reply, @params
107
+ controller.params[field].should_not be_nil
108
+ end
109
+ end #describe fields
110
+
111
+ describe 'success (00)' do
112
+ before :each do
113
+ Spree::OmnikassaPaymentResponse.any_instance.stub(:response_level).and_return(:success)
114
+ end
115
+
116
+ it 'should set payment state to completed' do
117
+ post :reply, @params
118
+ @payment.state.should == "completed"
119
+ end
120
+ it 'should log the response with level :info' do
121
+ Rails.logger.should_receive(:info).with( /OmnikassaPaymentResponse posted: payment: .*; params: .*/ )
122
+ post :reply, @params
123
+ end
124
+ it 'should set the order state to completed' do
125
+ post :reply, @params
126
+ @payment_response.order.state.should == "complete"
127
+ end
128
+ end
129
+ describe "pending (#{response_codes[:pending].join(',')})" do
130
+ before :each do
131
+ Spree::OmnikassaPaymentResponse.any_instance.stub(:response_level).and_return(:pending)
132
+ end
133
+
134
+ it 'should set payment state to pending' do
135
+ post :reply, @params
136
+ @payment.state == "pending"
137
+ end
138
+ it 'should log the response with level :info' do
139
+ Rails.logger.should_receive(:info).with( /OmnikassaPaymentResponse posted: payment: .*; params: .*/ )
140
+ post :reply, @params
141
+ end
142
+ it 'should set the order state to payment' do
143
+ post :reply, @params
144
+ @payment_response.order.state.should == "payment"
145
+ end
146
+ end
147
+ describe "cancelled (#{response_codes[:cancelled].join(',')})" do
148
+ before :each do
149
+ Spree::OmnikassaPaymentResponse.any_instance.stub(:response_level).and_return(:cancelled)
150
+ end
151
+ it 'should set payment state to failed' do
152
+ post :reply, @params
153
+ @payment.state == "failed"
154
+ end
155
+ it 'should log the response with level :info' do
156
+ Rails.logger.should_receive(:info).with( /OmnikassaPaymentResponse posted: payment: .*; params: .*/ )
157
+ post :reply, @params
158
+ end
159
+ it 'should set the order state to cancelled' do
160
+ Spree::Order.any_instance.should_receive(:cancel)
161
+ post :reply, @params
162
+ end
163
+ end
164
+ describe "failed (#{response_codes[:failed].join(',')})" do
165
+ before :each do
166
+ Spree::OmnikassaPaymentResponse.any_instance.stub(:response_level).and_return(:failed)
167
+ end
168
+ it 'should set payment state to failed' do
169
+ post :reply, @params
170
+ @payment.state == "failed"
171
+ end
172
+ it 'should log the response with level :error' do
173
+ Rails.logger.should_receive(:error).with( /OmnikassaPaymentResponse posted: payment: .*; params: .*/ )
174
+ post :reply, @params
175
+ end
176
+ it 'should set the order state to cancelled' do
177
+ Spree::Order.any_instance.should_receive(:cancel)
178
+ post :reply, @params
179
+ end
180
+ end
181
+
182
+ it 'should add a payment to order if not exists' do
183
+ @payment.started_processing!
184
+ Spree::OmnikassaPaymentsController.any_instance.should_receive(:add_payment_if_not_exists)
185
+ post :reply, @params
186
+ end
187
+ end
188
+ end
189
+
190
+ =begin
191
+ Spree Payment states from http://guides.spreecommerce.com/payments.html#payment
192
+ checkout Checkout has not been completed
193
+ processing The payment is being processed (temporary – intended to prevent double submission)
194
+ pending The payment has been processed but not yet complete (ex. authorized but not captured)
195
+ completed The payment is completed – only payments in this state count against the order total
196
+ failed The payment was rejected (ex. credit card was declined)
197
+ void The payment should not be counted against the order
198
+ =end