This repository has been archived by the owner on Apr 14, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from solidusio/end_to_end_transaction
End to end transaction
- Loading branch information
Showing
12 changed files
with
1,125 additions
and
5 deletions.
There are no files selected for viewing
107 changes: 106 additions & 1 deletion
107
app/assets/javascripts/spree/frontend/solidus_paypal_braintree.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,107 @@ | ||
// Placeholder manifest file. | ||
// the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/frontend/all.js' | ||
// the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/frontend/all.js' | ||
|
||
window.SolidusPaypalBraintree = { | ||
APPLE_PAY_API_VERSION: 1, | ||
|
||
initialize: function(authToken, clientReadyCallback) { | ||
braintree.client.create({ | ||
authorization: authToken | ||
}, function (clientErr, clientInstance) { | ||
if (clientErr) { | ||
console.error('Error creating client:', clientErr); | ||
return; | ||
} | ||
clientReadyCallback(clientInstance); | ||
}); | ||
}, | ||
|
||
setupApplePay: function(braintreeClient, merchantId, readyCallback) { | ||
if(window.ApplePaySession) { | ||
var promise = ApplePaySession.canMakePaymentsWithActiveCard(merchantId); | ||
promise.then(function (canMakePayments) { | ||
if (canMakePayments) { | ||
braintree.applePay.create({ | ||
client: braintreeClient | ||
}, function (applePayErr, applePayInstance) { | ||
if (applePayErr) { | ||
console.error("Error creating ApplePay:", applePayErr); | ||
return; | ||
} | ||
readyCallback(applePayInstance); | ||
}); | ||
} | ||
}); | ||
}; | ||
}, | ||
|
||
initializeApplePaySession: function(applePayInstance, storeName, paymentRequest, sessionCallback) { | ||
|
||
paymentRequest['requiredShippingContactFields'] = ['postalAddress', 'phone', 'email'] | ||
var paymentRequest = applePayInstance.createPaymentRequest(paymentRequest); | ||
|
||
var session = new ApplePaySession(SolidusPaypalBraintree.APPLE_PAY_API_VERSION, paymentRequest); | ||
session.onvalidatemerchant = function (event) { | ||
applePayInstance.performValidation({ | ||
validationURL: event.validationURL, | ||
displayName: storeName, | ||
}, function (validationErr, merchantSession) { | ||
if (validationErr) { | ||
console.error('Error validating Apple Pay:', validationErr); | ||
session.abort(); | ||
return; | ||
}; | ||
session.completeMerchantValidation(merchantSession); | ||
}); | ||
}; | ||
|
||
session.onpaymentauthorized = function (event) { | ||
applePayInstance.tokenize({ | ||
token: event.payment.token | ||
}, function (tokenizeErr, payload) { | ||
if (tokenizeErr) { | ||
console.error('Error tokenizing Apple Pay:', tokenizeErr); | ||
session.completePayment(ApplePaySession.STATUS_FAILURE); | ||
} | ||
session.completePayment(ApplePaySession.STATUS_SUCCESS); | ||
|
||
SolidusPaypalBraintree.setBraintreeApplePayContact(event.payment.shippingContact); | ||
SolidusPaypalBraintree.submitBraintreePayload(payload); | ||
}); | ||
}; | ||
|
||
sessionCallback(session); | ||
|
||
session.begin(); | ||
}, | ||
|
||
setBraintreeApplePayContact: function(appleContact) { | ||
var apple_map = { | ||
locality: 'city', | ||
countryCode: 'country_code', | ||
familyName: 'last_name', | ||
givenName: 'first_name', | ||
postalCode: 'zip', | ||
administrativeArea: 'state_code', | ||
} | ||
for (var key in apple_map) { | ||
document.querySelector("#transaction_address_attributes_" + apple_map[key]).value = appleContact[key]; | ||
} | ||
|
||
window.addressCon = appleContact; | ||
document.querySelector("#transaction_address_attributes_address_line_1").value = appleContact.addressLines[0]; | ||
|
||
if(appleContact.addressLines.length > 1) { | ||
document.querySelector("#transaction_address_attributes_address_line_2").value = appleContact.addressLines[1]; | ||
} | ||
|
||
document.querySelector("#transaction_phone").value = appleContact.phoneNumber; | ||
document.querySelector("#transaction_email").value = appleContact.emailAddress; | ||
}, | ||
|
||
submitBraintreePayload: function(payload) { | ||
document.querySelector("#transaction_nonce").value = payload.nonce; | ||
document.querySelector("#transaction_payment_type").value = payload.type; | ||
document.querySelector('#new_transaction').submit(); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
app/controllers/solidus_paypal_braintree/transactions_controller.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
class SolidusPaypalBraintree::TransactionsController < Spree::StoreController | ||
PERMITTED_BRAINTREE_TRANSACTION_PARAMS = [ | ||
:nonce, | ||
:payment_type, | ||
:phone, | ||
:email, | ||
address_attributes: [ | ||
:country_code, :last_name, :first_name, | ||
:city, :zip, :state_code, :address_line_1, :address_line_2 | ||
] | ||
] | ||
|
||
def create | ||
transaction = SolidusPaypalBraintree::Transaction.new transaction_params | ||
|
||
if transaction.valid? | ||
import = SolidusPaypalBraintree::TransactionImport.new(current_order, transaction) | ||
import.import! | ||
|
||
if import.order.complete? | ||
return redirect_to spree.order_path(import.order) | ||
else | ||
return redirect_to spree.checkout_state_path(import.order.state) | ||
end | ||
else | ||
render text: transaction.errors | ||
end | ||
end | ||
|
||
private | ||
|
||
def transaction_params | ||
params.require(:transaction) | ||
.permit(PERMITTED_BRAINTREE_TRANSACTION_PARAMS) | ||
.merge({ payment_method: payment_method }) | ||
end | ||
|
||
def payment_method | ||
SolidusPaypalBraintree::Gateway.find(params[:payment_method_id]) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require 'active_model' | ||
require 'solidus_paypal_braintree/transaction_address' | ||
|
||
module SolidusPaypalBraintree | ||
class Transaction | ||
include ActiveModel::Model | ||
|
||
attr_accessor :nonce, :payment_method, :payment_type, :address, :email, :phone | ||
|
||
validates :nonce, presence: true | ||
validates :payment_method, presence: true | ||
validates :payment_type, presence: true | ||
validates :phone, presence: true | ||
validates :email, presence: true | ||
|
||
validate do | ||
unless payment_method.is_a? SolidusPaypalBraintree::Gateway | ||
errors.add(:payment_method, 'Must be braintree') | ||
end | ||
end | ||
|
||
def address_attributes=(attributes) | ||
self.address = TransactionAddress.new attributes | ||
end | ||
end | ||
end |
10 changes: 10 additions & 0 deletions
10
app/models/solidus_paypal_braintree/transaction_address.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
require 'active_model' | ||
|
||
module SolidusPaypalBraintree | ||
class TransactionAddress | ||
include ActiveModel::Model | ||
|
||
attr_accessor :country_code, :last_name, :first_name, | ||
:city, :zip, :state_code, :address_line_1, :address_line_2 | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
require 'active_model' | ||
|
||
module SolidusPaypalBraintree | ||
class TransactionImport | ||
attr_reader :transaction, :order | ||
|
||
def initialize(order, transaction) | ||
@order = order | ||
@transaction = transaction | ||
end | ||
|
||
def source | ||
SolidusPaypalBraintree::Source.new nonce: transaction.nonce, | ||
payment_type: transaction.payment_type, | ||
user: user | ||
end | ||
|
||
def user | ||
order.user | ||
end | ||
|
||
def import! | ||
order.email = user.try!(:email) || transaction.email | ||
|
||
if address | ||
order.shipping_address = order.billing_address = address | ||
# work around a bug in most solidus versions | ||
# about tax zone cachine between address changes | ||
order.instance_variable_set("@tax_zone", nil) | ||
order.next | ||
end | ||
|
||
order.payments.new source: source, | ||
payment_method: transaction.payment_method, | ||
amount: order.total | ||
|
||
order.save! | ||
|
||
advance_order | ||
end | ||
|
||
def address | ||
transaction.address.try do |ta| | ||
country = Spree::Country.find_by(iso: ta.country_code.upcase) | ||
Spree::Address.new first_name: ta.first_name, | ||
last_name: ta.last_name, | ||
city: ta.city, | ||
country: country, | ||
state_name: ta.state_code, | ||
address1: ta.address_line_1, | ||
address2: ta.address_line_2, | ||
zipcode: ta.zip, | ||
phone: transaction.phone | ||
end | ||
end | ||
|
||
protected | ||
|
||
def advance_order | ||
order.next! until order.state == "confirm" | ||
end | ||
end | ||
end |
16 changes: 16 additions & 0 deletions
16
app/views/solidus_paypal_braintree/_transaction_form.html.erb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<%= form_for [main_app, SolidusPaypalBraintree::Transaction.new], id: 'braintree_complete_form', as: :transaction do |f| %> | ||
<%= f.hidden_field :nonce %> | ||
<%= f.hidden_field :payment_type %> | ||
<%= hidden_field_tag :payment_method_id, payment_method.id %> | ||
<%= f.hidden_field :phone %> | ||
<%= f.hidden_field :email %> | ||
|
||
<%= f.fields_for :address, SolidusPaypalBraintree::TransactionAddress.new do |fa| %> | ||
<% [:country_code, :last_name, :first_name, | ||
:city, :zip, :state_code, | ||
:address_line_1, :address_line_2].each do |address_field| %> | ||
<%= fa.hidden_field address_field %> | ||
<% end %> | ||
<% end %> | ||
|
||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
Rails.application.routes.draw do | ||
namespace :solidus_paypal_braintree do | ||
resource :checkout, only: [:update, :edit] | ||
|
||
resource :transactions, only: [:create] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.