diff --git a/app/DataMapper/PaymentMethodMeta.php b/app/DataMapper/PaymentMethodMeta.php index 607f1c339d53..b97eca6bb860 100644 --- a/app/DataMapper/PaymentMethodMeta.php +++ b/app/DataMapper/PaymentMethodMeta.php @@ -13,13 +13,18 @@ namespace App\DataMapper; class PaymentMethodMeta { + /** @var string */ public $exp_month; + /** @var string */ public $exp_year; + /** @var string */ public $brand; + /** @var string */ public $last4; + /** @var int */ public $type; } diff --git a/app/Exceptions/PaymentFailed.php b/app/Exceptions/PaymentFailed.php new file mode 100644 index 000000000000..06d3f9dda5cb --- /dev/null +++ b/app/Exceptions/PaymentFailed.php @@ -0,0 +1,21 @@ + $this->getMessage(), + 'code' => $this->getCode(), + ]); + } +} diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index 31fb779d4e6d..8a2774551cb1 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -193,7 +193,7 @@ class PaymentController extends Controller $payment_hash = new PaymentHash; $payment_hash->hash = Str::random(128); - $payment_hash->data = $payable_invoices->toArray(); + $payment_hash->data = ['invoices' => $payable_invoices->toArray()]; $payment_hash->fee_total = $fee_totals; $payment_hash->fee_invoice_id = $first_invoice->id; $payment_hash->save(); @@ -220,17 +220,19 @@ class PaymentController extends Controller return $gateway ->driver(auth()->user()->client) ->setPaymentMethod($payment_method_id) + ->setPaymentHash($payment_hash) ->processPaymentView($data); } public function response(PaymentResponseRequest $request) { - /*Payment Gateway*/ $gateway = CompanyGateway::find($request->input('company_gateway_id'))->firstOrFail(); + $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->payment_hash])->first(); return $gateway ->driver(auth()->user()->client) ->setPaymentMethod($request->input('payment_method_id')) + ->setPaymentHash($payment_hash) ->processPaymentResponse($request); } diff --git a/app/Models/PaymentHash.php b/app/Models/PaymentHash.php index 2e16a8fc2631..f8eddf35f915 100644 --- a/app/Models/PaymentHash.php +++ b/app/Models/PaymentHash.php @@ -21,9 +21,10 @@ class PaymentHash extends Model 'data' => 'object', ]; + public function invoices() { - return $this->data; + return $this->data->invoices; } public function payment() diff --git a/app/PaymentDrivers/BaseDriver.php b/app/PaymentDrivers/BaseDriver.php index 678d2728ba77..ff5ccc51f105 100644 --- a/app/PaymentDrivers/BaseDriver.php +++ b/app/PaymentDrivers/BaseDriver.php @@ -13,8 +13,12 @@ namespace App\PaymentDrivers; use App\Events\Invoice\InvoiceWasPaid; +use App\Events\Payment\PaymentWasCreated; +use App\Exceptions\PaymentFailed; use App\Factory\PaymentFactory; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; +use App\Jobs\Mail\PaymentFailureMailer; +use App\Jobs\Util\SystemLogger; use App\Models\Client; use App\Models\ClientContact; use App\Models\ClientGatewayToken; @@ -22,6 +26,7 @@ use App\Models\CompanyGateway; use App\Models\Invoice; use App\Models\Payment; use App\Models\PaymentHash; +use App\Models\SystemLog; use App\PaymentDrivers\AbstractPaymentDriver; use App\Utils\Ninja; use App\Utils\Traits\MakesHash; @@ -57,6 +62,11 @@ class BaseDriver extends AbstractPaymentDriver /* The initiated gateway driver class*/ public $payment_method; + /** + * @var \App\Models\PaymentHash + */ + public $payment_hash; + public static $methods = []; public function __construct(CompanyGateway $company_gateway, Client $client = null, $invitation = false) @@ -111,6 +121,13 @@ class BaseDriver extends AbstractPaymentDriver { } + public function setPaymentHash(PaymentHash $payment_hash) + { + $this->payment_hash = $payment_hash; + + return $this; + } + /** * Helper method to attach invoices to a payment. * @@ -147,6 +164,24 @@ class BaseDriver extends AbstractPaymentDriver $payment->currency_id = $this->client->getSetting('currency_id'); $payment->date = Carbon::now(); + $client_contact = $this->getContact(); + $client_contact_id = $client_contact ? $client_contact->id : null; + + $payment->amount = $data['amount']; + $payment->type_id = $data['payment_type']; + $payment->transaction_reference = $data['payment_method']; + $payment->client_contact_id = $client_contact_id; + $payment->save(); + + $this->payment_hash->payment_id = $payment->id; + $this->payment_hash->save(); + + $this->attachInvoices($payment, $this->payment_hash); + + $payment->service()->updateInvoicePayment($this->payment_hash); + + event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); + return $payment->service()->applyNumber()->save(); } @@ -228,4 +263,59 @@ class BaseDriver extends AbstractPaymentDriver } } + + /** + * Store payment method as company gateway token. + * + * @param array $data + * @return null|\App\Models\ClientGatewayToken + */ + public function storeGatewayToken(array $data): ?ClientGatewayToken + { + $company_gateway_token = new ClientGatewayToken(); + $company_gateway_token->company_id = $this->client->company->id; + $company_gateway_token->client_id = $this->client->id; + $company_gateway_token->token = $data['token']; + $company_gateway_token->company_gateway_id = $this->company_gateway->id; + $company_gateway_token->gateway_type_id = $data['payment_method_id']; + $company_gateway_token->meta = $data['payment_meta']; + $company_gateway_token->save(); + + if ($this->client->gateway_tokens->count() == 1) { + $this->client->gateway_tokens()->update(['is_default' => 0]); + + $company_gateway_token->is_default = 1; + $company_gateway_token->save(); + } + + return $company_gateway_token; + } + + public function processInternallyFailedPayment($gateway, $e) + { + if ($e instanceof \Exception) { + $error = $e->getMessage(); + } + + if ($e instanceof \Checkout\Library\Exceptions\CheckoutHttpException) { + $error = $e->getBody(); + } + + PaymentFailureMailer::dispatch( + $gateway->client, + $error, + $gateway->client->company, + $this->payment_hash->data->value + ); + + SystemLogger::dispatch( + $this->checkout->payment_hash, + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_ERROR, + $gateway::SYSTEM_LOG_TYPE, + $this->checkout->client, + ); + + throw new PaymentFailed($error, $e->getCode()); + } } diff --git a/app/PaymentDrivers/CheckoutCom/CreditCard.php b/app/PaymentDrivers/CheckoutCom/CreditCard.php new file mode 100644 index 000000000000..ca946750713f --- /dev/null +++ b/app/PaymentDrivers/CheckoutCom/CreditCard.php @@ -0,0 +1,152 @@ +checkout = $checkout; + } + + /** + * An authorization view for credit card. + * + * @param mixed $data + * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View + */ + public function authorizeView($data) + { + return render('gateways.checkout.credit_card.authorize'); + } + + /** + * Checkout.com supports doesn't support direct authorization of the credit card. + * Token can be saved after the first (successful) purchase. + * + * @param mixed $data + * @return void + */ + public function authorizeResponse($data) + { + return; + } + + public function paymentView($data) + { + $data['gateway'] = $this->checkout; + $data['company_gateway'] = $this->checkout->company_gateway; + $data['client'] = $this->checkout->client; + $data['currency'] = $this->checkout->client->getCurrencyCode(); + $data['value'] = $this->checkout->convertToCheckoutAmount($data['amount_with_fee'], $this->checkout->client->getCurrencyCode()); + $data['raw_value'] = $data['amount_with_fee']; + $data['customer_email'] = $this->checkout->client->present()->email; + + return render('gateways.checkout.credit_card.pay', $data); + } + + public function paymentResponse(PaymentResponseRequest $request) + { + $this->checkout->init(); + + $state = [ + 'server_response' => json_decode($request->gateway_response), + 'value' => $request->value, + 'raw_value' => $request->raw_value, + 'currency' => $request->currency, + 'payment_hash' => $request->payment_hash, + 'reference' => $request->payment_hash, + ]; + + $state = array_merge($state, $request->all()); + $state['store_card'] = boolval($state['store_card']); + + $this->checkout->payment_hash->data = array_merge((array) $this->checkout->payment_hash->data, $state); + $this->checkout->payment_hash->save(); + + if ($request->has('token') && !is_null($request->token)) { + return $this->attemptPaymentUsingToken($request); + } + + return $this->attemptPaymentUsingCreditCard($request); + } + + private function attemptPaymentUsingToken(PaymentResponseRequest $request) + { + $method = new IdSource($this->checkout->payment_hash->data->token); + + return $this->completePayment($method, $request); + } + + private function attemptPaymentUsingCreditCard(PaymentResponseRequest $request) + { + $checkout_response = $this->checkout->payment_hash->data->server_response; + + $method = new TokenSource( + $checkout_response->cardToken + ); + + return $this->completePayment($method, $request); + } + + private function completePayment($method, PaymentResponseRequest $request) + { + $payment = new Payment($method, $this->checkout->payment_hash->data->currency); + $payment->amount = $this->checkout->payment_hash->data->value; + $payment->reference = $this->checkout->payment_hash->data->reference; + + if ($this->checkout->client->currency()->code === 'EUR') { + $payment->{'3ds'} = ['enabled' => true]; + } + + try { + $response = $this->checkout->gateway->payments()->request($payment); + + if ($response->status == 'Authorized') { + $this->checkout->confirmGatewayFee($request); + + return $this->processSuccessfulPayment($response); + } + + if ($response->status == 'Pending') { + $this->checkout->confirmGatewayFee($request); + + return $this->processPendingPayment($response); + } + + if ($response->status == 'Declined') { + $this->checkout->unWindGatewayFees($this->checkout->payment_hash); + + return $this->processUnsuccessfulPayment($response); + } + } catch (\Checkout\Library\Exceptions\CheckoutHttpException $e) { + $this->checkout->unWindGatewayFees($this->checkout->payment_hash); + + return $this->processInternallyFailedPayment($e); + } + } +} diff --git a/app/PaymentDrivers/CheckoutCom/Utilities.php b/app/PaymentDrivers/CheckoutCom/Utilities.php index 20804a258de0..5f24015e074f 100644 --- a/app/PaymentDrivers/CheckoutCom/Utilities.php +++ b/app/PaymentDrivers/CheckoutCom/Utilities.php @@ -12,6 +12,13 @@ namespace App\PaymentDrivers\CheckoutCom; +use App\Exceptions\PaymentFailed; +use App\Jobs\Mail\PaymentFailureMailer; +use App\Jobs\Util\SystemLogger; +use App\Models\GatewayType; +use App\Models\PaymentType; +use App\Models\SystemLog; + trait Utilities { public function getPublishableKey() @@ -39,4 +46,101 @@ trait Utilities // https://docs.checkout.com/resources/calculating-the-value#Calculatingthevalue-Option3:Thevaluedividedby100valuediv100 return round($amount * 100); } + + private function processSuccessfulPayment(\Checkout\Models\Payments\Payment $_payment) + { + if ($this->checkout->payment_hash->data->store_card) { + $this->storePaymentMethod($_payment); + } + + $data = [ + 'payment_method' => $_payment->source['id'], + 'payment_type' => PaymentType::parseCardType(strtolower($_payment->source['scheme'])), + 'amount' => $this->checkout->payment_hash->data->raw_value, + ]; + + $payment = $this->checkout->createPayment($data, \App\Models\Payment::STATUS_COMPLETED); + + SystemLogger::dispatch( + ['response' => $_payment, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_CHECKOUT, + $this->checkout->client + ); + + return redirect()->route('client.payments.show', ['payment' => $this->checkout->encodePrimaryKey($payment->id)]); + } + + public function processUnsuccessfulPayment(\Checkout\Models\Payments\Payment $_payment) + { + PaymentFailureMailer::dispatch( + $this->checkout->client, + $_payment, + $this->checkout->client->company, + $this->checkout->payment_hash->data->value + ); + + $message = [ + 'server_response' => $_payment, + 'data' => $this->checkout->payment_hash->data, + ]; + + SystemLogger::dispatch( + $message, + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_FAILURE, + SystemLog::TYPE_CHECKOUT, + $this->checkout->client + ); + + throw new PaymentFailed($_payment->status, $_payment->http_code); + } + + private function processPendingPayment(\Checkout\Models\Payments\Payment $_payment) + { + $data = [ + 'payment_method' => $_payment->source['id'], + 'payment_type' => PaymentType::parseCardType(strtolower($_payment->source['scheme'])), + 'amount' => $this->checkout->payment_hash->data->value, + ]; + + $payment = $this->checkout->createPayment($data, \App\Models\Payment::STATUS_PENDING); + + SystemLogger::dispatch( + ['response' => $_payment, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_CHECKOUT, + $this->checkout->client + ); + + try { + return redirect($_payment->_links['redirect']['href']); + } catch (\Exception $e) { + return $this->processInternallyFailedPayment($this->checkout, $e); + } + } + + private function storePaymentMethod(\Checkout\Models\Payments\Payment $response) + { + try { + $payment_meta = new \stdClass; + $payment_meta->exp_month = (string) $response->source['expiry_month']; + $payment_meta->exp_year = (string) $response->source['expiry_year']; + $payment_meta->brand = (string) $response->source['scheme']; + $payment_meta->last4 = (string) $response->source['last4']; + $payment_meta->type = (int) GatewayType::CREDIT_CARD; + + $data = [ + 'payment_meta' => $payment_meta, + 'token' => $response->id, + 'payment_method_id' => $this->checkout->payment_hash->data->payment_method_id, + ]; + + return $this->checokut->saveCard($data); + } catch (\Exception $e) { + session()->flash('message', ctrans('texts.payment_method_saving_failed')); + } + } } diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index 4d854817df27..f479ab1db6a8 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -12,24 +12,16 @@ namespace App\PaymentDrivers; -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\Payment; use App\Models\PaymentHash; -use App\Models\PaymentType; use App\Models\SystemLog; use App\PaymentDrivers\BaseDriver; use App\PaymentDrivers\CheckoutCom\Utilities; -use App\Utils\Ninja; use App\Utils\Traits\SystemLogTrait; use Checkout\CheckoutApi; use Checkout\Library\Exceptions\CheckoutHttpException; -use Checkout\Models\Payments\IdSource; -use Checkout\Models\Payments\Payment as CheckoutPayment; -use Checkout\Models\Payments\TokenSource; class CheckoutComPaymentDriver extends BaseDriver { @@ -50,15 +42,19 @@ class CheckoutComPaymentDriver extends BaseDriver /* Authorise payment methods */ public $can_authorise_credit_card = true; - /** Instance of \Checkout\CheckoutApi */ + /** + * @var \Checkout\CheckoutApi; + */ public $gateway; public $payment_method; //the gateway type id public static $methods = [ - GatewayType::CREDIT_CARD => '', + GatewayType::CREDIT_CARD => \App\PaymentDrivers\CheckoutCom\CreditCard::class, ]; + const SYSTEM_LOG_TYPE = SystemLog::TYPE_CHECKOUT; + /** * Returns the default gateway type. */ @@ -75,6 +71,13 @@ class CheckoutComPaymentDriver extends BaseDriver */ public function setPaymentMethod($payment_method = null) { + // At the moment Checkout.com payment + // driver only supports payments using credit card. + + $class = self::$methods[GatewayType::CREDIT_CARD]; + + $this->payment_method = new $class($this); + return $this; } @@ -82,7 +85,7 @@ class CheckoutComPaymentDriver extends BaseDriver * Initialize the checkout payment driver * @return $this */ - public function init() + public function init() { $config = [ 'secret' => $this->company_gateway->getConfigField('secretApiKey'), @@ -102,22 +105,20 @@ class CheckoutComPaymentDriver extends BaseDriver */ public function viewForType($gateway_type_id) { - //currently only ever token or creditcard so no need for switches - $this->payment_method = $gateway_type_id; + // At the moment Checkout.com payment + // driver only supports payments using credit card. - return 'gateways.checkout.credit_card'; - + return 'gateways.checkout.credit_card.pay'; } - /** - * Authorization view - * - * @param array $data Payment data array - * @return view Authorization View - */ public function authorizeView($data) { - return render('gateways.checkout.authorize'); + return $this->payment_method->authorizeView($data); + } + + public function authorizeResponse($data) + { + return $this->payment_method->authorizeResponse($data); } /** @@ -128,15 +129,7 @@ class CheckoutComPaymentDriver extends BaseDriver */ public function processPaymentView(array $data) { - $data['gateway'] = $this; - $data['company_gateway'] = $this->company_gateway; - $data['client'] = $this->client; - $data['currency'] = $this->client->getCurrencyCode(); - $data['value'] = $this->convertToCheckoutAmount($data['amount_with_fee'], $this->client->getCurrencyCode()); - $data['raw_value'] = $data['amount_with_fee']; - $data['customer_email'] = $this->client->present()->email; - - return render($this->viewForType($data['payment_method_id']), $data); + return $this->payment_method->paymentView($data); } /** @@ -147,259 +140,12 @@ class CheckoutComPaymentDriver extends BaseDriver */ public function processPaymentResponse($request) { - $this->init(); - - $state = [ - 'server_response' => json_decode($request->gateway_response), - 'value' => $request->value, - 'raw_value' => $request->raw_value, - 'currency' => $request->currency, - 'payment_hash' =>$request->payment_hash, - 'reference' => $request->payment_hash, - ]; - - $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->payment_hash])->first(); - - $state = array_merge($state, $request->all()); - $state['store_card'] = boolval($state['store_card']); - - if ($request->has('token') && ! is_null($request->token)) { - $method = new IdSource($state['token']); - $payment = new CheckoutPayment($method, $state['currency']); - $payment->amount = $state['value']; - $payment->reference = $state['reference']; - } else { - $method = new TokenSource($state['server_response']->cardToken); - $payment = new CheckoutPayment($method, $state['currency']); - $payment->amount = $state['value']; - $payment->reference = $state['reference']; - - if ($this->client->currency()->code === 'EUR') { - $payment->{'3ds'} = ['enabled' => true]; - } - } - - try { - $response = $this->gateway->payments()->request($payment); - $state['payment_response'] = $response; - - if ($response->status === 'Authorized') { - - $this->confirmGatewayFee($request); - - return $this->processSuccessfulPayment($state); - } - - if ($response->status === 'Pending') { - - $this->confirmGatewayFee($request); - - return $this->processPendingPayment($state); - } - - if ($response->status === 'Declined') { - $this->unWindGatewayFees($payment_hash); - - return $this->processUnsuccessfulPayment($state); - } - } catch (CheckoutHttpException $e) { - - $this->unWindGatewayFees($payment_hash); - - return $this->processInternallyFailedPayment($e, $state); - } + return $this->payment_method->paymentResponse($request); } - /** - * Process a successful payment response - * - * @param array $state The state array - * @return view The response - */ - public function processSuccessfulPayment($state) + public function storePaymentMethod(array $data) { - $state['charge_id'] = $state['payment_response']->id; - - if (isset($state['store_card']) && $state['store_card']) { - $this->saveCard($state); - } - - $data = [ - 'payment_method' => $state['charge_id'], - 'payment_type' => PaymentType::parseCardType($state['payment_response']->source['scheme']), - 'amount' => $state['raw_value'], - ]; - - $payment = $this->createPayment($data, Payment::STATUS_COMPLETED); - $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$state['payment_hash']])->firstOrFail(); - $payment_hash->payment_id = $payment->id; - $payment_hash->save(); - - $this->attachInvoices($payment, $payment_hash); - $payment->service()->updateInvoicePayment($payment_hash); - - event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); - - $logger_message = [ - 'server_response' => $state['payment_response'], - 'data' => $data, - ]; - - SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_CHECKOUT, $this->client); - - return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]); - } - - public function processPendingPayment($state) - { - $state['charge_id'] = $state['payment_response']->id; - - if (isset($state['store_card']) && $state['store_card']) { - $this->saveCard($state); - } - - $data = [ - 'payment_method' => $state['charge_id'], - 'payment_type' => PaymentType::parseCardType($state['payment_response']->source['scheme']), - 'amount' => $state['raw_value'], - ]; - - $payment = $this->createPayment($data, Payment::STATUS_PENDING); - - $this->attachInvoices($payment, $state['payment_hash']); - - $payment->service()->updateInvoicePayment($state['payment_hash']); - - event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars())); - - $logger_message = [ - 'server_response' => $state['payment_response'], - 'data' => $data, - ]; - - SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_SUCCESS, SystemLog::TYPE_CHECKOUT, $this->client); - - try { - return redirect($state['payment_response']->_links['redirect']['href']); - } catch (\Exception $e) { - - SystemLogger::dispatch($logger_message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_CHECKOUT, $this->client); - - $this->unWindGatewayFees($state['payment_hash']); - - return render('gateways.unsuccessful', [ - 'code' => $state['payment_response']->response_code, - 'message' => ctrans('texts.payment_error'), - ]); - - } - } - - public function processUnsuccessfulPayment($state) - { - PaymentFailureMailer::dispatch($this->client, $state['payment_response']->response_summary, $this->client->company, $state['payment_response']->amount); - - $message = [ - 'server_response' => $state['server_response'], - 'data' => $state, - ]; - - SystemLogger::dispatch($message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_CHECKOUT, $this->client); - - // throw new \Exception('Failed to process the payment: ' . $state['payment_response']->response_summary, 1); - - return render('gateways.unsuccessful', [ - 'code' => $state['payment_response']->response_code, - 'message' => ctrans('texts.payment_error'), - ]); - } - - public function processInternallyFailedPayment($e, $state) - { - $error_message = json_decode($e->getBody()); - - PaymentFailureMailer::dispatch($this->client, $error_message->message, $this->client->company, $state['value']); - - $message = [ - 'server_response' => $state['server_response'], - 'data' => $e->getBody(), - ]; - - SystemLogger::dispatch($message, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_CHECKOUT, $this->client); - - //todo push to a error page with the exception message. - - //throw new \Exception('Failed to process the payment.', 1); - - return render('gateways.unsuccessful', [ - 'code' => '500', - 'message' => ctrans('texts.payment_error'), - ]); - } - - public function createPayment($data, $status = Payment::STATUS_COMPLETED): Payment - { - $payment = parent::createPayment($data, $status); - - $client_contact = $this->getContact(); - $client_contact_id = $client_contact ? $client_contact->id : null; - - $payment->amount = $data['amount']; - $payment->type_id = $data['payment_type']; - $payment->transaction_reference = $data['payment_method']; - $payment->client_contact_id = $client_contact_id; - $payment->save(); - - return $payment; - } - - public function saveCard($state) - { - //some cards just can't be tokenized.... - if(!$state['payment_response']->source['id']) - return; - - // [id] => src_hck5nsv3fljehbam2cvdm7fioa - // [type] => card - // [expiry_month] => 10 - // [expiry_year] => 2022 - // [scheme] => Visa - // [last4] => 4242 - // [fingerprint] => 688192847DB9AE8A26C53776D036D5B8AD2CEAF1D5A8F5475F542B021041EFA1 - // [bin] => 424242 - // [card_type] => Credit - // [card_category] => Consumer - // [issuer] => JPMORGAN CHASE BANK NA - // [issuer_country] => US - // [product_id] => A - // [product_type] => Visa Traditional - // [avs_check] => S - // [cvv_check] => Y - // [payouts] => 1 - // [fast_funds] => d - - $payment_meta = new \stdClass; - $payment_meta->exp_month = (string)$state['payment_response']->source['expiry_month']; - $payment_meta->exp_year = (string)$state['payment_response']->source['expiry_year']; - $payment_meta->brand = (string)$state['payment_response']->source['scheme']; - $payment_meta->last4 = (string)$state['payment_response']->source['last4']; - $payment_meta->type = $this->payment_method; - - $company_gateway_token = new ClientGatewayToken(); - $company_gateway_token->company_id = $this->client->company->id; - $company_gateway_token->client_id = $this->client->id; - $company_gateway_token->token = $state['payment_response']->source['id']; - $company_gateway_token->company_gateway_id = $this->company_gateway->id; - $company_gateway_token->gateway_type_id = $state['payment_method_id']; - $company_gateway_token->meta = $payment_meta; - $company_gateway_token->save(); - - if ($this->client->gateway_tokens->count() == 1) { - $this->client->gateway_tokens()->update(['is_default' => 0]); - - $company_gateway_token->is_default = 1; - $company_gateway_token->save(); - } + return $this->storeGatewayToken($data); } public function refund(Payment $payment, $amount, $return_client_response = false) diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 1c8d955e504a..2e03c249ad19 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -3288,4 +3288,5 @@ return [ 'payment_type_Crypto' => 'Cryptocurrency', 'payment_type_Credit' => 'Credit', + 'payment_method_saving_failed' => 'Payment method can\'t be saved for future use.', ]; diff --git a/resources/views/portal/ninja2020/gateways/checkout/authorize.blade.php b/resources/views/portal/ninja2020/gateways/checkout/credit_card/authorize.blade.php similarity index 100% rename from resources/views/portal/ninja2020/gateways/checkout/authorize.blade.php rename to resources/views/portal/ninja2020/gateways/checkout/credit_card/authorize.blade.php diff --git a/resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php b/resources/views/portal/ninja2020/gateways/checkout/credit_card/pay.blade.php similarity index 100% rename from resources/views/portal/ninja2020/gateways/checkout/credit_card.blade.php rename to resources/views/portal/ninja2020/gateways/checkout/credit_card/pay.blade.php