solidus_paypal_braintree 0.1.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 +196 -0
- data/Rakefile +30 -0
- data/app/assets/javascripts/spree/backend/solidus_paypal_braintree.js +66 -0
- data/app/assets/javascripts/spree/braintree_hosted_form.js +98 -0
- data/app/assets/javascripts/spree/checkout/braintree.js +60 -0
- data/app/assets/javascripts/spree/frontend/paypal_button.js +182 -0
- data/app/assets/javascripts/spree/frontend/solidus_paypal_braintree.js +188 -0
- data/app/assets/stylesheets/spree/backend/solidus_paypal_braintree.scss +28 -0
- data/app/assets/stylesheets/spree/frontend/solidus_paypal_braintree.css +16 -0
- data/app/controllers/solidus_paypal_braintree/client_tokens_controller.rb +21 -0
- data/app/helpers/braintree_admin_helper.rb +18 -0
- data/app/models/application_record.rb +3 -0
- data/app/models/solidus_paypal_braintree/configuration.rb +5 -0
- data/app/models/solidus_paypal_braintree/customer.rb +4 -0
- data/app/models/solidus_paypal_braintree/gateway.rb +323 -0
- data/app/models/solidus_paypal_braintree/response.rb +52 -0
- data/app/models/solidus_paypal_braintree/source.rb +73 -0
- data/app/models/solidus_paypal_braintree/transaction.rb +30 -0
- data/app/models/solidus_paypal_braintree/transaction_address.rb +66 -0
- data/app/models/solidus_paypal_braintree/transaction_import.rb +92 -0
- data/app/models/spree/store_decorator.rb +11 -0
- data/app/overrides/admin_navigation_menu.rb +6 -0
- data/app/views/spree/shared/_braintree_hosted_fields.html.erb +26 -0
- data/config/initializers/braintree.rb +1 -0
- data/config/locales/en.yml +30 -0
- data/config/routes.rb +12 -0
- data/db/migrate/20160830061749_create_solidus_paypal_braintree_sources.rb +16 -0
- data/db/migrate/20160906201711_create_solidus_paypal_braintree_customers.rb +11 -0
- data/db/migrate/20161114231422_create_solidus_paypal_braintree_configurations.rb +11 -0
- data/db/migrate/20161125172005_add_braintree_configuration_to_stores.rb +9 -0
- data/db/migrate/20170203191030_add_credit_card_to_braintree_configuration.rb +6 -0
- data/db/migrate/20170505193712_add_null_constraint_to_sources.rb +30 -0
- data/db/migrate/20170508085402_add_not_null_constraint_to_sources_payment_type.rb +11 -0
- data/lib/controllers/backend/solidus_paypal_braintree/configurations_controller.rb +30 -0
- data/lib/controllers/frontend/solidus_paypal_braintree/checkouts_controller.rb +27 -0
- data/lib/controllers/frontend/solidus_paypal_braintree/transactions_controller.rb +61 -0
- data/lib/generators/solidus_paypal_braintree/install/install_generator.rb +37 -0
- data/lib/solidus_paypal_braintree.rb +10 -0
- data/lib/solidus_paypal_braintree/country_mapper.rb +35 -0
- data/lib/solidus_paypal_braintree/engine.rb +53 -0
- data/lib/solidus_paypal_braintree/factories.rb +18 -0
- data/lib/solidus_paypal_braintree/version.rb +3 -0
- data/lib/views/backend/solidus_paypal_braintree/configurations/_admin_tab.html.erb +3 -0
- data/lib/views/backend/solidus_paypal_braintree/configurations/list.html.erb +30 -0
- data/lib/views/backend/spree/admin/payments/source_forms/_paypal_braintree.html.erb +16 -0
- data/lib/views/backend/spree/admin/payments/source_views/_paypal_braintree.html.erb +34 -0
- data/lib/views/backend_v1.2/spree/admin/payments/source_forms/_paypal_braintree.html.erb +16 -0
- data/lib/views/frontend/spree/checkout/payment/_paypal_braintree.html.erb +52 -0
- metadata +350 -0
@@ -0,0 +1,182 @@
|
|
1
|
+
/**
|
2
|
+
* Constructor for PayPal button object
|
3
|
+
* @constructor
|
4
|
+
* @param {object} element - The DOM element of your PayPal button
|
5
|
+
*/
|
6
|
+
function PaypalButton(element) {
|
7
|
+
this.element = element;
|
8
|
+
}
|
9
|
+
|
10
|
+
/**
|
11
|
+
* Creates the PayPal session using the provided options and enables the button
|
12
|
+
*
|
13
|
+
* @param {object} options - The options passed to tokenize when constructing
|
14
|
+
* the PayPal instance
|
15
|
+
*
|
16
|
+
* See {@link https://braintree.github.io/braintree-web/3.9.0/PayPal.html#tokenize}
|
17
|
+
*/
|
18
|
+
PaypalButton.prototype.initialize = function(options) {
|
19
|
+
var self = this;
|
20
|
+
|
21
|
+
/* This sets the payment method id returned by fetchToken on the PaypalButton
|
22
|
+
* instance so that we can use it to build the transaction params later. */
|
23
|
+
SolidusPaypalBraintree.fetchToken(function(token, paymentMethodId) {
|
24
|
+
self.paymentMethodId = paymentMethodId;
|
25
|
+
|
26
|
+
SolidusPaypalBraintree.initializeWithDataCollector(token, function(client) {
|
27
|
+
self.createPaypalInstance(client, function(paypal) {
|
28
|
+
|
29
|
+
self.initializePaypalSession({
|
30
|
+
paypalInstance: paypal,
|
31
|
+
paypalButton: self.element,
|
32
|
+
paypalOptions: options
|
33
|
+
}, self.tokenizeCallback.bind(self));
|
34
|
+
});
|
35
|
+
|
36
|
+
});
|
37
|
+
});
|
38
|
+
};
|
39
|
+
|
40
|
+
PaypalButton.prototype.createPaypalInstance = function(braintreeClient, readyCallback) {
|
41
|
+
braintree.paypal.create({
|
42
|
+
client: braintreeClient
|
43
|
+
}, function (paypalErr, paypalInstance) {
|
44
|
+
if (paypalErr) {
|
45
|
+
console.error("Error creating PayPal:", paypalErr);
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
readyCallback(paypalInstance);
|
49
|
+
});
|
50
|
+
};
|
51
|
+
|
52
|
+
/* Initializes and begins the Paypal session
|
53
|
+
*
|
54
|
+
* @param config Configuration settings for the session
|
55
|
+
* @param config.paypalInstance {object} The Paypal instance returned by Braintree
|
56
|
+
* @param config.paypalButton {object} The button DOM element
|
57
|
+
* @param config.paypalOptions {object} Configuration options for Paypal
|
58
|
+
* @param config.error {tokenizeErrorCallback} Callback function for tokenize errors
|
59
|
+
* @param {tokenizeCallback} callback Callback function for tokenization
|
60
|
+
*/
|
61
|
+
PaypalButton.prototype.initializePaypalSession = function(config, callback) {
|
62
|
+
config.paypalButton.removeAttribute('disabled');
|
63
|
+
config.paypalButton.addEventListener('click', function(event) {
|
64
|
+
config.paypalInstance.tokenize(config.paypalOptions, callback);
|
65
|
+
}, false);
|
66
|
+
},
|
67
|
+
|
68
|
+
/**
|
69
|
+
* Default callback function for when tokenization completes
|
70
|
+
*
|
71
|
+
* @param {object|null} tokenizeErr - The error returned by Braintree on failure
|
72
|
+
* @param {object} payload - The payload returned by Braintree on success
|
73
|
+
*/
|
74
|
+
PaypalButton.prototype.tokenizeCallback = function(tokenizeErr, payload) {
|
75
|
+
if (tokenizeErr) {
|
76
|
+
console.error('Error tokenizing:', tokenizeErr);
|
77
|
+
} else {
|
78
|
+
var params = this.transactionParams(payload);
|
79
|
+
|
80
|
+
Spree.ajax({
|
81
|
+
url: Spree.pathFor("solidus_paypal_braintree/transactions"),
|
82
|
+
type: 'POST',
|
83
|
+
dataType: 'json',
|
84
|
+
data: params,
|
85
|
+
success: function(response) {
|
86
|
+
window.location.href = response.redirectUrl;
|
87
|
+
},
|
88
|
+
error: function(xhr) {
|
89
|
+
console.error("Error submitting transaction")
|
90
|
+
},
|
91
|
+
});
|
92
|
+
}
|
93
|
+
};
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Assigns a new callback function for when tokenization completes
|
97
|
+
*
|
98
|
+
* @callback callback - The callback function to assign
|
99
|
+
*/
|
100
|
+
PaypalButton.prototype.setTokenizeCallback = function(callback) {
|
101
|
+
this.tokenizeCallback = callback;
|
102
|
+
};
|
103
|
+
|
104
|
+
/**
|
105
|
+
* Builds the transaction parameters to submit to Solidus for the given
|
106
|
+
* payload returned by Braintree
|
107
|
+
*
|
108
|
+
* @param {object} payload - The payload returned by Braintree after tokenization
|
109
|
+
*/
|
110
|
+
PaypalButton.prototype.transactionParams = function(payload) {
|
111
|
+
return {
|
112
|
+
"payment_method_id" : this.paymentMethodId,
|
113
|
+
"transaction" : {
|
114
|
+
"email" : payload.details.email,
|
115
|
+
"phone" : payload.details.phone,
|
116
|
+
"nonce" : payload.nonce,
|
117
|
+
"payment_type" : payload.type,
|
118
|
+
"address_attributes" : this.addressParams(payload)
|
119
|
+
}
|
120
|
+
}
|
121
|
+
};
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Builds the address parameters to submit to Solidus using the payload
|
125
|
+
* returned by Braintree
|
126
|
+
*
|
127
|
+
* @param {object} payload - The payload returned by Braintree after tokenization
|
128
|
+
*/
|
129
|
+
PaypalButton.prototype.addressParams = function(payload) {
|
130
|
+
if (payload.details.shippingAddress.recipientName) {
|
131
|
+
var first_name = payload.details.shippingAddress.recipientName.split(" ")[0];
|
132
|
+
var last_name = payload.details.shippingAddress.recipientName.split(" ")[1];
|
133
|
+
}
|
134
|
+
if (first_name == null || last_name == null) {
|
135
|
+
var first_name = payload.details.firstName;
|
136
|
+
var last_name = payload.details.lastName;
|
137
|
+
}
|
138
|
+
|
139
|
+
return {
|
140
|
+
"first_name" : first_name,
|
141
|
+
"last_name" : last_name,
|
142
|
+
"address_line_1" : payload.details.shippingAddress.line1,
|
143
|
+
"address_line_2" : payload.details.shippingAddress.line2,
|
144
|
+
"city" : payload.details.shippingAddress.city,
|
145
|
+
"state_code" : payload.details.shippingAddress.state,
|
146
|
+
"zip" : payload.details.shippingAddress.postalCode,
|
147
|
+
"country_code" : payload.details.shippingAddress.countryCode
|
148
|
+
}
|
149
|
+
};
|
150
|
+
|
151
|
+
$(document).ready(function() {
|
152
|
+
if (document.getElementById("empty-cart")) {
|
153
|
+
$.when(
|
154
|
+
$.getScript("https://js.braintreegateway.com/web/3.9.0/js/client.min.js"),
|
155
|
+
$.getScript("https://js.braintreegateway.com/web/3.9.0/js/paypal.min.js"),
|
156
|
+
$.getScript("https://js.braintreegateway.com/web/3.9.0/js/data-collector.min.js"),
|
157
|
+
$.Deferred(function( deferred ){
|
158
|
+
$( deferred.resolve );
|
159
|
+
})
|
160
|
+
).done(function() {
|
161
|
+
$('<script/>').attr({
|
162
|
+
'data-merchant' : "braintree",
|
163
|
+
'data-id' : "paypal-button",
|
164
|
+
'data-button' : "checkout",
|
165
|
+
'data-color' : "blue",
|
166
|
+
'data-size' : "medium",
|
167
|
+
'data-shape' : "pill",
|
168
|
+
'data-button_type' : "button",
|
169
|
+
'data-button_disabled' : "true"
|
170
|
+
}).
|
171
|
+
load(function() {
|
172
|
+
var button = new PaypalButton(document.querySelector("#paypal-button"));
|
173
|
+
button.initialize({
|
174
|
+
flow: 'vault',
|
175
|
+
enableShippingAddress: true,
|
176
|
+
});
|
177
|
+
}).
|
178
|
+
insertAfter("#content").
|
179
|
+
attr('src', 'https://www.paypalobjects.com/api/button.js?')
|
180
|
+
});
|
181
|
+
}
|
182
|
+
});
|
@@ -0,0 +1,188 @@
|
|
1
|
+
//= require spree/braintree_hosted_form
|
2
|
+
|
3
|
+
window.SolidusPaypalBraintree = {
|
4
|
+
APPLE_PAY_API_VERSION: 1,
|
5
|
+
|
6
|
+
// Override to provide your own error messages.
|
7
|
+
braintreeErrorHandle: function(braintreeError) {
|
8
|
+
var $contentContainer = $("#content");
|
9
|
+
var $flash = $("<div class='flash error'>" + braintreeError.name + ": " + braintreeError.message + "</div>");
|
10
|
+
$contentContainer.prepend($flash);
|
11
|
+
|
12
|
+
$flash.show().delay(5000).fadeOut(500);
|
13
|
+
},
|
14
|
+
|
15
|
+
fetchToken: function(tokenCallback) {
|
16
|
+
Spree.ajax({
|
17
|
+
dataType: 'json',
|
18
|
+
type: 'POST',
|
19
|
+
url: Spree.pathFor('solidus_paypal_braintree/client_token'),
|
20
|
+
success: function(response) {
|
21
|
+
tokenCallback(response.client_token, response.payment_method_id);
|
22
|
+
},
|
23
|
+
error: function(xhr) {
|
24
|
+
console.error("Error fetching braintree token");
|
25
|
+
}
|
26
|
+
});
|
27
|
+
},
|
28
|
+
|
29
|
+
initialize: function(authToken, clientReadyCallback) {
|
30
|
+
braintree.client.create({
|
31
|
+
authorization: authToken
|
32
|
+
}, function (clientErr, clientInstance) {
|
33
|
+
if (clientErr) {
|
34
|
+
console.error('Error creating client:', clientErr);
|
35
|
+
return;
|
36
|
+
}
|
37
|
+
clientReadyCallback(clientInstance);
|
38
|
+
});
|
39
|
+
},
|
40
|
+
|
41
|
+
initializeWithDataCollector: function(authToken, clientReadyCallback) {
|
42
|
+
braintree.client.create({
|
43
|
+
authorization: authToken
|
44
|
+
}, function (clientErr, clientInstance) {
|
45
|
+
braintree.dataCollector.create({
|
46
|
+
client: clientInstance,
|
47
|
+
paypal: true
|
48
|
+
}, function (err, dataCollectorInstance) {
|
49
|
+
if (err) {
|
50
|
+
console.error('Error creating data collector:', err);
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
});
|
54
|
+
if (clientErr) {
|
55
|
+
console.error('Error creating client:', clientErr);
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
clientReadyCallback(clientInstance);
|
59
|
+
});
|
60
|
+
},
|
61
|
+
|
62
|
+
setupApplePay: function(braintreeClient, merchantId, readyCallback) {
|
63
|
+
if(window.ApplePaySession && location.protocol == "https:") {
|
64
|
+
var promise = ApplePaySession.canMakePaymentsWithActiveCard(merchantId);
|
65
|
+
promise.then(function (canMakePayments) {
|
66
|
+
if (canMakePayments) {
|
67
|
+
braintree.applePay.create({
|
68
|
+
client: braintreeClient
|
69
|
+
}, function (applePayErr, applePayInstance) {
|
70
|
+
if (applePayErr) {
|
71
|
+
console.error("Error creating ApplePay:", applePayErr);
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
readyCallback(applePayInstance);
|
75
|
+
});
|
76
|
+
}
|
77
|
+
});
|
78
|
+
};
|
79
|
+
},
|
80
|
+
|
81
|
+
/* Initializes and begins the ApplePay session
|
82
|
+
*
|
83
|
+
* @param config Configuration settings for the session
|
84
|
+
* @param config.applePayInstance {object} The instance returned from applePay.create
|
85
|
+
* @param config.storeName {String} The name of the store
|
86
|
+
* @param config.paymentRequest {object} The payment request to submit
|
87
|
+
* @param config.currentUserEmail {String|undefined} The active user's email
|
88
|
+
* @param config.paymentMethodId {Integer} The SolidusPaypalBraintree::Gateway id
|
89
|
+
*/
|
90
|
+
initializeApplePaySession: function(config, sessionCallback) {
|
91
|
+
|
92
|
+
var requiredFields = ['postalAddress', 'phone'];
|
93
|
+
|
94
|
+
if (!config.currentUserEmail) {
|
95
|
+
requiredFields.push('email');
|
96
|
+
}
|
97
|
+
|
98
|
+
config.paymentRequest['requiredShippingContactFields'] = requiredFields
|
99
|
+
var paymentRequest = config.applePayInstance.createPaymentRequest(config.paymentRequest);
|
100
|
+
|
101
|
+
var session = new ApplePaySession(SolidusPaypalBraintree.APPLE_PAY_API_VERSION, paymentRequest);
|
102
|
+
session.onvalidatemerchant = function (event) {
|
103
|
+
config.applePayInstance.performValidation({
|
104
|
+
validationURL: event.validationURL,
|
105
|
+
displayName: config.storeName,
|
106
|
+
}, function (validationErr, merchantSession) {
|
107
|
+
if (validationErr) {
|
108
|
+
console.error('Error validating Apple Pay:', validationErr);
|
109
|
+
session.abort();
|
110
|
+
return;
|
111
|
+
};
|
112
|
+
session.completeMerchantValidation(merchantSession);
|
113
|
+
});
|
114
|
+
};
|
115
|
+
|
116
|
+
session.onpaymentauthorized = function (event) {
|
117
|
+
config.applePayInstance.tokenize({
|
118
|
+
token: event.payment.token
|
119
|
+
}, function (tokenizeErr, payload) {
|
120
|
+
if (tokenizeErr) {
|
121
|
+
console.error('Error tokenizing Apple Pay:', tokenizeErr);
|
122
|
+
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
123
|
+
}
|
124
|
+
|
125
|
+
var contact = event.payment.shippingContact;
|
126
|
+
|
127
|
+
Spree.ajax({
|
128
|
+
data: SolidusPaypalBraintree.buildTransaction(payload, config, contact),
|
129
|
+
dataType: 'json',
|
130
|
+
type: 'POST',
|
131
|
+
url: Spree.pathFor('solidus_paypal_braintree/transactions'),
|
132
|
+
success: function(response) {
|
133
|
+
session.completePayment(ApplePaySession.STATUS_SUCCESS);
|
134
|
+
window.location.replace(response.redirectUrl);
|
135
|
+
},
|
136
|
+
error: function(xhr) {
|
137
|
+
if (xhr.status === 422) {
|
138
|
+
var errors = xhr.responseJSON.errors
|
139
|
+
|
140
|
+
if (errors && errors["Address"]) {
|
141
|
+
session.completePayment(ApplePaySession.STATUS_INVALID_SHIPPING_POSTAL_ADDRESS);
|
142
|
+
} else {
|
143
|
+
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
}
|
147
|
+
});
|
148
|
+
|
149
|
+
});
|
150
|
+
};
|
151
|
+
|
152
|
+
sessionCallback(session);
|
153
|
+
|
154
|
+
session.begin();
|
155
|
+
},
|
156
|
+
|
157
|
+
buildTransaction: function(payload, config, shippingContact) {
|
158
|
+
return {
|
159
|
+
transaction: {
|
160
|
+
nonce: payload.nonce,
|
161
|
+
phone: shippingContact.phoneNumber,
|
162
|
+
email: config.currentUserEmail || shippingContact.emailAddress,
|
163
|
+
payment_type: payload.type,
|
164
|
+
address_attributes: SolidusPaypalBraintree.buildAddress(shippingContact)
|
165
|
+
},
|
166
|
+
payment_method_id: config.paymentMethodId
|
167
|
+
};
|
168
|
+
},
|
169
|
+
|
170
|
+
buildAddress: function(shippingContact) {
|
171
|
+
var addressHash = {
|
172
|
+
country_name: shippingContact.country,
|
173
|
+
country_code: shippingContact.countryCode,
|
174
|
+
first_name: shippingContact.givenName,
|
175
|
+
last_name: shippingContact.familyName,
|
176
|
+
state_code: shippingContact.administrativeArea,
|
177
|
+
city: shippingContact.locality,
|
178
|
+
zip: shippingContact.postalCode,
|
179
|
+
address_line_1: shippingContact.addressLines[0]
|
180
|
+
};
|
181
|
+
|
182
|
+
if(shippingContact.addressLines.length > 1) {
|
183
|
+
addressHash['address_line_2'] = shippingContact.addressLines[1];
|
184
|
+
}
|
185
|
+
|
186
|
+
return addressHash;
|
187
|
+
}
|
188
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/*
|
2
|
+
Placeholder manifest file.
|
3
|
+
the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/backend/all.css'
|
4
|
+
*/
|
5
|
+
|
6
|
+
// Set Bootstrap variables if they're not already defined
|
7
|
+
// e.g if we're on Solidus < v1.4
|
8
|
+
$input-border-color: #cee1f4 !default;
|
9
|
+
$border-radius: 3px !default;
|
10
|
+
$input-color: #5498DA !default;
|
11
|
+
$brand-danger: #C60F13 !default;
|
12
|
+
$brand-success: #9FC820 !default;
|
13
|
+
|
14
|
+
.braintree-hosted-fields .input {
|
15
|
+
border: 1px solid $input-border-color;
|
16
|
+
border-radius: $border-radius;
|
17
|
+
color: $input-color;
|
18
|
+
height: 30px;
|
19
|
+
padding: 7px 10px;
|
20
|
+
|
21
|
+
&.braintree-hosted-fields-invalid {
|
22
|
+
border-color: $brand-danger;
|
23
|
+
}
|
24
|
+
|
25
|
+
&.braintree-hosted-fields-valid {
|
26
|
+
border-color: $brand-success;
|
27
|
+
}
|
28
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
/*
|
2
|
+
Placeholder manifest file.
|
3
|
+
the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/frontend/all.css'
|
4
|
+
*/
|
5
|
+
|
6
|
+
.braintree-hosted-fields .input {
|
7
|
+
border: 1px solid #d9d9db;
|
8
|
+
border-radius: 3px;
|
9
|
+
color: #5498DA;
|
10
|
+
height: 30px;
|
11
|
+
padding: 5px 10px;
|
12
|
+
}
|
13
|
+
|
14
|
+
.paypal-button-widget .paypal-button:hover {
|
15
|
+
background: transparent;
|
16
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SolidusPaypalBraintree
|
2
|
+
class ClientTokensController < Spree::Api::BaseController
|
3
|
+
skip_before_action :authenticate_user
|
4
|
+
|
5
|
+
before_action :load_gateway
|
6
|
+
|
7
|
+
def create
|
8
|
+
render json: { client_token: @gateway.generate_token, payment_method_id: @gateway.id }
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def load_gateway
|
14
|
+
if params[:payment_method_id]
|
15
|
+
@gateway = ::SolidusPaypalBraintree::Gateway.find_by!(id: params[:payment_method_id])
|
16
|
+
else
|
17
|
+
@gateway = ::SolidusPaypalBraintree::Gateway.find_by!(active: true)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module BraintreeAdminHelper
|
2
|
+
# Returns a link to the Braintree web UI for the given Braintree payment
|
3
|
+
def braintree_transaction_link(payment)
|
4
|
+
environment = payment.payment_method.preferred_environment == 'sandbox' ? 'sandbox' : 'www'
|
5
|
+
merchant_id = payment.payment_method.preferred_merchant_id
|
6
|
+
response_code = payment.response_code
|
7
|
+
|
8
|
+
return unless response_code.present?
|
9
|
+
return response_code unless merchant_id.present?
|
10
|
+
|
11
|
+
link_to(
|
12
|
+
response_code,
|
13
|
+
"https://#{environment}.braintreegateway.com/merchants/#{merchant_id}/transactions/#{response_code}",
|
14
|
+
title: 'Show payment on Braintree',
|
15
|
+
target: '_blank'
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|