mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge pull request #6842 from beganovich/v5-728
Checkout.com: Standalone credit card authorization
This commit is contained in:
commit
384642acde
@ -14,9 +14,12 @@ namespace App\PaymentDrivers\CheckoutCom;
|
|||||||
|
|
||||||
use App\Exceptions\PaymentFailed;
|
use App\Exceptions\PaymentFailed;
|
||||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||||
|
use App\Http\Requests\Request;
|
||||||
use App\Jobs\Mail\PaymentFailureMailer;
|
use App\Jobs\Mail\PaymentFailureMailer;
|
||||||
use App\Models\ClientGatewayToken;
|
use App\Models\ClientGatewayToken;
|
||||||
|
use App\Models\GatewayType;
|
||||||
use App\PaymentDrivers\CheckoutComPaymentDriver;
|
use App\PaymentDrivers\CheckoutComPaymentDriver;
|
||||||
|
use App\PaymentDrivers\Common\MethodInterface;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Checkout\Library\Exceptions\CheckoutHttpException;
|
use Checkout\Library\Exceptions\CheckoutHttpException;
|
||||||
use Checkout\Models\Payments\IdSource;
|
use Checkout\Models\Payments\IdSource;
|
||||||
@ -25,7 +28,7 @@ use Checkout\Models\Payments\TokenSource;
|
|||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
class CreditCard
|
class CreditCard implements MethodInterface
|
||||||
{
|
{
|
||||||
use Utilities;
|
use Utilities;
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
@ -38,6 +41,8 @@ class CreditCard
|
|||||||
public function __construct(CheckoutComPaymentDriver $checkout)
|
public function __construct(CheckoutComPaymentDriver $checkout)
|
||||||
{
|
{
|
||||||
$this->checkout = $checkout;
|
$this->checkout = $checkout;
|
||||||
|
|
||||||
|
$this->checkout->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,15 +59,50 @@ class CreditCard
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checkout.com supports doesn't support direct authorization of the credit card.
|
* Handle authorization for credit card.
|
||||||
* Token can be saved after the first (successful) purchase.
|
|
||||||
*
|
*
|
||||||
* @param mixed $data
|
* @param Request $request
|
||||||
* @return void
|
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function authorizeResponse($data)
|
public function authorizeResponse(Request $request)
|
||||||
{
|
{
|
||||||
return;
|
$gateway_response = \json_decode($request->gateway_response);
|
||||||
|
|
||||||
|
$method = new TokenSource(
|
||||||
|
$gateway_response->token
|
||||||
|
);
|
||||||
|
|
||||||
|
$payment = new Payment($method, 'USD');
|
||||||
|
$payment->amount = 100; // $1
|
||||||
|
$payment->reference = '$1 payment for authorization.';
|
||||||
|
$payment->capture = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $this->checkout->gateway->payments()->request($payment);
|
||||||
|
|
||||||
|
if ($response->approved && $response->status === 'Authorized') {
|
||||||
|
$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->source['id'],
|
||||||
|
'payment_method_id' => GatewayType::CREDIT_CARD,
|
||||||
|
];
|
||||||
|
|
||||||
|
$payment_method = $this->checkout->storeGatewayToken($data);
|
||||||
|
|
||||||
|
return redirect()->route('client.payment_methods.show', $payment_method->hashed_id);
|
||||||
|
}
|
||||||
|
} catch (CheckoutHttpException $exception) {
|
||||||
|
throw new PaymentFailed(
|
||||||
|
$exception->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function paymentView($data)
|
public function paymentView($data)
|
||||||
@ -80,8 +120,6 @@ class CreditCard
|
|||||||
|
|
||||||
public function paymentResponse(PaymentResponseRequest $request)
|
public function paymentResponse(PaymentResponseRequest $request)
|
||||||
{
|
{
|
||||||
$this->checkout->init();
|
|
||||||
|
|
||||||
$state = [
|
$state = [
|
||||||
'server_response' => json_decode($request->gateway_response),
|
'server_response' => json_decode($request->gateway_response),
|
||||||
'value' => $request->value,
|
'value' => $request->value,
|
||||||
@ -133,7 +171,6 @@ class CreditCard
|
|||||||
|
|
||||||
private function completePayment($method, PaymentResponseRequest $request)
|
private function completePayment($method, PaymentResponseRequest $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
$payment = new Payment($method, $this->checkout->payment_hash->data->currency);
|
$payment = new Payment($method, $this->checkout->payment_hash->data->currency);
|
||||||
$payment->amount = $this->checkout->payment_hash->data->value;
|
$payment->amount = $this->checkout->payment_hash->data->value;
|
||||||
$payment->reference = $this->checkout->getDescription();
|
$payment->reference = $this->checkout->getDescription();
|
||||||
@ -161,7 +198,6 @@ class CreditCard
|
|||||||
$response = $this->checkout->gateway->payments()->request($payment);
|
$response = $this->checkout->gateway->payments()->request($payment);
|
||||||
|
|
||||||
if ($response->status == 'Authorized') {
|
if ($response->status == 'Authorized') {
|
||||||
|
|
||||||
return $this->processSuccessfulPayment($response);
|
return $this->processSuccessfulPayment($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +217,6 @@ class CreditCard
|
|||||||
return $this->processUnsuccessfulPayment($response);
|
return $this->processUnsuccessfulPayment($response);
|
||||||
}
|
}
|
||||||
} catch (CheckoutHttpException $e) {
|
} catch (CheckoutHttpException $e) {
|
||||||
|
|
||||||
$this->checkout->unWindGatewayFees($this->checkout->payment_hash);
|
$this->checkout->unWindGatewayFees($this->checkout->payment_hash);
|
||||||
return $this->checkout->processInternallyFailedPayment($this->checkout, $e);
|
return $this->checkout->processInternallyFailedPayment($this->checkout, $e);
|
||||||
}
|
}
|
||||||
|
2
public/js/clients/payment_methods/authorize-checkout-card.js
vendored
Normal file
2
public/js/clients/payment_methods/authorize-checkout-card.js
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/*! For license information please see authorize-checkout-card.js.LICENSE.txt */
|
||||||
|
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=29)}({29:function(e,t,n){e.exports=n("kduS")},kduS:function(e,t){function n(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}(new(function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.button=document.querySelector("#pay-button")}var t,r,o;return t=e,(r=[{key:"init",value:function(){this.frames=Frames.init(document.querySelector("meta[name=public-key]").content)}},{key:"handle",value:function(){var e=this;this.init(),Frames.addEventHandler(Frames.Events.CARD_VALIDATION_CHANGED,(function(t){e.button.disabled=!Frames.isCardValid()})),Frames.addEventHandler(Frames.Events.CARD_TOKENIZED,(function(e){document.querySelector('input[name="gateway_response"]').value=JSON.stringify(e),document.getElementById("server_response").submit()})),document.querySelector("#authorization-form").addEventListener("submit",(function(t){e.button.disabled=!0,t.preventDefault(),Frames.submitCard()}))}}])&&n(t.prototype,r),o&&n(t,o),e}())).handle()}});
|
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
@ -5,6 +5,7 @@
|
|||||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
|
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1",
|
||||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7",
|
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7",
|
||||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=f7f4ecfb1771951b91e7",
|
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=f7f4ecfb1771951b91e7",
|
||||||
|
"/js/clients/payment_methods/authorize-checkout-card.js": "/js/clients/payment_methods/authorize-checkout-card.js?id=d23f32f956a8c8927339",
|
||||||
"/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=9fb7941baba1f9645ed9",
|
"/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=9fb7941baba1f9645ed9",
|
||||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=8fea0be371d430064a89",
|
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=8fea0be371d430064a89",
|
||||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=7c2cbef525868592f42e",
|
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=7c2cbef525868592f42e",
|
||||||
|
51
resources/js/clients/payment_methods/authorize-checkout-card.js
vendored
Normal file
51
resources/js/clients/payment_methods/authorize-checkout-card.js
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CheckoutCreditCardAuthorization {
|
||||||
|
constructor() {
|
||||||
|
this.button = document.querySelector('#pay-button');
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.frames = Frames.init(
|
||||||
|
document.querySelector('meta[name=public-key]').content
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle() {
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
Frames.addEventHandler(
|
||||||
|
Frames.Events.CARD_VALIDATION_CHANGED,
|
||||||
|
(event) => {
|
||||||
|
this.button.disabled = !Frames.isCardValid();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Frames.addEventHandler(Frames.Events.CARD_TOKENIZED, (event) => {
|
||||||
|
document.querySelector(
|
||||||
|
'input[name="gateway_response"]'
|
||||||
|
).value = JSON.stringify(event);
|
||||||
|
|
||||||
|
document.getElementById('server_response').submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelector('#authorization-form')
|
||||||
|
.addEventListener('submit', (event) => {
|
||||||
|
this.button.disabled = true;
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
Frames.submitCard();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new CheckoutCreditCardAuthorization().handle();
|
@ -1,7 +1,44 @@
|
|||||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'Credit card', 'card_title' => 'Credit card'])
|
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'Credit card', 'card_title' => 'Credit card'])
|
||||||
|
|
||||||
|
@section('gateway_head')
|
||||||
|
<meta name="public-key" content="{{ $gateway->getPublishableKey() }}">
|
||||||
|
|
||||||
|
@include('portal.ninja2020.gateways.checkout.credit_card.includes.styles')
|
||||||
|
|
||||||
|
<script src="https://cdn.checkout.com/js/framesv2.min.js"></script>
|
||||||
|
@endsection
|
||||||
|
|
||||||
@section('gateway_content')
|
@section('gateway_content')
|
||||||
@component('portal.ninja2020.components.general.card-element-single', ['title' => 'Credit card', 'show_title' => false])
|
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::CREDIT_CARD]) }}"
|
||||||
{{ __('texts.checkout_authorize_label') }}
|
method="post" id="server_response">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<input type="hidden" name="payment_method_id" value="{{ \App\Models\GatewayType::CREDIT_CARD }}">
|
||||||
|
<input type="hidden" name="gateway_response" id="gateway_response">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
|
||||||
|
{{ ctrans('texts.credit_card') }}
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element-single')
|
||||||
|
<div id="checkout--container">
|
||||||
|
<form class="xl:flex xl:justify-center" id="authorization-form" method="POST" action="#">
|
||||||
|
<div class="one-liner">
|
||||||
|
<div class="card-frame">
|
||||||
|
<!-- form will be added here -->
|
||||||
|
</div>
|
||||||
|
<!-- add submit button -->
|
||||||
|
<button id="pay-button" disabled>
|
||||||
|
{{ ctrans('texts.add_payment_method') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p class="success-payment-message"></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@endcomponent
|
@endcomponent
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_footer')
|
||||||
|
<script src="{{ asset('js/clients/payment_methods/authorize-checkout-card.js') }}"></script>
|
||||||
|
@endsection
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
<style>
|
||||||
|
*,
|
||||||
|
*::after,
|
||||||
|
*::before {
|
||||||
|
box-sizing: border-box
|
||||||
|
}
|
||||||
|
|
||||||
|
#payment-form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
.one-liner {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column
|
||||||
|
}
|
||||||
|
|
||||||
|
#pay-button {
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #FFF;
|
||||||
|
font-weight: 500;
|
||||||
|
height: 40px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #13395E;
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(19, 57, 94, 0.4)
|
||||||
|
}
|
||||||
|
|
||||||
|
#pay-button:active {
|
||||||
|
background-color: #0B2A49;
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(19, 57, 94, 0.4)
|
||||||
|
}
|
||||||
|
|
||||||
|
#pay-button:hover {
|
||||||
|
background-color: #15406B;
|
||||||
|
box-shadow: 0 2px 5px 0 rgba(19, 57, 94, 0.4)
|
||||||
|
}
|
||||||
|
|
||||||
|
#pay-button:disabled {
|
||||||
|
background-color: #697887;
|
||||||
|
box-shadow: none
|
||||||
|
}
|
||||||
|
|
||||||
|
#pay-button:not(:disabled) {
|
||||||
|
cursor: pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-frame {
|
||||||
|
border: solid 1px #13395E;
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
height: 40px;
|
||||||
|
box-shadow: 0 1px 3px 0 rgba(19, 57, 94, 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-frame.frame--rendered {
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-frame.frame--rendered.frame--focus {
|
||||||
|
border: solid 1px #13395E;
|
||||||
|
box-shadow: 0 2px 5px 0 rgba(19, 57, 94, 0.15)
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-frame.frame--rendered.frame--invalid {
|
||||||
|
border: solid 1px #D96830;
|
||||||
|
box-shadow: 0 2px 5px 0 rgba(217, 104, 48, 0.15)
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-payment-message {
|
||||||
|
color: #13395E;
|
||||||
|
line-height: 1.4
|
||||||
|
}
|
||||||
|
|
||||||
|
.token {
|
||||||
|
color: #b35e14;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-family: monospace
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 31rem) {
|
||||||
|
.one-liner {
|
||||||
|
flex-direction: row
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-frame {
|
||||||
|
width: 318px;
|
||||||
|
margin-bottom: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#pay-button {
|
||||||
|
width: 175px;
|
||||||
|
margin-left: 8px
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
@ -7,101 +7,7 @@
|
|||||||
<meta name="currency" content="{{ $currency }}">
|
<meta name="currency" content="{{ $currency }}">
|
||||||
<meta name="reference" content="{{ $payment_hash }}">
|
<meta name="reference" content="{{ $payment_hash }}">
|
||||||
|
|
||||||
<style>*, *::after, *::before {
|
@include('portal.ninja2020.gateways.checkout.credit_card.includes.styles')
|
||||||
box-sizing: border-box
|
|
||||||
}
|
|
||||||
#payment-form {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
iframe {
|
|
||||||
width: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
.one-liner {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column
|
|
||||||
}
|
|
||||||
|
|
||||||
#pay-button {
|
|
||||||
border: none;
|
|
||||||
border-radius: 3px;
|
|
||||||
color: #FFF;
|
|
||||||
font-weight: 500;
|
|
||||||
height: 40px;
|
|
||||||
width: 100%;
|
|
||||||
background-color: #13395E;
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(19, 57, 94, 0.4)
|
|
||||||
}
|
|
||||||
|
|
||||||
#pay-button:active {
|
|
||||||
background-color: #0B2A49;
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(19, 57, 94, 0.4)
|
|
||||||
}
|
|
||||||
|
|
||||||
#pay-button:hover {
|
|
||||||
background-color: #15406B;
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(19, 57, 94, 0.4)
|
|
||||||
}
|
|
||||||
|
|
||||||
#pay-button:disabled {
|
|
||||||
background-color: #697887;
|
|
||||||
box-shadow: none
|
|
||||||
}
|
|
||||||
|
|
||||||
#pay-button:not(:disabled) {
|
|
||||||
cursor: pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-frame {
|
|
||||||
border: solid 1px #13395E;
|
|
||||||
border-radius: 3px;
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
height: 40px;
|
|
||||||
box-shadow: 0 1px 3px 0 rgba(19, 57, 94, 0.2)
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-frame.frame--rendered {
|
|
||||||
opacity: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-frame.frame--rendered.frame--focus {
|
|
||||||
border: solid 1px #13395E;
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(19, 57, 94, 0.15)
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-frame.frame--rendered.frame--invalid {
|
|
||||||
border: solid 1px #D96830;
|
|
||||||
box-shadow: 0 2px 5px 0 rgba(217, 104, 48, 0.15)
|
|
||||||
}
|
|
||||||
|
|
||||||
.success-payment-message {
|
|
||||||
color: #13395E;
|
|
||||||
line-height: 1.4
|
|
||||||
}
|
|
||||||
|
|
||||||
.token {
|
|
||||||
color: #b35e14;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
font-family: monospace
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 31rem) {
|
|
||||||
.one-liner {
|
|
||||||
flex-direction: row
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-frame {
|
|
||||||
width: 318px;
|
|
||||||
margin-bottom: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#pay-button {
|
|
||||||
width: 175px;
|
|
||||||
margin-left: 8px
|
|
||||||
}
|
|
||||||
}</style>
|
|
||||||
|
|
||||||
<script src="https://cdn.checkout.com/js/framesv2.min.js"></script>
|
<script src="https://cdn.checkout.com/js/framesv2.min.js"></script>
|
||||||
@endsection
|
@endsection
|
||||||
|
@ -38,17 +38,6 @@ class CreditCardTest extends DuskTestCase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddingPaymentMethodShouldntBePossible()
|
|
||||||
{
|
|
||||||
$this->browse(function (Browser $browser) {
|
|
||||||
$browser
|
|
||||||
->visitRoute('client.payment_methods.index')
|
|
||||||
->press('Add Payment Method')
|
|
||||||
->clickLink('Credit Card')
|
|
||||||
->assertSee('Checkout.com can be can saved as payment method for future use, once you complete your first transaction. Don\'t forget to check "Store credit card details" during payment process.');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testPayWithNewCard()
|
public function testPayWithNewCard()
|
||||||
{
|
{
|
||||||
$this->browse(function (Browser $browser) {
|
$this->browse(function (Browser $browser) {
|
||||||
@ -117,4 +106,22 @@ class CreditCardTest extends DuskTestCase
|
|||||||
->assertSee('Payment method has been successfully removed.');
|
->assertSee('Payment method has been successfully removed.');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testAddingCreditCardStandalone()
|
||||||
|
{
|
||||||
|
$this->browse(function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->visitRoute('client.payment_methods.index')
|
||||||
|
->press('Add Payment Method')
|
||||||
|
->clickLink('Credit Card')
|
||||||
|
->withinFrame('iframe', function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->type('cardnumber', '4242424242424242')
|
||||||
|
->type('exp-date', '04/22')
|
||||||
|
->type('cvc', '100');
|
||||||
|
})
|
||||||
|
->press('#pay-button')
|
||||||
|
->waitForText('Details of payment method', 60);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
4
webpack.mix.js
vendored
4
webpack.mix.js
vendored
@ -114,6 +114,10 @@ mix.js("resources/js/app.js", "public/js")
|
|||||||
"resources/js/clients/payments/stripe-sepa.js",
|
"resources/js/clients/payments/stripe-sepa.js",
|
||||||
"public/js/clients/payments/stripe-sepa.js"
|
"public/js/clients/payments/stripe-sepa.js"
|
||||||
)
|
)
|
||||||
|
.js(
|
||||||
|
"resources/js/clients/payment_methods/authorize-checkout-card.js",
|
||||||
|
"public/js/clients/payment_methods/authorize-checkout-card.js"
|
||||||
|
)
|
||||||
|
|
||||||
mix.copyDirectory('node_modules/card-js/card-js.min.css', 'public/css/card-js.min.css');
|
mix.copyDirectory('node_modules/card-js/card-js.min.css', 'public/css/card-js.min.css');
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user