diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index 0770470d5bfd..94c18469a8b3 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -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); + + } } diff --git a/app/PaymentDrivers/BasePaymentDriver.php b/app/PaymentDrivers/BasePaymentDriver.php index 71dbabc8d1fa..7d984d95d0c8 100644 --- a/app/PaymentDrivers/BasePaymentDriver.php +++ b/app/PaymentDrivers/BasePaymentDriver.php @@ -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 diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index c430e69bebd1..a28a42171668 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -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 diff --git a/resources/views/portal/default/gateways/stripe/credit_card.blade.php b/resources/views/portal/default/gateways/stripe/credit_card.blade.php index d3797afc0175..af14b691766c 100644 --- a/resources/views/portal/default/gateways/stripe/credit_card.blade.php +++ b/resources/views/portal/default/gateways/stripe/credit_card.blade.php @@ -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)
+
- -
-
-
-
-
-
@@ -29,8 +39,8 @@
- - + +
@@ -38,7 +48,7 @@
@@ -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(); } diff --git a/resources/views/portal/default/invoices/index.blade.php b/resources/views/portal/default/invoices/index.blade.php index 35f6a45f492a..eaeea9fa7508 100644 --- a/resources/views/portal/default/invoices/index.blade.php +++ b/resources/views/portal/default/invoices/index.blade.php @@ -103,7 +103,6 @@ $(function() { data: function(data) { data.client_status = client_statuses; data.filter = table_filter; - // data.search.value = table_filter; } }, diff --git a/routes/client.php b/routes/client.php index c5cae630faa8..c8028fdf3600 100644 --- a/routes/client.php +++ b/routes/client.php @@ -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');