solidus_conekta_card 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +26 -0
- data/README.md +39 -0
- data/Rakefile +23 -0
- data/app/assets/javascripts/spree/backend/solidus_conekta_card.js +24 -0
- data/app/assets/javascripts/spree/conekta.js +1213 -0
- data/app/assets/javascripts/spree/frontend/solidus_conekta_card.js +24 -0
- data/app/assets/stylesheets/spree/backend/solidus_conekta_card.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_conekta_card.css +4 -0
- data/app/controllers/spree/admin/payments_controller_decorator.rb +39 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +27 -0
- data/app/models/spree/gateway/conekta_card_gateway.rb +73 -0
- data/app/models/spree/payment_method/conekta_card.rb +29 -0
- data/app/views/spree/admin/payments/source_forms/_conekta_card.html.erb +56 -0
- data/app/views/spree/admin/payments/source_views/_conekta_card.html.erb +1 -0
- data/app/views/spree/api/source_views/_conekta_card.json.jbuilder +1 -0
- data/app/views/spree/checkout/payment/_conekta_card.html.erb +57 -0
- data/config/locales/en.yml +8 -0
- data/config/locales/es-MX.yml +6 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20181204175053_create_conekta_card_payments.rb +9 -0
- data/lib/generators/solidus_conekta_card/install/install_generator.rb +34 -0
- data/lib/solidus_conekta_card/engine.rb +26 -0
- data/lib/solidus_conekta_card/factories.rb +8 -0
- data/lib/solidus_conekta_card/version.rb +5 -0
- data/lib/solidus_conekta_card.rb +6 -0
- metadata +312 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
$(document).ready(function() {
|
2
|
+
|
3
|
+
var conektaSuccessResponseHandler = function(token) {
|
4
|
+
var $form = $("#checkout_form_payment");
|
5
|
+
//Add the token_id in the form
|
6
|
+
$form.append($('<input type="hidden" name="conektaTokenId" id="conektaTokenId">').val(token.id));
|
7
|
+
$form.get(0).submit(); //Submit
|
8
|
+
};
|
9
|
+
var conektaErrorResponseHandler = function(response) {
|
10
|
+
var $form = $("#checkout_form_payment");
|
11
|
+
$form.find(".card-errors").text(response.message_to_purchaser);
|
12
|
+
};
|
13
|
+
|
14
|
+
//jQuery generate the token on submit.
|
15
|
+
$(function () {
|
16
|
+
$("#checkout_form_payment").submit(function(event) {
|
17
|
+
var $form = $(this);
|
18
|
+
if ($(creditCardPaymentId).prop('checked')) {
|
19
|
+
Conekta.Token.create($form, conektaSuccessResponseHandler, conektaErrorResponseHandler);
|
20
|
+
return false;
|
21
|
+
}
|
22
|
+
});
|
23
|
+
});
|
24
|
+
});
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AdminPaymentsDecorator
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
def create
|
8
|
+
@payment = Spree::PaymentCreate.new(@order, object_params).build
|
9
|
+
if @payment.payment_method.source_required? && params[:card].present? && params[:card] != 'new'
|
10
|
+
@payment.source = @payment.payment_method.payment_source_class.find_by(id: params[:card])
|
11
|
+
end
|
12
|
+
|
13
|
+
if @payment.save
|
14
|
+
if @order.completed?
|
15
|
+
# If the order was already complete then go ahead and process the payment
|
16
|
+
# (auth and/or capture depending on payment method configuration)
|
17
|
+
if params[:conektaTokenId]
|
18
|
+
@order.payments.last.source.update_attributes(gateway_payment_profile_id: params[:conektaTokenId])
|
19
|
+
end
|
20
|
+
@payment.process! if @payment.checkout?
|
21
|
+
else
|
22
|
+
# Transition order as far as it will go.
|
23
|
+
while @order.next; end
|
24
|
+
end
|
25
|
+
|
26
|
+
flash[:success] = flash_message_for(@payment, :successfully_created)
|
27
|
+
redirect_to admin_order_payments_path(@order)
|
28
|
+
else
|
29
|
+
flash[:error] = t('spree.payment_could_not_be_created')
|
30
|
+
render :new
|
31
|
+
end
|
32
|
+
rescue Spree::Core::GatewayError => e
|
33
|
+
flash[:error] = e.message.to_s
|
34
|
+
redirect_to new_admin_order_payment_path(@order)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Spree::Admin::PaymentsController.include(AdminPaymentsDecorator)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Spree::CheckoutController.class_eval do
|
4
|
+
def update
|
5
|
+
if update_order
|
6
|
+
assign_temp_address
|
7
|
+
|
8
|
+
if params[:conektaTokenId]
|
9
|
+
@order.payments.last.source.update_attributes(gateway_payment_profile_id: params[:conektaTokenId])
|
10
|
+
end
|
11
|
+
|
12
|
+
unless transition_forward
|
13
|
+
redirect_on_failure
|
14
|
+
return
|
15
|
+
end
|
16
|
+
|
17
|
+
if @order.completed?
|
18
|
+
finalize_order
|
19
|
+
else
|
20
|
+
send_to_next_state
|
21
|
+
end
|
22
|
+
|
23
|
+
else
|
24
|
+
render :edit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'conekta'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class Gateway::ConektaCardGateway < Spree::CreditCard
|
5
|
+
attr_accessor :server, :test_mode, :auth_token, :public_auth_token, :source_method
|
6
|
+
|
7
|
+
def purchase(money, source, gateway_options)
|
8
|
+
::Conekta.api_key = auth_token ? auth_token : ''
|
9
|
+
::Conekta.api_version = '2.0.0'
|
10
|
+
|
11
|
+
begin
|
12
|
+
order = Spree::Order.find(gateway_options[:originator].order_id)
|
13
|
+
|
14
|
+
unless order.conekta_order_id
|
15
|
+
conekta_order = ::Conekta::Order.create(payload(order, source))
|
16
|
+
end
|
17
|
+
|
18
|
+
conekta_order = ::Conekta::Order.find(order.conekta_order_id)
|
19
|
+
ActiveMerchant::Billing::Response.new(true, 'Orden creada satisfactoriamente', {}, parse_response(conekta_order))
|
20
|
+
rescue ::Conekta::Error => error
|
21
|
+
ActiveMerchant::Billing::Response.new(false, error.details.map(&:message).join(', '))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def name
|
26
|
+
'Conekta Card'
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def payload(order, source)
|
32
|
+
{
|
33
|
+
currency: 'MXN',
|
34
|
+
customer_info: {
|
35
|
+
name: order.ship_address.full_name,
|
36
|
+
email: order.email,
|
37
|
+
phone: order.ship_address.phone
|
38
|
+
},
|
39
|
+
charges: [
|
40
|
+
{
|
41
|
+
payment_method: {
|
42
|
+
type: 'card',
|
43
|
+
token_id: source.gateway_payment_profile_id
|
44
|
+
}
|
45
|
+
}
|
46
|
+
],
|
47
|
+
line_items: order_line_items(order),
|
48
|
+
shipping_lines: shipping_lines(order),
|
49
|
+
shipping_contact: {
|
50
|
+
address: {
|
51
|
+
street1: order.ship_address.address1,
|
52
|
+
postal_code: order.ship_address.zipcode,
|
53
|
+
country: 'MX'
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def order_line_items(order)
|
60
|
+
order.line_items.map { |li| {name: li.product.name, unit_price: (li.price * 100).to_i, quantity: li.quantity} }
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_response(response)
|
64
|
+
{
|
65
|
+
conekta_order_id: response.id
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def shipping_lines(order)
|
70
|
+
order.shipments.map {|s| {id: s.id, carrier: s.shipping_method.name, amount: (s.cost * 100).to_i} }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class PaymentMethod::ConektaCard < PaymentMethod::CreditCard
|
5
|
+
preference :auth_token, :string
|
6
|
+
preference :public_auth_token, :string
|
7
|
+
preference :source_method, :string, default: 'card'
|
8
|
+
|
9
|
+
def auto_capture
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def partial_name
|
14
|
+
'conekta_card'
|
15
|
+
end
|
16
|
+
|
17
|
+
def gateway_class
|
18
|
+
Spree::Gateway::ConektaCardGateway
|
19
|
+
end
|
20
|
+
|
21
|
+
def payment_source_class
|
22
|
+
Spree::Gateway::ConektaCardGateway
|
23
|
+
end
|
24
|
+
|
25
|
+
def payment_profiles_supported?
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
<% param_prefix = "payment_source[#{payment_method.id}]" %>
|
2
|
+
<span class="card-errors"></span>
|
3
|
+
<div>
|
4
|
+
<label>
|
5
|
+
<span>Cardholder name</span>
|
6
|
+
<%= text_field_tag "#{param_prefix}[name]",
|
7
|
+
"#{@order.billing_firstname} #{@order.billing_lastname}",
|
8
|
+
{ id: "name_on_card_#{payment_method.id}",
|
9
|
+
data: { conekta: 'card[name]' } } %>
|
10
|
+
</label>
|
11
|
+
</div>
|
12
|
+
<div>
|
13
|
+
<label>
|
14
|
+
<span>Card number</span>
|
15
|
+
<% options_hash = Rails.env.production? ? { autocomplete: 'off' } : {} %>
|
16
|
+
<%= text_field_tag "#{param_prefix}[number]",
|
17
|
+
'',
|
18
|
+
options_hash.merge(id: 'card_number',
|
19
|
+
class: 'required cardNumber',
|
20
|
+
size: 19,
|
21
|
+
maxlength: 19,
|
22
|
+
autocomplete: "off",
|
23
|
+
data: { conekta: 'card[number]' }) %>
|
24
|
+
</label>
|
25
|
+
</div>
|
26
|
+
<div>
|
27
|
+
<label>
|
28
|
+
<span>CVC</span>
|
29
|
+
<%= text_field_tag "#{param_prefix}[verification_value]",
|
30
|
+
'',
|
31
|
+
options_hash.merge(id: 'card_code',
|
32
|
+
class: 'required cardCode',
|
33
|
+
size: 5,
|
34
|
+
data: { conekta: 'card[cvc]' } ) %>
|
35
|
+
</label>
|
36
|
+
</div>
|
37
|
+
<div>
|
38
|
+
<label>
|
39
|
+
<span>Expiration date (MM/YYYY)</span>
|
40
|
+
<%= select_month(Date.today,
|
41
|
+
{ prefix: param_prefix, field_name: 'month', use_month_numbers: true },
|
42
|
+
class: 'required',
|
43
|
+
id: "card_month",
|
44
|
+
data: { conekta: 'card[exp_month]' }) %>
|
45
|
+
</label>
|
46
|
+
<span>/</span>
|
47
|
+
<%= select_year(Date.today,
|
48
|
+
{ prefix: param_prefix, field_name: 'year', start_year: Date.today.year, end_year: Date.today.year + 15 },
|
49
|
+
class: 'required',
|
50
|
+
id: "card_year",
|
51
|
+
data: { conekta: 'card[exp_year]' }) %>
|
52
|
+
</div>
|
53
|
+
<%= javascript_tag do %>
|
54
|
+
var creditCardPaymentId = '#order_payments_attributes__payment_method_id_<%= payment_method.id %>'
|
55
|
+
Conekta.setPublicKey('<%= payment_method.preferences[:public_auth_token] %>');
|
56
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render "spree/admin/payments/source_views/gateway", payment: payment %>
|
@@ -0,0 +1 @@
|
|
1
|
+
# frozen_string_literal: true
|
@@ -0,0 +1,57 @@
|
|
1
|
+
<% param_prefix = "payment_source[#{payment_method.id}]" %>
|
2
|
+
<span class="card-errors"></span>
|
3
|
+
<div>
|
4
|
+
<label>
|
5
|
+
<span>Cardholder name</span>
|
6
|
+
<%= text_field_tag "#{param_prefix}[name]",
|
7
|
+
"#{@order.billing_firstname} #{@order.billing_lastname}",
|
8
|
+
{ id: "name_on_card_#{payment_method.id}",
|
9
|
+
data: { conekta: 'card[name]' } } %>
|
10
|
+
</label>
|
11
|
+
</div>
|
12
|
+
<div>
|
13
|
+
<label>
|
14
|
+
<span>Card number</span>
|
15
|
+
<% options_hash = Rails.env.production? ? { autocomplete: 'off' } : {} %>
|
16
|
+
<%= text_field_tag "#{param_prefix}[number]",
|
17
|
+
'',
|
18
|
+
options_hash.merge(id: 'card_number',
|
19
|
+
class: 'required cardNumber',
|
20
|
+
size: 19,
|
21
|
+
maxlength: 19,
|
22
|
+
autocomplete: "off",
|
23
|
+
data: { conekta: 'card[number]' }) %>
|
24
|
+
</label>
|
25
|
+
</div>
|
26
|
+
<div>
|
27
|
+
<label>
|
28
|
+
<span>CVC</span>
|
29
|
+
<%= text_field_tag "#{param_prefix}[verification_value]",
|
30
|
+
'',
|
31
|
+
options_hash.merge(id: 'card_code',
|
32
|
+
class: 'required cardCode',
|
33
|
+
size: 5,
|
34
|
+
data: { conekta: 'card[cvc]' } ) %>
|
35
|
+
</label>
|
36
|
+
</div>
|
37
|
+
<div>
|
38
|
+
<label>
|
39
|
+
<span>Expiration date (MM/YYYY)</span>
|
40
|
+
<%= select_month(Date.today,
|
41
|
+
{ prefix: param_prefix, field_name: 'month', use_month_numbers: true },
|
42
|
+
class: 'required',
|
43
|
+
id: "card_month",
|
44
|
+
data: { conekta: 'card[exp_month]' }) %>
|
45
|
+
</label>
|
46
|
+
<span>/</span>
|
47
|
+
<%= select_year(Date.today,
|
48
|
+
{ prefix: param_prefix, field_name: 'year', start_year: Date.today.year, end_year: Date.today.year + 15 },
|
49
|
+
class: 'required',
|
50
|
+
id: "card_year",
|
51
|
+
data: { conekta: 'card[exp_year]' }) %>
|
52
|
+
</div>
|
53
|
+
|
54
|
+
<%= javascript_tag do %>
|
55
|
+
var creditCardPaymentId = '#order_payments_attributes__payment_method_id_<%= payment_method.id %>'
|
56
|
+
Conekta.setPublicKey('<%= payment_method.preferences[:public_auth_token] %>');
|
57
|
+
<% end %>
|
@@ -0,0 +1,8 @@
|
|
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
|
+
activerecord:
|
6
|
+
attributes:
|
7
|
+
spree/gateway/conekta_card_gateway:
|
8
|
+
number: Card Number
|
data/config/routes.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusConektaCard
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
class_option :auto_run_migrations, type: :boolean, default: false
|
7
|
+
|
8
|
+
def add_javascripts
|
9
|
+
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/conekta\n"
|
10
|
+
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_conekta_card\n"
|
11
|
+
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_conekta_card\n"
|
12
|
+
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/conekta\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_stylesheets
|
16
|
+
inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_conekta_card\n", before: /\*\//, verbose: true
|
17
|
+
inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_conekta_card\n", before: /\*\//, verbose: true
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_migrations
|
21
|
+
run 'bundle exec rake railties:install:migrations FROM=solidus_conekta_card'
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_migrations
|
25
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
|
26
|
+
if run_migrations
|
27
|
+
run 'bundle exec rake db:migrate'
|
28
|
+
else
|
29
|
+
puts 'Skipping rake db:migrate, don\'t forget to run it!'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusConektaCard
|
4
|
+
class Engine < Rails::Engine
|
5
|
+
require 'spree/core'
|
6
|
+
isolate_namespace Spree
|
7
|
+
engine_name 'solidus_conekta_card'
|
8
|
+
|
9
|
+
# use rspec for tests
|
10
|
+
config.generators do |g|
|
11
|
+
g.test_framework :rspec
|
12
|
+
end
|
13
|
+
|
14
|
+
initializer 'spree_payment_network.register.payment_methods' do |app|
|
15
|
+
app.config.spree.payment_methods << Spree::PaymentMethod::ConektaCard
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.activate
|
19
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
|
20
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
config.to_prepare(&method(:activate).to_proc)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
FactoryBot.define do
|
4
|
+
# Define your Spree extensions Factories within this file to enable applications, and other extensions to use and override them.
|
5
|
+
#
|
6
|
+
# Example adding this to your spec_helper will load these Factories for use:
|
7
|
+
# require 'solidus_conekta_card/factories'
|
8
|
+
end
|