spree_ignitor_ipay88 0.0.2
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +32 -0
- data/app/assets/images/ignitor_logo.png +0 -0
- data/app/assets/javascripts/spree/backend/spree_ignitor_ipay88.js +0 -0
- data/app/assets/javascripts/spree/frontend/spree_ignitor_ipay88.js +0 -0
- data/app/assets/stylesheets/spree/backend/spree_ignitor_ipay88.css +0 -0
- data/app/assets/stylesheets/spree/frontend/spree_ignitor_ipay88.css +0 -0
- data/app/controllers/spree/admin/payment_methods_controller_decorator.rb +3 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +21 -0
- data/app/controllers/spree/ipay88_controller.rb +97 -0
- data/app/helpers/spree/ipay88_helper.rb +38 -0
- data/app/models/spree/ipay88/payment_method.rb +43 -0
- data/app/models/spree/ipay88/transaction.rb +123 -0
- data/app/models/spree/ipay88.rb +5 -0
- data/app/models/spree_order_decorator.rb +16 -0
- data/app/models/spree_payment_method_decorator.rb +3 -0
- data/app/overrides/payment_method_view_override.rb +11 -0
- data/app/views/spree/admin/payment_methods/_branding.html.erb +3 -0
- data/app/views/spree/checkout/payment/_ipay88.html.erb +0 -0
- data/app/views/spree/ipay88/error.html.erb +2 -0
- data/app/views/spree/ipay88/show.html.erb +38 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20160726135841_create_spree_ipay88_transactions.rb +28 -0
- data/lib/sha1_encryptor.rb +29 -0
- data/lib/spree_ignitor_ipay88/engine.rb +20 -0
- data/lib/spree_ignitor_ipay88/version.rb +3 -0
- data/lib/spree_ignitor_ipay88.rb +6 -0
- data/lib/tasks/spree_ignitor_ipay88_tasks.rake +4 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e32f8b521896268e7499c14003d07f72632cbafc
|
4
|
+
data.tar.gz: 0dda862451fd477a2a2b36e0aea89dce6e5ba860
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f8846fde0336030bca2ba19c6ba064e81427aaf322779ca91047db94c231c1e8511b579c1a66dacb6dd0642f9578f189bb9429b3c3a373fac4d5a7d59cc6ea7a
|
7
|
+
data.tar.gz: 0329df80c64d55a06549a2573fe00e8346d10e70dd703af9f0c015f524c884a48371676754e00c5f8fa79956b4825bab97c6a75681875e6dc1bd1faab2e2d46d
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Edutor Technologies
|
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/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
require 'rake/testtask'
|
9
|
+
|
10
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
11
|
+
rdoc.rdoc_dir = 'rdoc'
|
12
|
+
rdoc.title = 'SpreeIgnitorIpay88'
|
13
|
+
rdoc.options << '--line-numbers'
|
14
|
+
rdoc.rdoc_files.include('README.rdoc')
|
15
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
Rake::TestTask.new do |t|
|
19
|
+
t.libs << 'test'
|
20
|
+
t.test_files = FileList['test/**/*test.rb']
|
21
|
+
t.verbose = true
|
22
|
+
end
|
23
|
+
|
24
|
+
load 'rails/tasks/statistics.rake'
|
25
|
+
|
26
|
+
desc "Run tests"
|
27
|
+
task :default => :test
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
Bundler::GemHelper.install_tasks
|
32
|
+
|
Binary file
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Spree
|
2
|
+
CheckoutController.class_eval do
|
3
|
+
|
4
|
+
before_action :push_to_ipay88_show_action, only: :update
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
# This is the hook which pushes/redirects user to ipay88 show page for the first time
|
9
|
+
def push_to_ipay88_show_action
|
10
|
+
# Perform this redirect only if the order is in payment state
|
11
|
+
return unless (params[:state] == 'payment') && params[:order][:payments_attributes]
|
12
|
+
# The user already has picked Ipay88.
|
13
|
+
# So we will have the corresponding payment method for Ipay88 in the parameter
|
14
|
+
payment_method = PaymentMethod.find(params[:order][:payments_attributes].first[:payment_method_id])
|
15
|
+
if payment_method && payment_method.kind_of?(Spree::Ipay88::PaymentMethod)
|
16
|
+
redirect_to gateway_ipay88_path(@order.number, payment_method.id)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Spree
|
2
|
+
class Ipay88Controller < StoreController
|
3
|
+
# Because call back should come from Ipay. They don't have an authenticity token
|
4
|
+
skip_before_action :verify_authenticity_token, only: :callback
|
5
|
+
# Ensure that the callback is redirected from Ipay88' secure server
|
6
|
+
before_action :check_signature, only: :callback
|
7
|
+
helper 'spree/orders'
|
8
|
+
include Spree::Ipay88Helper
|
9
|
+
|
10
|
+
# This is the method which renders the form which redirects to Ipay88 upon form submission from user's browser
|
11
|
+
def show
|
12
|
+
# We initially let the user to pick which payment method he wants to use. Payment method id therefore comes from the user
|
13
|
+
@payment_method = Spree::PaymentMethod.find(params[:payment_method_id])
|
14
|
+
|
15
|
+
if !@payment_method or !@payment_method.kind_of?(Spree::Ipay88::PaymentMethod)
|
16
|
+
# if by any chance
|
17
|
+
flash[:error] = 'Invalid payment method'
|
18
|
+
# Don't render anything just show a flash message in the existing screen (checkout#edit)
|
19
|
+
render :error
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
@order = current_order
|
24
|
+
if @order.has_authorized_ipay88_transaction?
|
25
|
+
# if by any chance, we get to the url by copy pasting the link etc., we flash useful error message
|
26
|
+
flash[:error] = 'Order #{@order.number} is already authorized at Ipay88'
|
27
|
+
# Don't render anything just show a flash message in the existing screen (checkout#edit)
|
28
|
+
render :error
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
# Precautions
|
33
|
+
@order.cancel_existing_ipay88_transactions!
|
34
|
+
@order.payments.destroy_all
|
35
|
+
|
36
|
+
# Creates new payment and a corresponding Ipay88 transaction
|
37
|
+
@order.payments.build(amount:@order.total,payment_method_id:@payment_method.id)
|
38
|
+
@transaction = @order.ipay88_transactions.build( amount:@order.total, currency:@order.currency.to_s, payment_method_id:@payment_method.id )
|
39
|
+
@transaction.transact # shifts the transaction state from 'created' to 'sent'. We didn't really send the transaction to ipay88 yet.
|
40
|
+
# Now all we have left is to make the user submit the form
|
41
|
+
|
42
|
+
# We save the order, the corresponding payment and ipay88 transaction in the database
|
43
|
+
@order.save!
|
44
|
+
# these are needed on the view
|
45
|
+
@bill_address, @ship_address = @order.bill_address, (@order.ship_address || @order.bill_address)
|
46
|
+
logger.info("Will send order #{@order.number} to Ipay88 with local transaction ID: #{@transaction.id}")
|
47
|
+
end
|
48
|
+
|
49
|
+
# Responds to the Ipay88 initiated redirect. This is the URL which is given to Ipay88 as a redirect/callback url
|
50
|
+
|
51
|
+
def callback
|
52
|
+
@transaction.status = params["Status"]
|
53
|
+
@transaction.ipay88_payment_id = params["PaymentId"].to_s
|
54
|
+
@transaction.ref_no = params["RefNo"] # Spree's order.number
|
55
|
+
@transaction.ipay88_amount = params["Amount"] # Stored seperately, in case
|
56
|
+
@transaction.remark = params["Remark"]
|
57
|
+
@transaction.trans_id = params["TransId"].to_s
|
58
|
+
@transaction.auth_code = params["AuthCode"]
|
59
|
+
@transaction.error_description = params["ErrDesc"]
|
60
|
+
@transaction.signature = params["Signature"]
|
61
|
+
|
62
|
+
session[:access_token] = @transaction.order.guest_token if @transaction.order.respond_to?(:guest_token)
|
63
|
+
session[:order_id] = @transaction.order.id
|
64
|
+
|
65
|
+
if @transaction.next
|
66
|
+
# Handles transaction states
|
67
|
+
if @transaction.authorized? # Success
|
68
|
+
session[:order_id] = nil
|
69
|
+
flash[:success] = I18n.t(:success)
|
70
|
+
# Google analytics part
|
71
|
+
# flash[:commerce_tracking] = 'nothing special'
|
72
|
+
if session[:access_token].nil?
|
73
|
+
redirect_to order_path(@transaction.order, {:order_complete => true})
|
74
|
+
else # Enables the url to be reused and copied else where a.k.a the page will still be displayed
|
75
|
+
redirect_to order_path(@transaction.order, {:order_complete => true, :token => session[:access_token]})
|
76
|
+
end
|
77
|
+
else # Failure
|
78
|
+
redirect_to edit_order_path(@transaction.order), :error => @transaction.error_description
|
79
|
+
end
|
80
|
+
else
|
81
|
+
render 'error'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def check_signature
|
88
|
+
@transaction = Spree::Ipay88::Transaction.find(params[:id])
|
89
|
+
raise "Transaction with id: #{params[:id]} not found!" unless @transaction
|
90
|
+
merchant_key = @transaction.payment_method.preferred_merchant_key
|
91
|
+
# Produces white screen
|
92
|
+
@ipay88_error = params["ErrDesc"]
|
93
|
+
render 'error' unless params["Signature"] == get_response_signature(params,merchant_key)
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'sha1_encryptor'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Ipay88Helper
|
5
|
+
|
6
|
+
# Generates request parameters to be used in form which redirects the user to ipay88
|
7
|
+
def request_params(payment_method,order)
|
8
|
+
request_params = {"MerchantCode"=>payment_method.preferred_merchant_code,"RefNo"=>order.number,
|
9
|
+
"Amount"=>get_amount(order),"Currency"=>order.currency,"ProdDesc"=>order.prod_desc,
|
10
|
+
"UserName"=>"","UserEmail"=>"","UserContact"=>"",
|
11
|
+
"Remark"=>"","Signature"=>get_request_signature(payment_method,order),"ResponseURL"=>""}
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_amount(order)
|
15
|
+
order.total.to_money.format(thousands_separator:',',symbol:false)
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_simplified_amount(order)
|
19
|
+
order.total.to_money.format(thousands_separator:false,symbol:false).gsub('.','')
|
20
|
+
end
|
21
|
+
|
22
|
+
# Calculates request signature which is used by Ipay88 to verify if the request is received with right amount from the right merchant
|
23
|
+
def get_request_signature(payment_method,order)
|
24
|
+
params = {merchant_key:payment_method.preferred_merchant_key,merchant_code:payment_method.preferred_merchant_code,
|
25
|
+
ref_no:order.number,simplified_amount:get_simplified_amount(order),currency:order.currency}
|
26
|
+
SHA1Encryptor.request_signature(params)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Directly send in response params to generate response signature
|
30
|
+
def get_response_signature(params,merchant_key)
|
31
|
+
simplified_amount = params["Amount"].gsub(/[\.\,]/,"")
|
32
|
+
signature_params = {merchant_key:merchant_key,merchant_code:params["MerchantCode"],payment_id:params["PaymentId"],
|
33
|
+
ref_no:params["RefNo"],simplified_amount:simplified_amount,currency:params["Currency"],
|
34
|
+
status:params["Status"]}
|
35
|
+
SHA1Encryptor.response_signature(signature_params)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Spree
|
2
|
+
class Ipay88::PaymentMethod < Spree::PaymentMethod
|
3
|
+
preference :merchant_code, :string
|
4
|
+
preference :merchant_key, :string
|
5
|
+
|
6
|
+
# This is the url to which we redirect user to pay money through ipay88 gateway
|
7
|
+
def url
|
8
|
+
"https://www.mobile88.com/epayment/entry.asp"
|
9
|
+
end
|
10
|
+
|
11
|
+
# Auto capture of payments. Leave it true always.
|
12
|
+
def auto_capture?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
# For the sake of Spree you need to add a purchase class with success? and authorization methods,
|
17
|
+
# mention the transaction provider class, payment source class and a method type named
|
18
|
+
def purchase(amount, source, options = {})
|
19
|
+
Class.new do
|
20
|
+
def success?;
|
21
|
+
true;
|
22
|
+
end
|
23
|
+
|
24
|
+
def authorization;
|
25
|
+
nil;
|
26
|
+
end
|
27
|
+
end.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def provider_class
|
31
|
+
Spree::Ipay88::Transaction
|
32
|
+
end
|
33
|
+
|
34
|
+
def payment_source_class
|
35
|
+
Spree::Ipay88::Transaction
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_type
|
39
|
+
'ipay88'
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Spree
|
2
|
+
# Ipay88 transaction class. The model which handles transaction records on the store when done through Ipay88
|
3
|
+
class Ipay88::Transaction < ActiveRecord::Base
|
4
|
+
belongs_to :order, class_name:"Spree::Order"
|
5
|
+
belongs_to :payment_method, class_name:"Spree::Ipay88::PaymentMethod"
|
6
|
+
has_many :payments, :as => :source
|
7
|
+
|
8
|
+
def actions
|
9
|
+
["capture","void"]
|
10
|
+
end
|
11
|
+
|
12
|
+
# Only captures payments that have checkout and pending states
|
13
|
+
def can_capture?(payment)
|
14
|
+
['checkout', 'pending'].include?(payment.state)
|
15
|
+
end
|
16
|
+
|
17
|
+
def can_void?(payment)
|
18
|
+
payment.state != 'void'
|
19
|
+
end
|
20
|
+
|
21
|
+
# The following methods first update the state from checkout to
|
22
|
+
# pending as required by the state machine used by payments class
|
23
|
+
# After the transaction, capture payment
|
24
|
+
|
25
|
+
def capture(payment)
|
26
|
+
payment.update_attribute(:state,'pending') if payment.state == 'checkout'
|
27
|
+
payment.complete
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
# Method to void payments in case there are issues with transaction
|
32
|
+
def void(payment)
|
33
|
+
payment.update_attribute(:state,'pending') if payment.state =='checkout'
|
34
|
+
payment.complete
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
# Uses state machine provided automatically when you require spree/core
|
39
|
+
#TODO update states according to the statuses received after writing controller
|
40
|
+
|
41
|
+
state_machine :initial=> :created, :use_transactions => false do
|
42
|
+
|
43
|
+
before_transition :to => :sent, :do => :initialize_state!
|
44
|
+
|
45
|
+
event :transact do
|
46
|
+
transition :created => :sent
|
47
|
+
end
|
48
|
+
|
49
|
+
event :next do
|
50
|
+
transition [:sent, :batch] => :authorized, :if => lambda {|txn| txn.status == 1}
|
51
|
+
transition [:sent, :batch] => :failed, :if => lambda {|txn| txn.status == 0}
|
52
|
+
end
|
53
|
+
|
54
|
+
after_transition :to => :authorized, :do => :payment_authorized
|
55
|
+
|
56
|
+
# This is useful when internet failure occurs and
|
57
|
+
# after the user retries the payment via a new transaction
|
58
|
+
# It is important to note that a new transaction gets created
|
59
|
+
# as soon as an old transaction is moved to cancelled state and a user retries the operation.
|
60
|
+
# Another way to create a cancelled transaction is
|
61
|
+
# when we query the Ipay88 server to know if the transaction is aborted for any reason.
|
62
|
+
# In that case since the transaction is already in cancelled state,
|
63
|
+
# it won't cause any inconsistency when a new transaction is initiated
|
64
|
+
|
65
|
+
event :cancel do
|
66
|
+
transition all - [:authorized] => :cancelled
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def payment_authorized
|
71
|
+
payment = order.payments.where(:payment_method_id=>self.payment_method.id).first
|
72
|
+
payment.update_attributes :source => self, :payment_method_id => self.payment_method.id
|
73
|
+
order.next
|
74
|
+
order.save
|
75
|
+
end
|
76
|
+
|
77
|
+
def initialize_state!
|
78
|
+
if order.confirmation_required? && !order.confirm?
|
79
|
+
raise "Order is not in 'confirm' state. Order should be in 'confirm' state before transaction can be sent to CCAvenue"
|
80
|
+
end
|
81
|
+
this = self
|
82
|
+
previous = order.ipay88_transactions.reject {|t| t==this}
|
83
|
+
previous.each {|p| p.cancel!}
|
84
|
+
# This transaction number is unique only within the scope of order.
|
85
|
+
#This is to keep track of succesful and cancelled transactions.
|
86
|
+
generate_transaction_number!
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def gateway_order_number
|
91
|
+
order.number + transaction_number
|
92
|
+
end
|
93
|
+
|
94
|
+
def generate_transaction_number!
|
95
|
+
record = true
|
96
|
+
# attempts to create a record till you meet an unused transaction number and finaly creates a record
|
97
|
+
# whose transaction number is unique
|
98
|
+
while record.present?
|
99
|
+
random = "#{Array.new(4){rand(4)}.join}"
|
100
|
+
record = Spree::Ipay88::Transaction.where(order_id: self.order.id,transaction_number: random)
|
101
|
+
end
|
102
|
+
self.transaction_number = random
|
103
|
+
end
|
104
|
+
|
105
|
+
def initialize(*args)
|
106
|
+
if !args or args.empty?
|
107
|
+
super(*args)
|
108
|
+
else
|
109
|
+
from_admin = args[0].delete('from_admin')
|
110
|
+
super(*args)
|
111
|
+
if from_admin
|
112
|
+
self.amount = self.order.amount
|
113
|
+
self.transact
|
114
|
+
self.ipay88_amount = self.amount.to_s
|
115
|
+
self.next
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
Spree::Order.class_eval do
|
2
|
+
has_many :ipay88_transactions, :class_name => "Spree::Ipay88::Transaction"
|
3
|
+
|
4
|
+
def has_authorized_ipay88_transaction?
|
5
|
+
ipay88_transactions.select{|txn| txn.authorized?}.present?
|
6
|
+
end
|
7
|
+
|
8
|
+
def cancel_existing_ipay88_transactions!
|
9
|
+
ipay88_transactions.each{|t| t.cancel!}
|
10
|
+
end
|
11
|
+
|
12
|
+
def prod_desc
|
13
|
+
self.products.map(&:name).join(",")
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# We want to remove environments select list from payment methods view in admin panel
|
2
|
+
Deface::Override.new(:virtual_path => 'spree/admin/payment_methods/_form',
|
3
|
+
:name => 'Environment section removal',
|
4
|
+
:remove => "[data-hook='environment']"
|
5
|
+
)
|
6
|
+
|
7
|
+
# Ignitor company branding
|
8
|
+
Deface::Override.new(:virtual_path => 'spree/admin/payment_methods/_form',
|
9
|
+
:insert_before => "[data-hook='name']",
|
10
|
+
:text => "<%= render 'branding', payment_method: @payment_method%>",
|
11
|
+
:name => 'branding')
|
File without changes
|
@@ -0,0 +1,38 @@
|
|
1
|
+
<div id="checkout" data-hook>
|
2
|
+
<%= render partial: 'spree/shared/error_messages', locals: { target: @order } %>
|
3
|
+
<h3><%= t(:checkout) %></h3>
|
4
|
+
<div class="row">
|
5
|
+
<div class="">
|
6
|
+
<div class="clear"></div>
|
7
|
+
<div class="checkout_form">
|
8
|
+
<%= form_tag @payment_method.url do %>
|
9
|
+
<%
|
10
|
+
request_params = request_params(@payment_method,@order)
|
11
|
+
redirect_url = gateway_ipay88_callback_url(@transaction, :protocol => 'http')
|
12
|
+
%>
|
13
|
+
|
14
|
+
<div style="padding:10px;background-color:#fcf8e3">
|
15
|
+
<p style= "color:red"> * Mandatory Fields</p>
|
16
|
+
|
17
|
+
<%= hidden_field_tag 'MerchantCode', request_params['MerchantCode'] %>
|
18
|
+
<%= hidden_field_tag 'RefNo', request_params['RefNo'] %>
|
19
|
+
<%= hidden_field_tag 'Amount', request_params['Amount'] %>
|
20
|
+
<%= hidden_field_tag 'Currency', request_params['Currency'] %>
|
21
|
+
<%= hidden_field_tag 'ProdDesc', request_params['ProdDesc'] %>
|
22
|
+
<%= text_field_tag 'UserName', request_params['UserName'],required:true, placeholder:'Your name' %>
|
23
|
+
<%= email_field_tag 'UserEmail', request_params['UserEmail'],required:true, placeholder:'Email' %>
|
24
|
+
<%= telephone_field_tag 'UserContact', request_params['UserContact'],required:true,placeholder:"Contact Number" %>
|
25
|
+
<%= hidden_field_tag 'Remark', request_params['Remark'] %>
|
26
|
+
<%= hidden_field_tag 'Signature', request_params['Signature'] %>
|
27
|
+
<%= hidden_field_tag 'ResponseURL', redirect_url %>
|
28
|
+
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<%= render :partial => 'spree/checkout/confirm' %>
|
32
|
+
<p style="margin: 10px 0;"><%= t(:ipay88_instructional_text) %></p><br/>
|
33
|
+
<% end %>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
<div class="clear"></div>
|
38
|
+
</div>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
Spree::Core::Engine.routes.draw do
|
2
|
+
match '/gateway/:order_id/ipay88/:payment_method_id' => 'ipay88#show', :as => :gateway_ipay88, via: [:get, :post]
|
3
|
+
# Here :id refers to ipay88 transaction ID. The response redirect is dynamically sent to this url
|
4
|
+
match '/gateway/ipay88/:id/callback' => 'ipay88#callback', :as => :gateway_ipay88_callback, via: [:get, :post]
|
5
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class CreateSpreeIpay88Transactions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :spree_ipay88_transactions do |t|
|
4
|
+
t.integer :order_id
|
5
|
+
t.integer :payment_method_id
|
6
|
+
t.string :transaction_number # unique transaction number within the scope of an order
|
7
|
+
t.string :ref_no # This will correspond to order.number. It is different from Order#id
|
8
|
+
t.decimal :amount, :precision => 8, :scale => 2
|
9
|
+
t.string :currency
|
10
|
+
t.string :ipay88_amount # For the purpose of cross verifying when needed
|
11
|
+
t.string :state # Used by State machine gem to maintain various transaction states
|
12
|
+
t.integer :status # Either 0= Failure or 1= Success
|
13
|
+
t.string :signature # Correspongs to response signature
|
14
|
+
t.string :ipay88_payment_id
|
15
|
+
t.string :error_description
|
16
|
+
t.string :auth_code # Authorization code from bank as fetched by ipay88
|
17
|
+
t.text :remark
|
18
|
+
t.string :trans_id # Provided by ipay88
|
19
|
+
|
20
|
+
t.timestamps
|
21
|
+
end
|
22
|
+
|
23
|
+
add_index :spree_ipay88_transactions, :order_id
|
24
|
+
add_index :spree_ipay88_transactions, :trans_id
|
25
|
+
add_index :spree_ipay88_transactions, :ref_no
|
26
|
+
add_index :spree_ipay88_transactions, :ipay88_payment_id
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
class SHA1Encryptor
|
3
|
+
|
4
|
+
# Creates signature based on the information needed as per ipay88
|
5
|
+
def self.request_signature(params)
|
6
|
+
# Ref No. is same as order number
|
7
|
+
# amount should be stripped of commas and periods. And it should be only till 2 decimal digits
|
8
|
+
cipher = params[:merchant_key]+params[:merchant_code]+
|
9
|
+
params[:ref_no]+params[:simplified_amount]+params[:currency]
|
10
|
+
self.digest(cipher)
|
11
|
+
end
|
12
|
+
|
13
|
+
# The intended purpose of this method is to verify the signature received from ipay88 for additional security
|
14
|
+
def self.response_signature(params)
|
15
|
+
# payment id is the one received from ipay88. It is different from spree's payment id
|
16
|
+
# status is basically 1 or 0 1= success, 0 = failure. This too, is received from ipay88
|
17
|
+
cipher = params[:merchant_key]+params[:merchant_code]+
|
18
|
+
params[:payment_id]+params[:ref_no]+params[:simplified_amount]+params[:currency]+params[:status]
|
19
|
+
self.digest(cipher)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
def self.digest(target_string)
|
25
|
+
digest = Digest::SHA1.digest(target_string)
|
26
|
+
# encodes it in base64
|
27
|
+
[digest].pack("m").chomp
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module SpreeIgnitorIpay88
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
require 'spree/core'
|
4
|
+
isolate_namespace Spree
|
5
|
+
engine_name 'spree_ignitor_ipay88'
|
6
|
+
|
7
|
+
def self.activate
|
8
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
|
9
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
config.after_initialize do |app|
|
14
|
+
app.config.spree.payment_methods+= [Spree::Ipay88::PaymentMethod]
|
15
|
+
end
|
16
|
+
|
17
|
+
config.to_prepare &method(:activate).to_proc
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spree_ignitor_ipay88
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Edutor Technologies
|
8
|
+
- Ignitor learning
|
9
|
+
- Sriharsha Chintalapati
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2016-08-02 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: spree_core
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "~>"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '3.0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: sqlite3
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '1.3'
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '1.3'
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: minitest
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '5.9'
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '5.9'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: gem-release
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0.7'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0.7'
|
71
|
+
description: Ipay88 is a payment gateway service in South East Asian countries. This
|
72
|
+
gem provides integration support for Spree with the gateway
|
73
|
+
email:
|
74
|
+
- info@ignitorlearning.com
|
75
|
+
executables: []
|
76
|
+
extensions: []
|
77
|
+
extra_rdoc_files: []
|
78
|
+
files:
|
79
|
+
- MIT-LICENSE
|
80
|
+
- Rakefile
|
81
|
+
- app/assets/images/ignitor_logo.png
|
82
|
+
- app/assets/javascripts/spree/backend/spree_ignitor_ipay88.js
|
83
|
+
- app/assets/javascripts/spree/frontend/spree_ignitor_ipay88.js
|
84
|
+
- app/assets/stylesheets/spree/backend/spree_ignitor_ipay88.css
|
85
|
+
- app/assets/stylesheets/spree/frontend/spree_ignitor_ipay88.css
|
86
|
+
- app/controllers/spree/admin/payment_methods_controller_decorator.rb
|
87
|
+
- app/controllers/spree/checkout_controller_decorator.rb
|
88
|
+
- app/controllers/spree/ipay88_controller.rb
|
89
|
+
- app/helpers/spree/ipay88_helper.rb
|
90
|
+
- app/models/spree/ipay88.rb
|
91
|
+
- app/models/spree/ipay88/payment_method.rb
|
92
|
+
- app/models/spree/ipay88/transaction.rb
|
93
|
+
- app/models/spree_order_decorator.rb
|
94
|
+
- app/models/spree_payment_method_decorator.rb
|
95
|
+
- app/overrides/payment_method_view_override.rb
|
96
|
+
- app/views/spree/admin/payment_methods/_branding.html.erb
|
97
|
+
- app/views/spree/checkout/payment/_ipay88.html.erb
|
98
|
+
- app/views/spree/ipay88/error.html.erb
|
99
|
+
- app/views/spree/ipay88/show.html.erb
|
100
|
+
- config/locales/en.yml
|
101
|
+
- config/routes.rb
|
102
|
+
- db/migrate/20160726135841_create_spree_ipay88_transactions.rb
|
103
|
+
- lib/sha1_encryptor.rb
|
104
|
+
- lib/spree_ignitor_ipay88.rb
|
105
|
+
- lib/spree_ignitor_ipay88/engine.rb
|
106
|
+
- lib/spree_ignitor_ipay88/version.rb
|
107
|
+
- lib/tasks/spree_ignitor_ipay88_tasks.rake
|
108
|
+
homepage: http://www.ignitorlearning.com
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements:
|
127
|
+
- none
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.4.6
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Ipay88 payment gateway support for Spree commerce engine
|
133
|
+
test_files: []
|