diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index 4dbeb2ae7f16..b8a52f6a284f 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -128,6 +128,9 @@ class PaymentController extends Controller { $gateway = CompanyGateway::find($request->input('company_gateway_id')); - return $gateway->driver(auth()->user()->client)->processPaymentResponse($request); + return $gateway + ->driver(auth()->user()->client) + ->setPaymentMethod('App\\PaymentDrivers\\Stripe\\CreditCard') + ->processPaymentResponse($request); } } diff --git a/app/PaymentDrivers/Stripe/CreditCard.php b/app/PaymentDrivers/Stripe/CreditCard.php index c3eb5426bb4d..678500a7101a 100644 --- a/app/PaymentDrivers/Stripe/CreditCard.php +++ b/app/PaymentDrivers/Stripe/CreditCard.php @@ -12,9 +12,16 @@ namespace App\PaymentDrivers\Stripe; +use App\Events\Payment\PaymentWasCreated; +use App\Jobs\Mail\PaymentFailureMailer; +use App\Jobs\Util\SystemLogger; use App\Models\ClientGatewayToken; use App\Models\GatewayType; +use App\Models\Invoice; +use App\Models\PaymentType; +use App\Models\SystemLog; use App\PaymentDrivers\StripePaymentDriver; +use Stripe\PaymentMethod; class CreditCard { @@ -100,8 +107,126 @@ class CreditCard return render('gateways.stripe.credit_card', $data); } - public function paymentResponse() + public function paymentResponse($request) { - # code... + $server_response = json_decode($request->input('gateway_response')); + + $state = [ + 'payment_method' => $server_response->payment_method, + 'payment_status' => $server_response->status, + 'save_card' => $request->store_card, + 'gateway_type_id' => $request->payment_method_id, + 'hashed_ids' => $request->hashed_ids, + 'server_response' => $server_response, + ]; + + $invoices = Invoice::whereIn('id', $this->stripe->transformKeys($state['hashed_ids'])) + ->whereClientId($this->stripe->client->id) + ->get(); + + if ($this->stripe->getContact()) { + $client_contact = $this->stripe->getContact(); + } else { + $client_contact = $invoices->first()->invitations->first()->contact; + } + + $this->stripe->init(); + + $state['payment_intent'] = \Stripe\PaymentIntent::retrieve($server_response->id); + $state['customer'] = $state['payment_intent']->customer; + + if ($state['payment_status'] == 'succeeded') { + return $this->processSuccessfulPayment($state); + } + + return $this->processUnsuccessfulPayment($server_response); + } + + private function processSuccessfulPayment($state) + { + $state['charge_id'] = $state['payment_intent']->charges->data[0]->id; + + $this->stripe->init(); + + $state['payment_method'] = PaymentMethod::retrieve($state['payment_method']); + $payment_method_object = $state['payment_method']->jsonSerialize(); + + $state['payment_meta'] = [ + 'exp_month' => $payment_method_object['card']['exp_month'], + 'exp_year' => $payment_method_object['card']['exp_year'], + 'brand' => $payment_method_object['card']['brand'], + 'last4' => $payment_method_object['card']['last4'], + 'type' => $payment_method_object['type'], + ]; + + $payment_type = PaymentType::parseCardType($payment_method_object['card']['brand']); + + if ($state['save_card'] === true) { + $this->saveCard($state); + } + + // Todo: Need to fix this to support payment types other than credit card.... sepa etc etc + if (!isset($state['payment_type'])) { + $state['payment_type'] = PaymentType::CREDIT_CARD_OTHER; + } + + $data = [ + 'payment_method' => $state['charge_id'], // ???? + 'payment_type' => $state['payment_type'], + 'amount' => $state['server_response']->amount, + ]; + + $payment = $this->stripe->createPayment($data); + + $this->stripe->attachInvoices($payment, $state['hashed_ids']); + + $payment->service()->updateInvoicePayment(); + + event(new PaymentWasCreated($payment, $payment->company)); + + $logger_message = [ + 'server_response' => $state['payment_intent'], + 'data' => $data + ]; + + SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_STRIPE, $this->stripe->client); + + return redirect()->route('client.payments.show', ['payment' => $this->stripe->encodePrimaryKey($payment->id)]); + } + + private function processUnsuccessfulPayment($server_response) + { + PaymentFailureMailer::dispatch($this->stripe->client, $server_response->cancellation_reason, $this->stripe->client->company, $server_response->amount); + + $message = [ + 'server_response' => $server_response, + 'data' => $data // - undefined @todo + ]; + + SystemLogger::dispatch($message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_STRIPE, $this->stripe->client); + + throw new \Exception('Failed to process the payment.', 1); + } + + private function saveCard($state) + { + $state['payment_method']->attach(['customer' => $state['customer']]); + + $company_gateway_token = new ClientGatewayToken(); + $company_gateway_token->company_id = $this->stripe->client->company->id; + $company_gateway_token->client_id = $this->stripe->client->id; + $company_gateway_token->token = $state['payment_method']; + $company_gateway_token->company_gateway_id = $this->stripe->company_gateway->id; + $company_gateway_token->gateway_type_id = $state['gateway_type_id']; + $company_gateway_token->gateway_customer_reference = $state['customer']; + $company_gateway_token->meta = $state['payment_meta']; + $company_gateway_token->save(); + + if ($this->stripe->client->gateway_tokens->count() == 1) { + $this->stripe->client->gateway_tokens()->update(['is_default' => 0]); + + $company_gateway_token->is_default = 1; + $company_gateway_token->save(); + } } } diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 036a13c1e625..d46df13b53fd 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -205,132 +205,7 @@ class StripePaymentDriver extends BasePaymentDriver */ public function processPaymentResponse($request) //We never have to worry about unsuccessful payments as failures are handled at the front end for this driver. { - $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('payment_method_id'); - $hashed_ids = $request->input('hashed_ids'); - $invoices = Invoice::whereIn('id', $this->transformKeys($hashed_ids)) - ->whereClientId($this->client->id) - ->get(); - /** - * Potential statuses that can be returned - * - * requires_action - * processing - * canceled - * requires_action - * requires_confirmation - * requires_payment_method - * - */ - - if ($this->getContact()) { - $client_contact = $this->getContact(); - } else { - $client_contact = $invoices->first()->invitations->first()->contact; - } - - $this->init(); - $payment_intent = \Stripe\PaymentIntent::retrieve($server_response->id); - $customer = $payment_intent->customer; - - if ($payment_status == 'succeeded') { - - $charge_id = $payment_intent->charges->data[0]->id; - - $this->init(); - $stripe_payment_method = \Stripe\PaymentMethod::retrieve($payment_method); - $stripe_payment_method_obj = $stripe_payment_method->jsonSerialize(); - - $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']; - - $payment_type = PaymentType::parseCardType($stripe_payment_method_obj['card']['brand']); - } - - if ($save_card == 'true') { - $stripe_payment_method->attach(['customer' => $customer]); - - $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 ($this->client->gateway_tokens->count() == 1) { - $this->client->gateway_tokens()->update(['is_default'=>0]); - - $cgt->is_default = 1; - $cgt->save(); - } - } - - //todo need to fix this to support payment types other than credit card.... sepa etc etc - if (!$payment_type) { - $payment_type = PaymentType::CREDIT_CARD_OTHER; - } - - - $data = [ - 'payment_method' => $charge_id, - 'payment_type' => $payment_type, - 'amount' => $server_response->amount, - ]; - - /* Create payment*/ - $payment = $this->createPayment($data); - - /* Link invoices to payment*/ - $this->attachInvoices($payment, $hashed_ids); - - $payment->service()->UpdateInvoicePayment(); - - event(new PaymentWasCreated($payment, $payment->company)); - - SystemLogger::dispatch( - [ - 'server_response' => $payment_intent, - 'data' => $data - ], - SystemLog::CATEGORY_GATEWAY_RESPONSE, - SystemLog::EVENT_GATEWAY_SUCCESS, - SystemLog::TYPE_STRIPE, - $this->client - ); - - return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); - } else { - - PaymentFailureMailer::dispatch($this->client, $server_response->cancellation_reason, $this->client->company, $server_response->amount); - - /*Fail and log*/ - SystemLogger::dispatch( - [ - 'server_response' => $server_response, - 'data' => $data - ], - SystemLog::CATEGORY_GATEWAY_RESPONSE, - SystemLog::EVENT_GATEWAY_FAILURE, - SystemLog::TYPE_STRIPE, - $this->client - ); - - throw new \Exception("Failed to process payment", 1); - } + return $this->payment_method->paymentResponse($request); } public function createPayment($data) :Payment