solidus_conekta 1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +90 -0
- data/Rakefile +21 -0
- data/app/assets/javascripts/spree/backend/solidus_conekta.js +2 -0
- data/app/assets/javascripts/spree/frontend/conekta.js +635 -0
- data/app/assets/javascripts/spree/frontend/easyXDM.min.js +25 -0
- data/app/assets/javascripts/spree/frontend/printThis.js +146 -0
- data/app/assets/javascripts/spree/frontend/solidus_conekta.js.coffee +63 -0
- data/app/assets/javascripts/spree/frontend/utils.js.erb +35 -0
- data/app/assets/stylesheets/spree/backend/print.css.sass +12 -0
- data/app/assets/stylesheets/spree/backend/solidus_conekta.css +3 -0
- data/app/assets/stylesheets/spree/frontend/conekta.css.sass +45 -0
- data/app/assets/stylesheets/spree/frontend/solidus_conekta.css +4 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +30 -0
- data/app/controllers/spree/conekta/payments_controller.rb +16 -0
- data/app/models/spree/billing_integration/conekta_gateway/bank.rb +30 -0
- data/app/models/spree/billing_integration/conekta_gateway/card.rb +35 -0
- data/app/models/spree/billing_integration/conekta_gateway/cash.rb +30 -0
- data/app/models/spree/billing_integration/conekta_gateway/monthly_payment.rb +35 -0
- data/app/models/spree/billing_integration/conekta_gateway.rb +31 -0
- data/app/models/spree/conekta_payment.rb +16 -0
- data/app/models/spree/credit_card_decorator.rb +8 -0
- data/app/models/spree/line_item_decorator.rb +11 -0
- data/app/models/spree/order_decorator.rb +19 -0
- data/app/models/spree/payment_decorator.rb +18 -0
- data/app/models/spree.rb +5 -0
- data/app/overrides/add_conekta_scripts_to_the_checkout.rb +4 -0
- data/app/views/spree/admin/payments/_banorte.html.erb +32 -0
- data/app/views/spree/admin/payments/_oxxo.html.erb +29 -0
- data/app/views/spree/admin/payments/_spei.html.erb +30 -0
- data/app/views/spree/admin/payments/source_forms/_conekta.html.erb +3 -0
- data/app/views/spree/admin/payments/source_forms/_conekta_card.html.erb +3 -0
- data/app/views/spree/admin/payments/source_views/_conekta.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_conekta_card.html.erb +19 -0
- data/app/views/spree/checkout/_conekta_scripts.html.erb +17 -0
- data/app/views/spree/checkout/existing_payment/_conekta_card.html.erb +9 -0
- data/app/views/spree/checkout/payment/_conekta.html.erb +3 -0
- data/app/views/spree/checkout/payment/_conekta_card.html.erb +75 -0
- data/app/views/spree/conekta/gateway_options.json.jbuilder +34 -0
- data/app/views/spree/conekta/payments/_bank.html.erb +0 -0
- data/app/views/spree/conekta/payments/_banorte.html.erb +30 -0
- data/app/views/spree/conekta/payments/_card.html.erb +0 -0
- data/app/views/spree/conekta/payments/_cash.html.erb +0 -0
- data/app/views/spree/conekta/payments/_oxxo.html.erb +36 -0
- data/app/views/spree/conekta/payments/_spei.html.erb +28 -0
- data/app/views/spree/conekta/payments/show.html.erb +25 -0
- data/config/locales/en.yml +26 -0
- data/config/locales/es-MX.yml +26 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20130904161251_create_spree_conekta_payments.rb +9 -0
- data/db/migrate/20130904172418_rename_type_column_to_conekta_payment.rb +7 -0
- data/db/migrate/20140220160614_add_installments_to_spree_credit_card.rb +5 -0
- data/db/migrate/20140509145837_add_payment_method_id_to_spree_conekta_payment.rb +6 -0
- data/db/migrate/20140509151116_add_user_id_to_spree_conekta_payment.rb +6 -0
- data/lib/generators/solidus_conekta/install/install_generator.rb +31 -0
- data/lib/solidus_conekta/engine.rb +40 -0
- data/lib/solidus_conekta/factories.rb +6 -0
- data/lib/solidus_conekta/version.rb +3 -0
- data/lib/solidus_conekta.rb +10 -0
- data/lib/spree/conekta/client.rb +36 -0
- data/lib/spree/conekta/configuration.rb +25 -0
- data/lib/spree/conekta/credit_card.rb +42 -0
- data/lib/spree/conekta/credit_card_collection.rb +36 -0
- data/lib/spree/conekta/customer.rb +39 -0
- data/lib/spree/conekta/exchange.rb +30 -0
- data/lib/spree/conekta/fake_response.rb +10 -0
- data/lib/spree/conekta/monthly_payment_provider.rb +26 -0
- data/lib/spree/conekta/payment_notification_handler.rb +36 -0
- data/lib/spree/conekta/payment_source/bank.rb +13 -0
- data/lib/spree/conekta/payment_source/card.rb +21 -0
- data/lib/spree/conekta/payment_source/cash.rb +13 -0
- data/lib/spree/conekta/provider.rb +134 -0
- data/lib/spree/conekta/response.rb +14 -0
- data/lib/tasks/solidus_conekta_tasks.rake +4 -0
- metadata +509 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
module Spree::Conekta
|
2
|
+
module Client
|
3
|
+
CONEKTA_API = 'https://api.conekta.io/'
|
4
|
+
|
5
|
+
attr_accessor :auth_token
|
6
|
+
|
7
|
+
def post(params)
|
8
|
+
Oj.load connection.post(endpoint, Oj.dump(params)).body
|
9
|
+
end
|
10
|
+
|
11
|
+
def get
|
12
|
+
Oj.load connection.get(endpoint).body
|
13
|
+
end
|
14
|
+
|
15
|
+
def connection
|
16
|
+
Faraday.new(url: CONEKTA_API) do |faraday|
|
17
|
+
faraday.request :url_encoded
|
18
|
+
|
19
|
+
faraday.headers = headers
|
20
|
+
faraday.adapter :typhoeus
|
21
|
+
faraday.basic_auth(auth_token, nil)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def headers
|
26
|
+
{
|
27
|
+
'Accept' => ' application/vnd.conekta-v0.3.0+json',
|
28
|
+
'Content-type' => ' application/json'
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def endpoint
|
33
|
+
raise 'Not Implemented'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Spree
|
2
|
+
module Conekta
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :configuration
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.configure
|
9
|
+
self.configuration ||= Configuration.new
|
10
|
+
yield(configuration)
|
11
|
+
end
|
12
|
+
|
13
|
+
class Configuration
|
14
|
+
attr_accessor :installment_options, :installment_default
|
15
|
+
|
16
|
+
def installment_options
|
17
|
+
@installment_options ||= :installment_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def installment_default
|
21
|
+
@installment_default ||= :installment_default
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Spree
|
2
|
+
module Conekta
|
3
|
+
class CreditCard
|
4
|
+
include Spree::Conekta::Client
|
5
|
+
|
6
|
+
attr_reader :customer
|
7
|
+
attr_accessor :id, :brand, :last4
|
8
|
+
|
9
|
+
def self.create(customer, token, auth_token)
|
10
|
+
new(customer, token: token, auth_token: auth_token)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.build(customer, card, auth_token)
|
14
|
+
new(customer, card: card, auth_token: auth_token)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(customer, options)
|
18
|
+
@customer = customer
|
19
|
+
@auth_token = options[:auth_token]
|
20
|
+
build_card(options[:card]) if options[:card]
|
21
|
+
create_card(options[:token]) if options[:token]
|
22
|
+
end
|
23
|
+
|
24
|
+
def endpoint
|
25
|
+
"customers/#{customer.id}/cards"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def build_card(card)
|
31
|
+
@id = card['id']
|
32
|
+
@brand = card['brand']
|
33
|
+
@last4 = card['last4']
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_card(token)
|
37
|
+
response = post(token: token)
|
38
|
+
build_card(response)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Spree
|
2
|
+
module Conekta
|
3
|
+
class CreditCardCollection
|
4
|
+
include Enumerable
|
5
|
+
include Spree::Conekta::Client
|
6
|
+
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_instance_delegators :@cards, :each, :size
|
10
|
+
|
11
|
+
attr_reader :customer
|
12
|
+
|
13
|
+
def initialize(customer, options)
|
14
|
+
@customer = customer
|
15
|
+
@auth_token = options[:auth_token]
|
16
|
+
@cards = build_cards(get)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add(token)
|
20
|
+
@cards << Spree::Conekta::CreditCard.create(customer, token, auth_token)
|
21
|
+
end
|
22
|
+
|
23
|
+
def endpoint
|
24
|
+
"customers/#{customer.id}/cards"
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def build_cards(response)
|
30
|
+
response.map do |credit_card|
|
31
|
+
Spree::Conekta::CreditCard.build(customer, credit_card, auth_token: auth_token)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Spree
|
2
|
+
module Conekta
|
3
|
+
class Customer
|
4
|
+
include Spree::Conekta::Client
|
5
|
+
|
6
|
+
attr_reader :user, :options, :credit_cards
|
7
|
+
|
8
|
+
def initialize(user, options = {})
|
9
|
+
@user = user
|
10
|
+
@options = options
|
11
|
+
@auth_token = options[:auth_token]
|
12
|
+
end
|
13
|
+
|
14
|
+
def id
|
15
|
+
@id ||= user.gateway_customer_profile_id || create_new_client
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_credit_card(token)
|
19
|
+
credit_cards.add(token)
|
20
|
+
end
|
21
|
+
|
22
|
+
def credit_cards
|
23
|
+
@credit_cards ||= Spree::Conekta::CreditCardCollection.new(self, auth_token: auth_token)
|
24
|
+
end
|
25
|
+
|
26
|
+
def endpoint
|
27
|
+
'customers'
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def create_new_client
|
33
|
+
response = post(name: user.email, email: user.email)
|
34
|
+
user.update_column(:gateway_customer_profile_id, response['id']) if options[:persist]
|
35
|
+
response['id']
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Spree::Conekta
|
2
|
+
class Exchange
|
3
|
+
|
4
|
+
EXCHANCE_SERVICES = 'https://currency-api.appspot.com/api/'
|
5
|
+
|
6
|
+
def initialize(amount, currency_from)
|
7
|
+
@amount = (amount.to_i)
|
8
|
+
@currency_from = currency_from
|
9
|
+
get_exchange_rate
|
10
|
+
end
|
11
|
+
|
12
|
+
def amount_exchanged
|
13
|
+
@amount_exchanged ||= (@amount * @exchange_rate).round
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def get_exchange_rate
|
19
|
+
response = JSON.parse(connection.get("#{@currency_from}/MXN.json?amount=#{@amount}").body)
|
20
|
+
@exchange_rate = response['rate'].nil? ? 0 : response['rate'].to_f
|
21
|
+
end
|
22
|
+
|
23
|
+
def connection
|
24
|
+
Faraday.new(url: EXCHANCE_SERVICES) do |faraday|
|
25
|
+
faraday.request :url_encoded
|
26
|
+
faraday.adapter :typhoeus
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Spree::Conekta
|
2
|
+
class MonthlyPaymentProvider
|
3
|
+
attr_accessor :auth_token
|
4
|
+
|
5
|
+
attr_reader :options
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@options = options
|
9
|
+
@auth_token = options[:auth_token]
|
10
|
+
end
|
11
|
+
|
12
|
+
def authorize(amount, source, gateway_options = {})
|
13
|
+
Response.new(parse_conekta_response(source.conekta_response), gateway_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def capture(amount, source, gateway_options = {})
|
17
|
+
Response.new({}, gateway_options)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def parse_conekta_response(response)
|
23
|
+
Oj.load response || '{}'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'celluloid'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Conekta
|
5
|
+
class PaymentNotificationHandler
|
6
|
+
include Celluloid
|
7
|
+
|
8
|
+
attr_reader :params, :action, :order, :delay
|
9
|
+
|
10
|
+
ACTIONS = Hash.new(:failure!).merge! 'charge.paid' => :capture!
|
11
|
+
|
12
|
+
def initialize(params, delay = 60)
|
13
|
+
@params = params
|
14
|
+
@delay = delay
|
15
|
+
@action = ACTIONS[params['type']]
|
16
|
+
@order = params['data']['object']['reference_id'].split('-').first
|
17
|
+
end
|
18
|
+
|
19
|
+
def perform_action
|
20
|
+
after(delay) do
|
21
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
22
|
+
payment.try(action)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def payment
|
30
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
31
|
+
Spree::Payment.find_by_order_number(order)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Spree::Conekta::PaymentSource
|
2
|
+
module Card
|
3
|
+
def request(common, method, gateway_options)
|
4
|
+
common['card'] = method.gateway_payment_profile_id
|
5
|
+
common['monthly_installments'] = installments_number(method)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.customer_address(gateway_options)
|
9
|
+
customer = gateway_options[:billing_address]
|
10
|
+
customer['street1'] = customer.delete(:address1)
|
11
|
+
customer['street2'] = customer.delete(:address2)
|
12
|
+
customer
|
13
|
+
end
|
14
|
+
|
15
|
+
def installments_number(source)
|
16
|
+
[3,6,9,12].include?(source.installments_number) ? source.installments_number : nil
|
17
|
+
end
|
18
|
+
|
19
|
+
module_function :request, :installments_number
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
module Spree::Conekta
|
2
|
+
class Provider
|
3
|
+
include Spree::Conekta::Client
|
4
|
+
|
5
|
+
attr_accessor :auth_token, :source_method
|
6
|
+
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
PAYMENT_SOURCES = {
|
10
|
+
'card' => Spree::Conekta::PaymentSource::Card,
|
11
|
+
'banorte' => Spree::Conekta::PaymentSource::Bank,
|
12
|
+
'spei' => Spree::Conekta::PaymentSource::Bank,
|
13
|
+
'oxxo' => Spree::Conekta::PaymentSource::Cash
|
14
|
+
}
|
15
|
+
|
16
|
+
def initialize(options = {})
|
17
|
+
@options = options
|
18
|
+
@auth_token = options[:auth_token]
|
19
|
+
@source_method = payment_processor(options[:source_method])
|
20
|
+
end
|
21
|
+
|
22
|
+
def authorize(amount, method_params, gateway_options = {})
|
23
|
+
common = build_common(amount, gateway_options)
|
24
|
+
commit common, method_params, gateway_options.merge({type: @options[:source_method]})
|
25
|
+
end
|
26
|
+
|
27
|
+
alias_method :purchase, :authorize
|
28
|
+
|
29
|
+
def capture(amount, method_params, gateway_options = {})
|
30
|
+
Response.new({}, gateway_options)
|
31
|
+
end
|
32
|
+
|
33
|
+
def endpoint
|
34
|
+
'charges'
|
35
|
+
end
|
36
|
+
|
37
|
+
def payment_processor(source_name)
|
38
|
+
PAYMENT_SOURCES[source_name]
|
39
|
+
end
|
40
|
+
|
41
|
+
def supports?(brand)
|
42
|
+
%w(visa master).include? brand
|
43
|
+
end
|
44
|
+
|
45
|
+
def credit(credit_cents, response_code, gateway_options)
|
46
|
+
Spree::Conekta::FakeResponse.new
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def commit(common, method_params, gateway_options)
|
52
|
+
source_method.request(common, method_params, gateway_options)
|
53
|
+
Spree::Conekta::Response.new post(common), source_method
|
54
|
+
end
|
55
|
+
|
56
|
+
def build_common(amount, gateway_params)
|
57
|
+
if source_method == Spree::Conekta::PaymentSource::Cash && gateway_params[:currency] != 'MXN'
|
58
|
+
return build_common_to_cash(amount, gateway_params)
|
59
|
+
else
|
60
|
+
{
|
61
|
+
'amount' => amount,
|
62
|
+
'reference_id' => gateway_params[:order_id],
|
63
|
+
'currency' => gateway_params[:currency],
|
64
|
+
'description' => gateway_params[:order_id],
|
65
|
+
'details' => details(gateway_params)
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def details(gateway_params)
|
71
|
+
{
|
72
|
+
'name' => gateway_params[:billing_address][:name],
|
73
|
+
'email' => gateway_params[:email],
|
74
|
+
'phone' => gateway_params[:billing_address][:phone],
|
75
|
+
'billing_address' => billing_address(gateway_params),
|
76
|
+
'line_items' => line_items(gateway_params),
|
77
|
+
'shipment' => shipment(gateway_params)
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
def shipping_address(gateway_params)
|
82
|
+
{
|
83
|
+
'street1' => gateway_params[:shipping_address][:address1],
|
84
|
+
'street2' => gateway_params[:shipping_address][:address2],
|
85
|
+
'city' => gateway_params[:shipping_address][:city],
|
86
|
+
'state' => gateway_params[:shipping_address][:state],
|
87
|
+
'country' => gateway_params[:shipping_address][:country],
|
88
|
+
'zip' => gateway_params[:shipping_address][:zip]
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
def billing_address(gateway_params)
|
93
|
+
{
|
94
|
+
'email' => gateway_params[:email],
|
95
|
+
'street1' => gateway_params[:billing_address][:address1],
|
96
|
+
'street2' => gateway_params[:billing_address][:address2],
|
97
|
+
'city' => gateway_params[:billing_address][:city],
|
98
|
+
'state' => gateway_params[:billing_address][:state],
|
99
|
+
'country' => gateway_params[:billing_address][:country],
|
100
|
+
'zip' => gateway_params[:billing_address][:zip]
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def line_items(gateway_params)
|
105
|
+
order = Spree::Order.find_by_number(gateway_params[:order_id].split('-').first)
|
106
|
+
order.line_items.map(&:to_conekta)
|
107
|
+
end
|
108
|
+
|
109
|
+
def shipment(gateway_params)
|
110
|
+
order = Spree::Order.find_by_number(gateway_params[:order_id].split('-').first)
|
111
|
+
shipment = order.shipments[0]
|
112
|
+
carrier = (shipment.present? ? shipment.shipping_method.name : "other")
|
113
|
+
traking_id = (shipment.present? ? shipment.tracking : nil)
|
114
|
+
{
|
115
|
+
'price' => gateway_params[:shipping],
|
116
|
+
'address' => shipping_address(gateway_params),
|
117
|
+
'service' => "other",
|
118
|
+
'carrier' => carrier,
|
119
|
+
'tracking_id' => traking_id
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
def build_common_to_cash(amount, gateway_params)
|
124
|
+
amount_exchanged = Spree::Conekta::Exchange.new(amount, gateway_params[:currency]).amount_exchanged
|
125
|
+
{
|
126
|
+
'amount' => amount_exchanged,
|
127
|
+
'reference_id' => gateway_params[:order_id],
|
128
|
+
'currency' => "MXN",
|
129
|
+
'description' => gateway_params[:order_id],
|
130
|
+
'details' => details(gateway_params)
|
131
|
+
}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Spree::Conekta
|
2
|
+
class Response < ActiveMerchant::Billing::Response
|
3
|
+
attr_accessor :response, :source_method, :status
|
4
|
+
|
5
|
+
def initialize(response, source_method)
|
6
|
+
@success = !(response.eql?('null') || response.include?('type')) if response
|
7
|
+
@message = @success ? 'Ok' : response['message']
|
8
|
+
@params = response
|
9
|
+
@params['message'] = @success ? 'Ok' : response['message_to_purchaser']
|
10
|
+
@status = response['status']
|
11
|
+
@source_method = source_method
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|