mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-09-20 08:21:34 +02:00
Payment responses and saving card details
This commit is contained in:
parent
89330e6e34
commit
5090c963d3
@ -124,13 +124,20 @@ class PaymentController extends Controller
|
||||
'amount_with_fee' => $amount + $gateway->calcGatewayFee($amount),
|
||||
'token' => auth()->user()->client->gateway_token($gateway->id, $payment_method_id),
|
||||
'payment_method_id' => $payment_method_id,
|
||||
'hashed_ids' => explode(",",request()->input('hashed_ids')),
|
||||
];
|
||||
|
||||
|
||||
return $gateway->driver(auth()->user()->client)->processPayment($data);
|
||||
return $gateway->driver(auth()->user()->client)->processPaymentView($data);
|
||||
|
||||
}
|
||||
|
||||
public function response(Request $request)
|
||||
{
|
||||
$gateway = CompanyGateway::find($request->input('company_gateway_id'));
|
||||
|
||||
return $gateway->driver(auth()->user()->client)->processPaymentResponse($request);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -82,6 +82,10 @@ class BasePaymentDriver
|
||||
];
|
||||
}
|
||||
|
||||
public function getCompanyGatewayId()
|
||||
{
|
||||
return $this->company_gateway->id;
|
||||
}
|
||||
/**
|
||||
* Returns whether refunds are possible with the gateway
|
||||
* @return boolean TRUE|FALSE
|
||||
@ -111,10 +115,14 @@ class BasePaymentDriver
|
||||
*/
|
||||
public function refundPayment() {}
|
||||
|
||||
public function authorizeCreditCardView($data) {}
|
||||
public function authorizeCreditCardView(array $data) {}
|
||||
|
||||
public function authorizeCreditCardResponse($request) {}
|
||||
|
||||
public function processPaymentView(array $data) {}
|
||||
|
||||
public function processPaymentResponse($request) {}
|
||||
|
||||
/************************************* Omnipay ******************************************
|
||||
authorize($options) - authorize an amount on the customer's card
|
||||
completeAuthorize($options) - handle return from off-site gateways after authorization
|
||||
|
@ -128,7 +128,7 @@ class StripePaymentDriver extends BasePaymentDriver
|
||||
}
|
||||
}
|
||||
|
||||
public function authorizeCreditCardView($data)
|
||||
public function authorizeCreditCardView(array $data)
|
||||
{
|
||||
|
||||
$intent['intent'] = $this->getSetupIntent();
|
||||
@ -195,22 +195,24 @@ class StripePaymentDriver extends BasePaymentDriver
|
||||
* @var amount_with_fee
|
||||
* @var token
|
||||
* @var payment_method_id
|
||||
* @var hashed_ids
|
||||
*
|
||||
* @param array $data variables required to build payment page
|
||||
* @return view Gateway and payment method specific view
|
||||
*/
|
||||
public function processPayment(array $data)
|
||||
public function processPaymentView(array $data)
|
||||
{
|
||||
$payment_intent_data = [
|
||||
'amount' => $data['amount_with_fee']*100,
|
||||
'currency' => $this->client->getCurrencyCode(),
|
||||
'customer' => $this->findOrCreateCustomer(),
|
||||
'description' => $data['invoices']->pluck('id'),
|
||||
'description' => $data['invoices']->pluck('id'), //todo more meaningful description here:
|
||||
];
|
||||
|
||||
if($data['token'])
|
||||
$payment_intent_data['payment_method'] = $data['token']->token;
|
||||
else{
|
||||
// $payment_intent_data['setup_future_usage'] = 'off_session';
|
||||
$payment_intent_data['setup_future_usage'] = 'off_session';
|
||||
// $payment_intent_data['save_payment_method'] = true;
|
||||
// $payment_intent_data['confirm'] = true;
|
||||
}
|
||||
@ -218,12 +220,88 @@ class StripePaymentDriver extends BasePaymentDriver
|
||||
|
||||
$data['intent'] = $this->createPaymentIntent($payment_intent_data);
|
||||
$data['gateway'] = $this;
|
||||
|
||||
|
||||
return view($this->viewForType($data['payment_method_id']), $data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment Intent Reponse looks like this
|
||||
+"id": "pi_1FMR7JKmol8YQE9DuC4zMeN3"
|
||||
+"object": "payment_intent"
|
||||
+"allowed_source_types": array:1 [▼
|
||||
0 => "card"
|
||||
]
|
||||
+"amount": 2372484
|
||||
+"canceled_at": null
|
||||
+"cancellation_reason": null
|
||||
+"capture_method": "automatic"
|
||||
+"client_secret": "pi_1FMR7JKmol8YQE9DuC4zMeN3_secret_J3yseWJG6uV0MmsrAT1FlUklV"
|
||||
+"confirmation_method": "automatic"
|
||||
+"created": 1569381877
|
||||
+"currency": "usd"
|
||||
+"description": "[3]"
|
||||
+"last_payment_error": null
|
||||
+"livemode": false
|
||||
+"next_action": null
|
||||
+"next_source_action": null
|
||||
+"payment_method": "pm_1FMR7ZKmol8YQE9DQWqPuyke"
|
||||
+"payment_method_types": array:1 [▶]
|
||||
+"receipt_email": null
|
||||
+"setup_future_usage": "off_session"
|
||||
+"shipping": null
|
||||
+"source": null
|
||||
+"status": "succeeded"
|
||||
*/
|
||||
public function processPaymentResponse($request)
|
||||
{
|
||||
$server_response = json_decode($request->input('gateway_response'));
|
||||
|
||||
$payment_method = $server_response->payment_method;
|
||||
$payment_status = $server_response->status;
|
||||
$save_card = $request->input('store_card');
|
||||
$gateway_type_id = $request->input('gateway_type_id');
|
||||
|
||||
$this->init()
|
||||
$payment_intent = \Stripe\PaymentIntent::retrieve($server_response->id);
|
||||
$customer = $payment_intent->customer;
|
||||
|
||||
if($save_card)
|
||||
{
|
||||
$this->init()
|
||||
$stripe_payment_method = \Stripe\PaymentMethod::retrieve($payment_method);
|
||||
$stripe_payment_method_obj = $stripe_payment_method->jsonSerialize();
|
||||
$stripe_payment_method->attach(['customer' => $customer]);
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
|
||||
if($stripe_payment_method_obj['type'] == 'card') {
|
||||
$payment_meta->exp_month = $stripe_payment_method_obj['card']['exp_month'];
|
||||
$payment_meta->exp_year = $stripe_payment_method_obj['card']['exp_year'];
|
||||
$payment_meta->brand = $stripe_payment_method_obj['card']['brand'];
|
||||
$payment_meta->last4 = $stripe_payment_method_obj['card']['last4'];
|
||||
$payment_meta->type = $stripe_payment_method_obj['type'];
|
||||
}
|
||||
|
||||
$cgt = new ClientGatewayToken;
|
||||
$cgt->company_id = $this->client->company->id;
|
||||
$cgt->client_id = $this->client->id;
|
||||
$cgt->token = $payment_method;
|
||||
$cgt->company_gateway_id = $this->company_gateway->id;
|
||||
$cgt->gateway_type_id = $gateway_type_id;
|
||||
$cgt->gateway_customer_reference = $customer;
|
||||
$cgt->meta = $payment_meta;
|
||||
$cgt->save();
|
||||
|
||||
if($is_default == 'true' || $this->client->gateway_tokens->count() == 1)
|
||||
{
|
||||
$this->client->gateway_tokens()->update(['is_default'=>0]);
|
||||
|
||||
$cgt->is_default = 1;
|
||||
$cgt->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new String Payment Intent
|
||||
|
@ -2,17 +2,27 @@
|
||||
|
||||
@section('pay_now')
|
||||
|
||||
{!! Former::framework('TwitterBootstrap4'); !!}
|
||||
|
||||
{!! Former::horizontal_open()
|
||||
->id('server_response')
|
||||
->route('client.payments.response')
|
||||
->method('POST'); !!}
|
||||
|
||||
{!! Former::hidden('gateway_response')->id('gateway_response') !!}
|
||||
{!! Former::hidden('store_card')->id('store_card') !!}
|
||||
{!! Former::hidden('hashed_ids')->value($hashed_ids) !!}
|
||||
{!! Former::hidden('company_gateway_id')->value($payment_method_id) !!}
|
||||
{!! Former::hidden('payment_method_id')->value($gateway->getCompanyGatewayId()) !!}
|
||||
{!! Former::close() !!}
|
||||
|
||||
|
||||
@if($token)
|
||||
<div class="py-md-5 ninja stripe">
|
||||
|
||||
<div class="form-group">
|
||||
<input class="form-control" id="cardholder-name" type="text" placeholder="{{ ctrans('texts.name') }}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div id="card-element"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button id="card-button" data-secret="{{ $intent->client_secret }}">
|
||||
Submit Payment
|
||||
<button id="card-button" class="btn btn-primary pull-right" data-secret="{{ $intent->client_secret }}">
|
||||
{{ ctrans('texts.pay_now') }} - {{ $token->meta->brand }} - {{ $token ->meta->last4}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -29,8 +39,8 @@
|
||||
</div>
|
||||
|
||||
<div class="form-check form-check-inline mr-1">
|
||||
<input class="form-check-input" id="proxy_is_default" type="checkbox">
|
||||
<label class="form-check-label" for="proxy_is_default">{{ ctrans('texts.save_as_default') }}</label>
|
||||
<input class="form-check-input" id="token_billing_checkbox" type="checkbox">
|
||||
<label class="form-check-label" for="token_billing_checkbox">{{ ctrans('texts.token_billing_checkbox') }}</label>
|
||||
</div>
|
||||
|
||||
|
||||
@ -38,7 +48,7 @@
|
||||
|
||||
<div class="form-group">
|
||||
<button id="card-button" class="btn btn-primary pull-right" data-secret="{{ $intent->client_secret }}">
|
||||
{{ ctrans('texts.pay_now') }}
|
||||
{{ ctrans('texts.pay_now') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -53,9 +63,6 @@
|
||||
var stripe = Stripe('{{ $gateway->getPublishableKey() }}');
|
||||
|
||||
var elements = stripe.elements();
|
||||
var cardElement = elements.create('card');
|
||||
cardElement.mount('#card-element');
|
||||
|
||||
|
||||
var cardholderName = document.getElementById('cardholder-name');
|
||||
var cardButton = document.getElementById('card-button');
|
||||
@ -65,7 +72,7 @@
|
||||
cardButton.addEventListener('click', function(ev) {
|
||||
stripe.handleCardPayment(
|
||||
clientSecret, {
|
||||
payment_method: {{$token->token}},
|
||||
payment_method: '{{$token->token}}',
|
||||
}
|
||||
).then(function(result) {
|
||||
if (result.error) {
|
||||
@ -82,6 +89,10 @@
|
||||
});
|
||||
});
|
||||
@else
|
||||
|
||||
var cardElement = elements.create('card');
|
||||
cardElement.mount('#card-element');
|
||||
|
||||
cardButton.addEventListener('click', function(ev) {
|
||||
stripe.handleCardPayment(
|
||||
clientSecret, cardElement, {
|
||||
@ -103,7 +114,7 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
@endif
|
||||
|
||||
$("#card-button").attr("disabled", true);
|
||||
|
||||
$('#cardholder-name').on('input',function(e){
|
||||
@ -112,12 +123,13 @@
|
||||
else
|
||||
$("#card-button").attr("disabled", true);
|
||||
});
|
||||
@endif
|
||||
|
||||
function postResult(result)
|
||||
{
|
||||
|
||||
$("#gateway_response").val(JSON.stringify(result.setupIntent));
|
||||
$("#is_default").val($('#proxy_is_default').is(":checked"));
|
||||
$("#gateway_response").val(JSON.stringify(result.paymentIntent));
|
||||
$("#store_card").val($('#token_billing_checkbox').is(":checked"));
|
||||
$("#card-button").attr("disabled", true);
|
||||
$('#server_response').submit();
|
||||
}
|
||||
|
@ -103,7 +103,6 @@ $(function() {
|
||||
data: function(data) {
|
||||
data.client_status = client_statuses;
|
||||
data.filter = table_filter;
|
||||
// data.search.value = table_filter;
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -25,6 +25,7 @@ Route::group(['middleware' => ['auth:contact'], 'prefix' => 'client', 'as' => 'c
|
||||
|
||||
Route::get('payments', 'ClientPortal\PaymentController@index')->name('payments.index');
|
||||
Route::post('payments/process', 'ClientPortal\PaymentController@process')->name('payments.process');
|
||||
Route::post('payments/process/response', 'ClientPortal\PaymentController@response')->name('payments.response');
|
||||
|
||||
Route::get('profile/{client_contact}/edit', 'ClientPortal\ProfileController@edit')->name('profile.edit');
|
||||
Route::put('profile/{client_contact}/edit', 'ClientPortal\ProfileController@update')->name('profile.update');
|
||||
|
Loading…
Reference in New Issue
Block a user