1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 20:52:56 +01:00

Support payments and storing cards via WePay.

This commit is contained in:
Joshua Dwire 2016-05-13 09:30:22 -04:00
parent ba000546c4
commit ce04c994dd
13 changed files with 480 additions and 328 deletions

View File

@ -449,7 +449,7 @@ class AccountGatewayController extends BaseController
'tokenType' => $wepayUser->token_type,
'tokenExpires' => $accessTokenExpires,
'accountId' => $wepayAccount->account_id,
'testMode' => WEPAY_ENVIRONMENT == WEPAY_STAGING,
'testMode' => WEPAY_ENVIRONMENT == WEPAY_STAGE,
));
$account->account_gateways()->save($accountGateway);

View File

@ -152,6 +152,8 @@ class PaymentController extends BaseController
$data = array();
Session::put($invitation->id.'payment_ref', $invoice->id.'_'.uniqid());
if ($paymentType != PAYMENT_TYPE_BRAINTREE_PAYPAL) {
if ($paymentType == PAYMENT_TYPE_TOKEN) {
$useToken = true;
@ -198,6 +200,10 @@ class PaymentController extends BaseController
$data['braintreeClientToken'] = $this->paymentService->getBraintreeClientToken($account);
}
if(!empty($data['braintreeClientToken']) || $accountGateway->getPublishableStripeKey()|| $accountGateway->gateway_id == GATEWAY_WEPAY) {
$data['tokenize'] = true;
}
} else {
if ($deviceData = Input::get('details')) {
Session::put($invitation->id . 'device_data', $deviceData);
@ -405,7 +411,7 @@ class PaymentController extends BaseController
'last_name' => 'required',
];
if ( ! Input::get('stripeToken') && ! Input::get('payment_method_nonce') && !(Input::get('plaidPublicToken') && Input::get('plaidAccountId'))) {
if ( ! Input::get('sourceToken') && !(Input::get('plaidPublicToken') && Input::get('plaidAccountId'))) {
$rules = array_merge(
$rules,
[
@ -459,8 +465,6 @@ class PaymentController extends BaseController
$paymentType = Session::get($invitation->id . 'payment_type');
$accountGateway = $account->getGatewayByType($paymentType);
$paymentMethod = null;
if ($useToken) {
if(!$sourceId) {
@ -492,21 +496,46 @@ class PaymentController extends BaseController
$details = $this->paymentService->getPaymentDetails($invitation, $accountGateway, $data);
// check if we're creating/using a billing token
$tokenBillingSupported = false;
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$tokenBillingSupported = true;
$customerReferenceParam = 'cardReference';
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH && !Input::get('authorize_ach')) {
Session::flash('error', trans('texts.ach_authorization_required'));
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
}
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
$tokenBillingSupported = true;
$customerReferenceParam = 'paymentMethodToken';
$deviceData = Input::get('device_data');
if (!$deviceData) {
$deviceData = Session::get($invitation->id . 'device_data');
}
if($deviceData) {
$details['device_data'] = $deviceData;
}
} elseif ($accountGateway->gateway_id == GATEWAY_WEPAY) {
$tokenBillingSupported = true;
$customerReferenceParam = false;
}
if ($tokenBillingSupported) {
if ($useToken) {
$details['customerReference'] = $customerReference;
unset($details['token']);
$details['cardReference'] = $sourceReference;
if ($customerReferenceParam) {
$details[$customerReferenceParam] = $customerReference;
}
$details['token'] = $sourceReference;
unset($details['card']);
} elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing') || $paymentType == PAYMENT_TYPE_STRIPE_ACH) {
$token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id, $customerReference/* return parameter */, $paymentMethod/* return parameter */);
if ($token) {
$details['token'] = $token;
$details['customerReference'] = $customerReference;
if ($customerReferenceParam) {
$details[$customerReferenceParam] = $customerReference;
}
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH && empty(Input::get('plaidPublicToken')) ) {
// The user needs to complete verification
@ -518,36 +547,6 @@ class PaymentController extends BaseController
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
}
}
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
$deviceData = Input::get('device_data');
if (!$deviceData) {
$deviceData = Session::get($invitation->id . 'device_data');
}
if ($token = Input::get('payment_method_nonce')) {
$details['token'] = $token;
unset($details['card']);
}
if ($useToken) {
$details['customerId'] = $customerReference;
$details['paymentMethodToken'] = $sourceReference;
unset($details['token']);
} elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing')) {
$token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id, $customerReference/* return parameter */, $paymentMethod/* return parameter */);
if ($token) {
$details['paymentMethodToken'] = $token;
$details['customerId'] = $customerReference;
unset($details['token']);
} else {
$this->error('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
}
}
if($deviceData) {
$details['deviceData'] = $deviceData;
}
}
$response = $gateway->purchase($details)->send();

View File

@ -859,7 +859,6 @@ class PublicClientController extends BaseController
];
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH) {
$data['currencies'] = Cache::get('currencies');
}
@ -867,6 +866,10 @@ class PublicClientController extends BaseController
$data['braintreeClientToken'] = $this->paymentService->getBraintreeClientToken($account);
}
if(!empty($data['braintreeClientToken']) || $accountGateway->getPublishableStripeKey()|| $accountGateway->gateway_id == GATEWAY_WEPAY) {
$data['tokenize'] = true;
}
return View::make('payments.add_paymentmethod', $data);
}
@ -882,7 +885,7 @@ class PublicClientController extends BaseController
$account = $client->account;
$accountGateway = $account->getGatewayByType($paymentType);
$sourceToken = $accountGateway->gateway_id == GATEWAY_STRIPE ? Input::get('stripeToken'):Input::get('payment_method_nonce');
$sourceToken = Input::get('sourceToken');
if (!PaymentController::processPaymentClientDetails($client, $accountGateway, $paymentType)) {
return Redirect::to('client/paymentmethods/add/' . $typeLink)->withInput(Request::except('cvv'));

View File

@ -562,6 +562,10 @@ if (!defined('CONTACT_EMAIL')) {
define('GATEWAY_WEPAY', 60);
define('GATEWAY_BRAINTREE', 61);
// The customer exists, but only as a local concept
// The remote gateway doesn't understand the concept of customers
define('CUSTOMER_REFERENCE_LOCAL', 'local');
define('EVENT_CREATE_CLIENT', 1);
define('EVENT_CREATE_INVOICE', 2);
define('EVENT_CREATE_QUOTE', 3);
@ -749,7 +753,7 @@ if (!defined('CONTACT_EMAIL')) {
// WePay
define('WEPAY_PRODUCTION', 'production');
define('WEPAY_STAGING', 'staging');
define('WEPAY_STAGE', 'stage');
define('WEPAY_CLIENT_ID', env('WEPAY_CLIENT_ID'));
define('WEPAY_CLIENT_SECRET', env('WEPAY_CLIENT_SECRET'));
define('WEPAY_ENVIRONMENT', env('WEPAY_ENVIRONMENT', WEPAY_PRODUCTION));

View File

@ -995,7 +995,7 @@ class Utils
public static function setupWePay($accountGateway = null)
{
if (WePay::getEnvironment() == 'none') {
if (WEPAY_ENVIRONMENT == WEPAY_STAGING) {
if (WEPAY_ENVIRONMENT == WEPAY_STAGE) {
WePay::useStaging(WEPAY_CLIENT_ID, WEPAY_CLIENT_SECRET);
} else {
WePay::useProduction(WEPAY_CLIENT_ID, WEPAY_CLIENT_SECRET);

View File

@ -1245,6 +1245,8 @@ class Account extends Eloquent
return GATEWAY_STRIPE;
} elseif ($this->isGatewayConfigured(GATEWAY_BRAINTREE)) {
return GATEWAY_BRAINTREE;
} elseif ($this->isGatewayConfigured(GATEWAY_WEPAY)) {
return GATEWAY_WEPAY;
} else {
return false;
}

View File

@ -46,7 +46,7 @@ class AccountGatewayService extends BaseService
return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml();
} else {
$accountGateway = AccountGateway::find($model->id);
$endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGING ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
$endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
$wepayAccountId = $accountGateway->getConfig()->accountId;
$linkText = $model->name;
$url = $endpoint.'account/'.$wepayAccountId;
@ -116,7 +116,7 @@ class AccountGatewayService extends BaseService
uctrans('texts.manage_wepay_account'),
function ($model) {
$accountGateway = AccountGateway::find($model->id);
$endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGING ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
$endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
return array(
'url' => $endpoint.'account/'.$accountGateway->getConfig()->accountId,
'attributes' => 'target="_blank"'

View File

@ -9,6 +9,7 @@ use Cache;
use Omnipay;
use Session;
use CreditCard;
use WePay;
use App\Models\Payment;
use App\Models\PaymentMethod;
use App\Models\Account;
@ -30,7 +31,8 @@ class PaymentService extends BaseService
protected static $refundableGateways = array(
GATEWAY_STRIPE,
GATEWAY_BRAINTREE
GATEWAY_BRAINTREE,
GATEWAY_WEPAY,
);
public function __construct(PaymentRepository $paymentRepo, AccountRepository $accountRepo, DatatableService $datatableService)
@ -95,9 +97,9 @@ class PaymentService extends BaseService
$data['ButtonSource'] = 'InvoiceNinja_SP';
};
if ($input && $accountGateway->isGateway(GATEWAY_STRIPE)) {
if (!empty($input['stripeToken'])) {
$data['token'] = $input['stripeToken'];
if ($input) {
if (!empty($input['sourceToken'])) {
$data['token'] = $input['sourceToken'];
unset($data['card']);
} elseif (!empty($input['plaidPublicToken'])) {
$data['plaidPublicToken'] = $input['plaidPublicToken'];
@ -106,6 +108,10 @@ class PaymentService extends BaseService
}
}
if ($accountGateway->isGateway(GATEWAY_WEPAY) && $transactionId = Session::get($invitation->id.'payment_ref')) {
$data['transaction_id'] = $transactionId;
}
return $data;
}
@ -266,6 +272,17 @@ class PaymentService extends BaseService
if (!$response->isSuccessful()) {
return $response->getMessage();
}
} elseif ($accountGateway->gateway_id == GATEWAY_WEPAY) {
try {
$wepay = Utils::setupWePay($accountGateway);
$wepay->request('/credit_card/delete', [
'client_id' => WEPAY_CLIENT_ID,
'client_secret' => WEPAY_CLIENT_SECRET,
'credit_card_id' => $paymentMethod->source_reference,
]);
} catch (\WePayException $ex){
return $ex->getMessage();
}
}
$paymentMethod->delete();
@ -291,16 +308,16 @@ class PaymentService extends BaseService
{
$customerReference = $client->getGatewayToken($accountGateway, $accountGatewayToken/* return paramenter */);
if ($customerReference) {
if ($customerReference && $customerReference != CUSTOMER_REFERENCE_LOCAL) {
$details['customerReference'] = $customerReference;
if ($accountGateway->gateway->id == GATEWAY_STRIPE) {
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$customerResponse = $gateway->fetchCustomer(array('customerReference' => $customerReference))->send();
if (!$customerResponse->isSuccessful()) {
$customerReference = null; // The customer might not exist anymore
}
} elseif ($accountGateway->gateway->id == GATEWAY_BRAINTREE) {
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
$customer = $gateway->findCustomer($customerReference)->send()->getData();
if (!($customer instanceof \Braintree\Customer)) {
@ -309,7 +326,7 @@ class PaymentService extends BaseService
}
}
if ($accountGateway->gateway->id == GATEWAY_STRIPE) {
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
if (!empty($details['plaidPublicToken'])) {
$plaidResult = $this->getPlaidToken($accountGateway, $details['plaidPublicToken'], $details['plaidAccountId']);
@ -355,7 +372,7 @@ class PaymentService extends BaseService
return;
}
}
} elseif ($accountGateway->gateway->id == GATEWAY_BRAINTREE) {
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
if (!$customerReference) {
$tokenResponse = $gateway->createCustomer(array('customerData' => array()))->send();
if ($tokenResponse->isSuccessful()) {
@ -377,6 +394,31 @@ class PaymentService extends BaseService
return;
}
}
} elseif ($accountGateway->gateway_id == GATEWAY_WEPAY) {
$wepay = Utils::setupWePay($accountGateway);
try {
$wepay->request('credit_card/authorize', array(
'client_id' => WEPAY_CLIENT_ID,
'client_secret' => WEPAY_CLIENT_SECRET,
'credit_card_id' => $details['token'],
));
// Get the card details
$tokenResponse = $wepay->request('credit_card', array(
'client_id' => WEPAY_CLIENT_ID,
'client_secret' => WEPAY_CLIENT_SECRET,
'credit_card_id' => $details['token'],
));
$customerReference = CUSTOMER_REFERENCE_LOCAL;
$sourceReference = $details['token'];
} catch (\WePayException $ex) {
$this->lastError = $ex->getMessage();
return;
}
} else {
return null;
}
if ($customerReference) {
@ -394,7 +436,7 @@ class PaymentService extends BaseService
$accountGatewayToken->token = $customerReference;
$accountGatewayToken->save();
$paymentMethod = $this->createPaymentMethodFromGatewayResponse($tokenResponse, $accountGateway, $accountGatewayToken, $contactId);
$paymentMethod = $this->convertPaymentMethodFromGatewayResponse($tokenResponse, $accountGateway, $accountGatewayToken, $contactId);
} else {
$this->lastError = $tokenResponse->getMessage();
@ -456,8 +498,24 @@ class PaymentService extends BaseService
return $paymentMethod;
}
public function convertPaymentMethodFromWePay($source, $accountGatewayToken = null, $paymentMethod = null) {
// Creating a new one or updating an existing one
if (!$paymentMethod) {
$paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
}
$paymentMethod->payment_type_id = $this->parseCardType($source->credit_card_name);
$paymentMethod->last4 = $source->last_four;
$paymentMethod->expiration = $source->expiration_year . '-' . $source->expiration_month . '-00';
$paymentMethod->setRelation('payment_type', Cache::get('paymentTypes')->find($paymentMethod->payment_type_id));
$paymentMethod->source_reference = $source->credit_card_id;
return $paymentMethod;
}
public function createPaymentMethodFromGatewayResponse($gatewayResponse, $accountGateway, $accountGatewayToken = null, $contactId = null) {
public function convertPaymentMethodFromGatewayResponse($gatewayResponse, $accountGateway, $accountGatewayToken = null, $contactId = null, $existingPaymentMethod = null) {
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$data = $gatewayResponse->getData();
if (!empty($data['object']) && ($data['object'] == 'card' || $data['object'] == 'bank_account')) {
@ -470,7 +528,7 @@ class PaymentService extends BaseService
}
if ($source) {
$paymentMethod = $this->convertPaymentMethodFromStripe($source, $accountGatewayToken);
$paymentMethod = $this->convertPaymentMethodFromStripe($source, $accountGatewayToken, $existingPaymentMethod);
}
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
$data = $gatewayResponse->getData();
@ -478,7 +536,12 @@ class PaymentService extends BaseService
if (!empty($data->transaction)) {
$transaction = $data->transaction;
$paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
if ($existingPaymentMethod) {
$paymentMethod = $existingPaymentMethod;
} else {
$paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
}
if ($transaction->paymentInstrumentType == 'credit_card') {
$card = $transaction->creditCardDetails;
$paymentMethod->last4 = $card->last4;
@ -490,9 +553,20 @@ class PaymentService extends BaseService
}
$paymentMethod->setRelation('payment_type', Cache::get('paymentTypes')->find($paymentMethod->payment_type_id));
} elseif (!empty($data->paymentMethod)) {
$paymentMethod = $this->convertPaymentMethodFromBraintree($data->paymentMethod, $accountGatewayToken);
$paymentMethod = $this->convertPaymentMethodFromBraintree($data->paymentMethod, $accountGatewayToken, $existingPaymentMethod);
}
} elseif ($accountGateway->gateway_id == GATEWAY_WEPAY) {
if ($gatewayResponse instanceof \Omnipay\WePay\Message\CustomCheckoutResponse) {
$wepay = \Utils::setupWePay($accountGateway);
$gatewayResponse = $wepay->request('credit_card', array(
'client_id' => WEPAY_CLIENT_ID,
'client_secret' => WEPAY_CLIENT_SECRET,
'credit_card_id' => $gatewayResponse->getData()['payment_method']['credit_card']['id'],
));
}
$paymentMethod = $this->convertPaymentMethodFromWePay($gatewayResponse, $accountGatewayToken, $existingPaymentMethod);
}
if (!empty($paymentMethod) && $accountGatewayToken && $contactId) {
@ -566,43 +640,49 @@ class PaymentService extends BaseService
$payment->payment_type_id = $this->detectCardType($card->getNumber());
}
$savePaymentMethod = !empty($paymentMethod);
// This will convert various gateway's formats to a known format
$paymentMethod = $this->convertPaymentMethodFromGatewayResponse($purchaseResponse, $accountGateway, null, null, $paymentMethod);
// If this is a stored payment method, we'll update it with the latest info
if ($savePaymentMethod) {
$paymentMethod->save();
}
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$data = $purchaseResponse->getData();
$source = !empty($data['source'])?$data['source']:$data['card'];
$payment->payment_status_id = $data['status'] == 'succeeded' ? PAYMENT_STATUS_COMPLETED : PAYMENT_STATUS_PENDING;
if ($source) {
$payment->last4 = $source['last4'];
if ($source['object'] == 'bank_account') {
$payment->routing_number = $source['routing_number'];
$payment->payment_type_id = PAYMENT_TYPE_ACH;
}
else{
$payment->expiration = $source['exp_year'] . '-' . $source['exp_month'] . '-00';
$payment->payment_type_id = $this->parseCardType($source['brand']);
}
}
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
$transaction = $purchaseResponse->getData()->transaction;
if ($transaction->paymentInstrumentType == 'credit_card') {
$card = $transaction->creditCardDetails;
$payment->last4 = $card->last4;
$payment->expiration = $card->expirationYear . '-' . $card->expirationMonth . '-00';
$payment->payment_type_id = $this->parseCardType($card->cardType);
} elseif ($transaction->paymentInstrumentType == 'paypal_account') {
$payment->payment_type_id = PAYMENT_TYPE_ID_PAYPAL;
$payment->email = $transaction->paypalDetails->payerEmail;
}
}
if ($payerId) {
$payment->payer_id = $payerId;
}
if ($paymentMethod) {
$payment->payment_method_id = $paymentMethod->id;
if ($paymentMethod->last4) {
$payment->last4 = $paymentMethod->last4;
}
if ($paymentMethod->expiration) {
$payment->expiration = $paymentMethod->expiration;
}
if ($paymentMethod->routing_number) {
$payment->routing_number = $paymentMethod->routing_number;
}
if ($paymentMethod->payment_type_id) {
$payment->payment_type_id = $paymentMethod->payment_type_id;
}
if ($paymentMethod->email) {
$payment->email = $paymentMethod->email;
}
if ($payerId) {
$payment->payer_id = $payerId;
}
if ($savePaymentMethod) {
$payment->payment_method_id = $paymentMethod->id;
}
}
$payment->save();
@ -665,20 +745,29 @@ class PaymentService extends BaseService
private function parseCardType($cardName) {
$cardTypes = array(
'Visa' => PAYMENT_TYPE_VISA,
'American Express' => PAYMENT_TYPE_AMERICAN_EXPRESS,
'MasterCard' => PAYMENT_TYPE_MASTERCARD,
'Discover' => PAYMENT_TYPE_DISCOVER,
'JCB' => PAYMENT_TYPE_JCB,
'Diners Club' => PAYMENT_TYPE_DINERS,
'Carte Blanche' => PAYMENT_TYPE_CARTE_BLANCHE,
'China UnionPay' => PAYMENT_TYPE_UNIONPAY,
'Laser' => PAYMENT_TYPE_LASER,
'Maestro' => PAYMENT_TYPE_MAESTRO,
'Solo' => PAYMENT_TYPE_SOLO,
'Switch' => PAYMENT_TYPE_SWITCH
'visa' => PAYMENT_TYPE_VISA,
'americanexpress' => PAYMENT_TYPE_AMERICAN_EXPRESS,
'amex' => PAYMENT_TYPE_AMERICAN_EXPRESS,
'mastercard' => PAYMENT_TYPE_MASTERCARD,
'discover' => PAYMENT_TYPE_DISCOVER,
'jcb' => PAYMENT_TYPE_JCB,
'dinersclub' => PAYMENT_TYPE_DINERS,
'carteblanche' => PAYMENT_TYPE_CARTE_BLANCHE,
'chinaunionpay' => PAYMENT_TYPE_UNIONPAY,
'unionpay' => PAYMENT_TYPE_UNIONPAY,
'laser' => PAYMENT_TYPE_LASER,
'maestro' => PAYMENT_TYPE_MAESTRO,
'solo' => PAYMENT_TYPE_SOLO,
'switch' => PAYMENT_TYPE_SWITCH
);
$cardName = strtolower(str_replace(array(' ', '-', '_'), '', $cardName));
if (empty($cardTypes[$cardName]) && 1 == preg_match('/^('.implode('|', array_keys($cardTypes)).')/', $cardName, $matches)) {
// Some gateways return extra stuff after the card name
$cardName = $matches[1];
}
if (!empty($cardTypes[$cardName])) {
return $cardTypes[$cardName];
} else {
@ -736,10 +825,9 @@ class PaymentService extends BaseService
$details = $this->getPaymentDetails($invitation, $accountGateway);
$details['customerReference'] = $token;
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$details['cardReference'] = $defaultPaymentMethod->source_reference;
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
$details['paymentMethodToken'] = $defaultPaymentMethod->source_reference;
$details['token'] = $defaultPaymentMethod->source_reference;
if ($accountGateway->gateway_id == GATEWAY_WEPAY) {
$details['transaction_id'] = 'autobill_'.$invoice->id;
}
// submit purchase/get response

View File

@ -3,221 +3,11 @@
@section('head')
@parent
@if (!empty($braintreeClientToken))
<script type="text/javascript" src="https://js.braintreegateway.com/js/braintree-2.23.0.min.js"></script>
<script type="text/javascript" >
$(function() {
braintree.setup("{{ $braintreeClientToken }}", "custom", {
id: "payment-form",
hostedFields: {
number: {
selector: "#card_number",
placeholder: "{{ trans('texts.card_number') }}"
},
cvv: {
selector: "#cvv",
placeholder: "{{ trans('texts.cvv') }}"
},
expirationMonth: {
selector: "#expiration_month",
placeholder: "{{ trans('texts.expiration_month') }}"
},
expirationYear: {
selector: "#expiration_year",
placeholder: "{{ trans('texts.expiration_year') }}"
},
styles: {
'input': {
'font-family': {!! json_encode(Utils::getFromCache($account->getBodyFontId(), 'fonts')['css_stack']) !!},
'font-weight': "{{ Utils::getFromCache($account->getBodyFontId(), 'fonts')['css_weight'] }}",
'font-size': '16px'
}
}
},
onError: function(e) {
var $form = $('.payment-form');
$form.find('button').prop('disabled', false);
// Show the errors on the form
if (e.details && e.details.invalidFieldKeys.length) {
var invalidField = e.details.invalidFieldKeys[0];
if (invalidField == 'number') {
$('#js-error-message').html('{{ trans('texts.invalid_card_number') }}').fadeIn();
}
else if (invalidField == 'expirationDate' || invalidField == 'expirationYear' || invalidField == 'expirationMonth') {
$('#js-error-message').html('{{ trans('texts.invalid_expiry') }}').fadeIn();
}
else if (invalidField == 'cvv') {
$('#js-error-message').html('{{ trans('texts.invalid_cvv') }}').fadeIn();
}
}
else {
$('#js-error-message').html(e.message).fadeIn();
}
}
});
$('.payment-form').submit(function(event) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
$('#js-error-message').hide();
});
});
</script>
@include('payments.tokenization_braintree')
@elseif (isset($accountGateway) && $accountGateway->getPublishableStripeKey())
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
Stripe.setPublishableKey('{{ $accountGateway->getPublishableStripeKey() }}');
$(function() {
$('.payment-form').submit(function(event) {
if($('[name=plaidAccountId]').length)return;
var $form = $(this);
var data = {
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
account_holder_name: $('#account_holder_name').val(),
account_holder_type: $('[name=account_holder_type]:checked').val(),
currency: $("#currency").val(),
country: $("#country").val(),
routing_number: $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''),
account_number: $('#account_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
@else
name: $('#first_name').val() + ' ' + $('#last_name').val(),
address_line1: $('#address1').val(),
address_line2: $('#address2').val(),
address_city: $('#city').val(),
address_state: $('#state').val(),
address_zip: $('#postal_code').val(),
address_country: $("#country_id option:selected").text(),
number: $('#card_number').val(),
cvc: $('#cvv').val(),
exp_month: $('#expiration_month').val(),
exp_year: $('#expiration_year').val()
@endif
};
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
// Validate the account details
if (!data.account_holder_type) {
$('#js-error-message').html('{{ trans('texts.missing_account_holder_type') }}').fadeIn();
return false;
}
if (!data.account_holder_name) {
$('#js-error-message').html('{{ trans('texts.missing_account_holder_name') }}').fadeIn();
return false;
}
if (!data.routing_number || !Stripe.bankAccount.validateRoutingNumber(data.routing_number, data.country)) {
$('#js-error-message').html('{{ trans('texts.invalid_routing_number') }}').fadeIn();
return false;
}
if (data.account_number != $('#confirm_account_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')) {
$('#js-error-message').html('{{ trans('texts.account_number_mismatch') }}').fadeIn();
return false;
}
if (!data.account_number || !Stripe.bankAccount.validateAccountNumber(data.account_number, data.country)) {
$('#js-error-message').html('{{ trans('texts.invalid_account_number') }}').fadeIn();
return false;
}
@else
// Validate the card details
if (!Stripe.card.validateCardNumber(data.number)) {
$('#js-error-message').html('{{ trans('texts.invalid_card_number') }}').fadeIn();
return false;
}
if (!Stripe.card.validateExpiry(data.exp_month, data.exp_year)) {
$('#js-error-message').html('{{ trans('texts.invalid_expiry') }}').fadeIn();
return false;
}
if (!Stripe.card.validateCVC(data.cvc)) {
$('#js-error-message').html('{{ trans('texts.invalid_cvv') }}').fadeIn();
return false;
}
@endif
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
$('#js-error-message').hide();
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
Stripe.bankAccount.createToken(data, stripeResponseHandler);
@else
Stripe.card.createToken(data, stripeResponseHandler);
@endif
// Prevent the form from submitting with the default action
return false;
});
@if($accountGateway->getPlaidEnabled())
var plaidHandler = Plaid.create({
selectAccount: true,
env: '{{ $accountGateway->getPlaidEnvironment() }}',
clientName: {!! json_encode($account->getDisplayName()) !!},
key: '{{ $accountGateway->getPlaidPublicKey() }}',
product: 'auth',
onSuccess: plaidSuccessHandler,
onExit : function(){$('#secured_by_plaid').hide()}
});
$('#plaid_link_button').click(function(){plaidHandler.open();$('#secured_by_plaid').fadeIn()});
$('#plaid_unlink').click(function(e){
e.preventDefault();
$('#manual_container').fadeIn();
$('#plaid_linked').hide();
$('#plaid_link_button').show();
$('#pay_now_button').hide();
$('#add_account_button').show();
$('[name=plaidPublicToken]').remove();
$('[name=plaidAccountId]').remove();
$('[name=account_holder_type],#account_holder_name').attr('required','required');
})
@endif
});
function stripeResponseHandler(status, response) {
var $form = $('.payment-form');
if (response.error) {
// Show the errors on the form
var error = response.error.message;
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
if(response.error.param == 'bank_account[country]') {
error = "{{trans('texts.country_not_supported')}}";
}
@endif
$form.find('button').prop('disabled', false);
$('#js-error-message').html(error).fadeIn();
} else {
// response contains id and card, which contains additional card details
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="stripeToken"/>').val(token));
// and submit
$form.get(0).submit();
}
};
function plaidSuccessHandler(public_token, metadata) {
$('#secured_by_plaid').hide()
var $form = $('.payment-form');
$form.append($('<input type="hidden" name="plaidPublicToken"/>').val(public_token));
$form.append($('<input type="hidden" name="plaidAccountId"/>').val(metadata.account_id));
$('#plaid_linked_status').text('{{ trans('texts.plaid_linked_status') }}'.replace(':bank', metadata.institution.name));
$('#manual_container').fadeOut();
$('#plaid_linked').show();
$('#plaid_link_button').hide();
$('[name=account_holder_type],#account_holder_name').removeAttr('required');
var payNowBtn = $('#pay_now_button');
if(payNowBtn.length) {
payNowBtn.show();
$('#add_account_button').hide();
}
};
</script>
@include('payments.tokenization_stripe')
@elseif (isset($accountGateway) && $accountGateway->gateway_id == GATEWAY_WEPAY)
@include('payments.tokenization_wepay')
@else
<script type="text/javascript">
$(function() {
@ -232,7 +22,6 @@
});
</script>
@endif
@stop
@section('content')
@ -283,7 +72,6 @@
{{ Former::populateField('email', $contact->email) }}
@if (!$client->country_id && $client->account->country_id)
{{ Former::populateField('country_id', $client->account->country_id) }}
{{ Former::populateField('country', $client->account->country->iso_3166_2) }}
@endif
@if (!$client->currency_id && $client->account->currency_id)
{{ Former::populateField('currency_id', $client->account->currency_id) }}
@ -442,9 +230,9 @@
))->inline()->label(trans('texts.account_holder_type')); !!}
{!! Former::text('account_holder_name')
->label(trans('texts.account_holder_name')) !!}
{!! Former::select('country')
{!! Former::select('country_id')
->label(trans('texts.country_id'))
->fromQuery($countries, 'name', 'iso_3166_2')
->fromQuery($countries, 'name', 'id')
->addGroupClass('country-select') !!}
{!! Former::select('currency')
->label(trans('texts.currency_id'))
@ -485,7 +273,7 @@
<h3>{{ trans('texts.paypal') }}</h3>
<div>{{$paypalDetails->firstName}} {{$paypalDetails->lastName}}</div>
<div>{{$paypalDetails->email}}</div>
<input type="hidden" name="payment_method_nonce" value="{{$sourceId}}">
<input type="hidden" name="sourceToken" value="{{$sourceId}}">
<input type="hidden" name="first_name" value="{{$paypalDetails->firstName}}">
<input type="hidden" name="last_name" value="{{$paypalDetails->lastName}}">
<input type="hidden" name="email" value="{{$paypalDetails->email}}">
@ -515,7 +303,7 @@
@if (!empty($braintreeClientToken))
<div id="card_number" class="braintree-hosted form-control"></div>
@else
{!! Former::text($accountGateway->getPublishableStripeKey() ? '' : 'card_number')
{!! Former::text(!empty($tokenize) ? '' : 'card_number')
->id('card_number')
->placeholder(trans('texts.card_number'))
->autocomplete('cc-number')
@ -526,7 +314,7 @@
@if (!empty($braintreeClientToken))
<div id="cvv" class="braintree-hosted form-control"></div>
@else
{!! Former::text($accountGateway->getPublishableStripeKey() ? '' : 'cvv')
{!! Former::text(!empty($tokenize) ? '' : 'cvv')
->id('cvv')
->placeholder(trans('texts.cvv'))
->autocomplete('off')
@ -539,7 +327,7 @@
@if (!empty($braintreeClientToken))
<div id="expiration_month" class="braintree-hosted form-control"></div>
@else
{!! Former::select($accountGateway->getPublishableStripeKey() ? '' : 'expiration_month')
{!! Former::select(!empty($tokenize) ? '' : 'expiration_month')
->id('expiration_month')
->autocomplete('cc-exp-month')
->placeholder(trans('texts.expiration_month'))
@ -562,7 +350,7 @@
@if (!empty($braintreeClientToken))
<div id="expiration_year" class="braintree-hosted form-control"></div>
@else
{!! Former::select($accountGateway->getPublishableStripeKey() ? '' : 'expiration_year')
{!! Former::select(!empty($tokenize) ? '' : 'expiration_year')
->id('expiration_year')
->autocomplete('cc-exp-year')
->placeholder(trans('texts.expiration_year'))

View File

@ -183,5 +183,6 @@
function setDefault(sourceId) {
$('#default_id').val(sourceId);
$('#defaultSourceForm').submit()
return false;
}
</script>

View File

@ -0,0 +1,61 @@
<script type="text/javascript" src="https://js.braintreegateway.com/js/braintree-2.23.0.min.js"></script>
<script type="text/javascript" >
$(function() {
braintree.setup("{{ $braintreeClientToken }}", "custom", {
id: "payment-form",
hostedFields: {
number: {
selector: "#card_number",
placeholder: "{{ trans('texts.card_number') }}"
},
cvv: {
selector: "#cvv",
placeholder: "{{ trans('texts.cvv') }}"
},
expirationMonth: {
selector: "#expiration_month",
placeholder: "{{ trans('texts.expiration_month') }}"
},
expirationYear: {
selector: "#expiration_year",
placeholder: "{{ trans('texts.expiration_year') }}"
},
styles: {
'input': {
'font-family': {!! json_encode(Utils::getFromCache($account->getBodyFontId(), 'fonts')['css_stack']) !!},
'font-weight': "{{ Utils::getFromCache($account->getBodyFontId(), 'fonts')['css_weight'] }}",
'font-size': '16px'
}
}
},
onError: function(e) {
var $form = $('.payment-form');
$form.find('button').prop('disabled', false);
// Show the errors on the form
if (e.details && e.details.invalidFieldKeys.length) {
var invalidField = e.details.invalidFieldKeys[0];
if (invalidField == 'number') {
$('#js-error-message').html('{{ trans('texts.invalid_card_number') }}').fadeIn();
}
else if (invalidField == 'expirationDate' || invalidField == 'expirationYear' || invalidField == 'expirationMonth') {
$('#js-error-message').html('{{ trans('texts.invalid_expiry') }}').fadeIn();
}
else if (invalidField == 'cvv') {
$('#js-error-message').html('{{ trans('texts.invalid_cvv') }}').fadeIn();
}
}
else {
$('#js-error-message').html(e.message).fadeIn();
}
}
});
$('.payment-form').submit(function(event) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
$('#js-error-message').hide();
});
});
</script>

View File

@ -0,0 +1,154 @@
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
Stripe.setPublishableKey('{{ $accountGateway->getPublishableStripeKey() }}');
$(function() {
var countries = {!! $countries->pluck('iso_3166_2','id') !!};
$('.payment-form').submit(function(event) {
if($('[name=plaidAccountId]').length)return;
var $form = $(this);
var data = {
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
account_holder_name: $('#account_holder_name').val(),
account_holder_type: $('[name=account_holder_type]:checked').val(),
currency: $("#currency").val(),
country: countries[$("#country_id").val()],
routing_number: $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''),
account_number: $('#account_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
@else
name: $('#first_name').val() + ' ' + $('#last_name').val(),
address_line1: $('#address1').val(),
address_line2: $('#address2').val(),
address_city: $('#city').val(),
address_state: $('#state').val(),
address_zip: $('#postal_code').val(),
address_country: $("#country_id option:selected").text(),
number: $('#card_number').val(),
cvc: $('#cvv').val(),
exp_month: $('#expiration_month').val(),
exp_year: $('#expiration_year').val()
@endif
};
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
// Validate the account details
if (!data.account_holder_type) {
$('#js-error-message').html('{{ trans('texts.missing_account_holder_type') }}').fadeIn();
return false;
}
if (!data.account_holder_name) {
$('#js-error-message').html('{{ trans('texts.missing_account_holder_name') }}').fadeIn();
return false;
}
if (!data.routing_number || !Stripe.bankAccount.validateRoutingNumber(data.routing_number, data.country)) {
$('#js-error-message').html('{{ trans('texts.invalid_routing_number') }}').fadeIn();
return false;
}
if (data.account_number != $('#confirm_account_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')) {
$('#js-error-message').html('{{ trans('texts.account_number_mismatch') }}').fadeIn();
return false;
}
if (!data.account_number || !Stripe.bankAccount.validateAccountNumber(data.account_number, data.country)) {
$('#js-error-message').html('{{ trans('texts.invalid_account_number') }}').fadeIn();
return false;
}
@else
// Validate the card details
if (!Stripe.card.validateCardNumber(data.number)) {
$('#js-error-message').html('{{ trans('texts.invalid_card_number') }}').fadeIn();
return false;
}
if (!Stripe.card.validateExpiry(data.exp_month, data.exp_year)) {
$('#js-error-message').html('{{ trans('texts.invalid_expiry') }}').fadeIn();
return false;
}
if (!Stripe.card.validateCVC(data.cvc)) {
$('#js-error-message').html('{{ trans('texts.invalid_cvv') }}').fadeIn();
return false;
}
@endif
// Disable the submit button to prevent repeated clicks
$form.find('button').prop('disabled', true);
$('#js-error-message').hide();
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
Stripe.bankAccount.createToken(data, stripeResponseHandler);
@else
Stripe.card.createToken(data, stripeResponseHandler);
@endif
// Prevent the form from submitting with the default action
return false;
});
@if($accountGateway->getPlaidEnabled())
var plaidHandler = Plaid.create({
selectAccount: true,
env: '{{ $accountGateway->getPlaidEnvironment() }}',
clientName: {!! json_encode($account->getDisplayName()) !!},
key: '{{ $accountGateway->getPlaidPublicKey() }}',
product: 'auth',
onSuccess: plaidSuccessHandler,
onExit : function(){$('#secured_by_plaid').hide()}
});
$('#plaid_link_button').click(function(){plaidHandler.open();$('#secured_by_plaid').fadeIn()});
$('#plaid_unlink').click(function(e){
e.preventDefault();
$('#manual_container').fadeIn();
$('#plaid_linked').hide();
$('#plaid_link_button').show();
$('#pay_now_button').hide();
$('#add_account_button').show();
$('[name=plaidPublicToken]').remove();
$('[name=plaidAccountId]').remove();
$('[name=account_holder_type],#account_holder_name').attr('required','required');
})
@endif
});
function stripeResponseHandler(status, response) {
var $form = $('.payment-form');
if (response.error) {
// Show the errors on the form
var error = response.error.message;
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
if(response.error.param == 'bank_account[country]') {
error = "{{trans('texts.country_not_supported')}}";
}
@endif
$form.find('button').prop('disabled', false);
$('#js-error-message').html(error).fadeIn();
} else {
// response contains id and card, which contains additional card details
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="sourceToken"/>').val(token));
// and submit
$form.get(0).submit();
}
};
function plaidSuccessHandler(public_token, metadata) {
$('#secured_by_plaid').hide()
var $form = $('.payment-form');
$form.append($('<input type="hidden" name="plaidPublicToken"/>').val(public_token));
$form.append($('<input type="hidden" name="plaidAccountId"/>').val(metadata.account_id));
$('#plaid_linked_status').text('{{ trans('texts.plaid_linked_status') }}'.replace(':bank', metadata.institution.name));
$('#manual_container').fadeOut();
$('#plaid_linked').show();
$('#plaid_link_button').hide();
$('[name=account_holder_type],#account_holder_name').removeAttr('required');
var payNowBtn = $('#pay_now_button');
if(payNowBtn.length) {
payNowBtn.show();
$('#add_account_button').hide();
}
};
</script>

View File

@ -0,0 +1,52 @@
<script type="text/javascript" src="https://static.wepay.com/min/js/tokenization.v2.js"></script>
<script type="text/javascript">
$(function() {
var countries = {!! $countries->pluck('iso_3166_2','id') !!};
WePay.set_endpoint('{{ WEPAY_ENVIRONMENT }}');
$('.payment-form').submit(function(event) {
var data = {
client_id: {{ WEPAY_CLIENT_ID }},
user_name: $('#first_name').val() + ' ' + $('#last_name').val(),
email: $('#email').val(),
cc_number: $('#card_number').val(),
cvv: $('#cvv').val(),
expiration_month: $('#expiration_month').val(),
expiration_year: $('#expiration_year').val(),
address: {
address1: $('#address1').val(),
address2: $('#address2').val(),
city: $('#city').val(),
country: countries[$("#country_id").val()]
}
};
if(data.address.country == 'US') {
data.address.zip = $('#postal_code').val();
} else {
data.address.postcode = $('#postal_code').val();
}
// Not including state/province, since WePay wants 2-letter codes and users enter the full name
var response = WePay.credit_card.create(data, function(response) {
var $form = $('.payment-form');
if (response.error) {
// Show the errors on the form
var error = response.error_description;
$form.find('button').prop('disabled', false);
$('#js-error-message').text(error).fadeIn();
} else {
// response contains id and card, which contains additional card details
var token = response.credit_card_id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="sourceToken"/>').val(token));
// and submit
$form.get(0).submit();
}
});
// Prevent the form from submitting with the default action
return false;
});
});
</script>