Merge branch 'v5-develop' of https://github.com/turbo124/invoiceninja into v5-develop

This commit is contained in:
David Bomba 2022-06-24 20:40:29 +10:00
commit d1c53cc6e1
26 changed files with 262653 additions and 258720 deletions

View File

@ -79,6 +79,7 @@ class BaseController extends Controller
'company.groups.documents', 'company.groups.documents',
'company.invoices.invitations.contact', 'company.invoices.invitations.contact',
'company.invoices.invitations.company', 'company.invoices.invitations.company',
'company.purchase_orders.invitations',
'company.invoices.documents', 'company.invoices.documents',
'company.products', 'company.products',
'company.products.documents', 'company.products.documents',

View File

@ -63,6 +63,8 @@ class Gateway extends StaticModel
$link = 'https://applications.sagepay.com/apply/2C02C252-0F8A-1B84-E10D-CF933EFCAA99'; $link = 'https://applications.sagepay.com/apply/2C02C252-0F8A-1B84-E10D-CF933EFCAA99';
} elseif ($this->id == 20 || $this->id == 56) { } elseif ($this->id == 20 || $this->id == 56) {
$link = 'https://dashboard.stripe.com/account/apikeys'; $link = 'https://dashboard.stripe.com/account/apikeys';
} elseif ($this->id == 59) {
$link = 'https://www.forte.net/';
} }
return $link; return $link;
@ -170,6 +172,12 @@ class Gateway extends StaticModel
GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']] // Razorpay GatewayType::HOSTED_PAGE => ['refund' => false, 'token_billing' => false, 'webhooks' => [' ']] // Razorpay
]; ];
break; break;
case 59:
return [
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], // Forte
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => [' ']],
];
break;
default: default:
return []; return [];
break; break;

View File

@ -0,0 +1,150 @@
<?php
/**
* 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://www.elastic.co/licensing/elastic-license
*/
namespace App\PaymentDrivers\Forte;
use App\Models\Payment;
use App\Models\GatewayType;
use App\Models\PaymentHash;
use App\Models\PaymentType;
use App\Http\Requests\Request;
use App\Utils\Traits\MakesHash;
use Illuminate\Support\Facades\Validator;
use App\PaymentDrivers\FortePaymentDriver;
class ACH
{
use MakesHash;
public $forte;
private $forte_base_uri="";
private $forte_api_access_id="";
private $forte_secure_key="";
private $forte_auth_organization_id="";
private $forte_organization_id="";
private $forte_location_id="";
public function __construct(FortePaymentDriver $forte)
{
$this->forte = $forte;
$this->forte_base_uri = "https://sandbox.forte.net/api/v3/";
if($this->forte->company_gateway->getConfigField('testMode') == false){
$this->forte_base_uri = "https://api.forte.net/v3/";
}
$this->forte_api_access_id = $this->forte->company_gateway->getConfigField('apiAccessId');
$this->forte_secure_key = $this->forte->company_gateway->getConfigField('secureKey');
$this->forte_auth_organization_id = $this->forte->company_gateway->getConfigField('authOrganizationId');
$this->forte_organization_id = $this->forte->company_gateway->getConfigField('organizationId');
$this->forte_location_id = $this->forte->company_gateway->getConfigField('locationId');
}
public function authorizeView(array $data)
{
return render('gateways.forte.ach.authorize', $data);
}
public function authorizeResponse(Request $request)
{
$payment_meta = new \stdClass;
$payment_meta->brand = (string)ctrans('texts.ach');
$payment_meta->last4 = (string) $request->last_4;
$payment_meta->exp_year = '-';
$payment_meta->type = GatewayType::BANK_TRANSFER;
$data = [
'payment_meta' => $payment_meta,
'token' => $request->one_time_token,
'payment_method_id' => $request->gateway_type_id,
];
$this->forte->storeGatewayToken($data);
return redirect()->route('client.payment_methods.index')->withSuccess('Payment Method added.');
}
public function paymentView(array $data)
{
$this->forte->payment_hash->data = array_merge((array) $this->forte->payment_hash->data, $data);
$this->forte->payment_hash->save();
$data['gateway'] = $this;
return render('gateways.forte.ach.pay', $data);
}
public function paymentResponse($request)
{
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
try {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $this->forte_base_uri.'organizations/'.$this->forte_organization_id.'/locations/'.$this->forte_location_id.'/transactions',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>'{
"action":"sale",
"authorization_amount": '.$payment_hash->data->total->amount_with_fee.',
"echeck":{
"sec_code":"PPD",
},
"billing_address":{
"first_name": "'.$this->forte->client->name.'",
"last_name": "'.$this->forte->client->name.'"
},
"echeck":{
"one_time_token":"'.$request->payment_token.'"
}
}',
CURLOPT_HTTPHEADER => array(
'X-Forte-Auth-Organization-Id: '.$this->forte_organization_id,
'Content-Type: application/json',
'Authorization: Basic '.base64_encode($this->forte_api_access_id.':'.$this->forte_secure_key),
'Cookie: visid_incap_621087=u18+3REYR/iISgzZxOF5s2ODW2IAAAAAQUIPAAAAAADuGqKgECQLS81FcSDrmhGe; nlbi_621087=YHngadhJ2VU+yr7/R1efXgAAAAD3mQyhqmnLls8PRu4iN58G; incap_ses_1136_621087=CVdrXUdhIlm9WJNDieLDD4QVXGIAAAAAvBwvkUcwhM0+OwvdPm2stg=='
),
));
$response = curl_exec($curl);
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
$response=json_decode($response);
} catch (\Throwable $th) {
throw $th;
}
if ($httpcode>299) {
$error = Validator::make([], []);
$error->getMessageBag()->add('gateway_error', $response->response->response_desc);
return redirect('client/invoices')->withErrors($error);
}
$data = [
'payment_method' => $request->payment_method_id,
'payment_type' => PaymentType::ACH,
'amount' => $payment_hash->data->amount_with_fee,
'transaction_reference' => $response->transaction_id,
'gateway_type_id' => GatewayType::BANK_TRANSFER,
];
$payment=$this->forte->createPayment($data, Payment::STATUS_COMPLETED);
return redirect('client/invoices')->withSuccess('Invoice paid.');
}
}

View File

@ -0,0 +1,160 @@
<?php
/**
* 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://www.elastic.co/licensing/elastic-license
*/
namespace App\PaymentDrivers\Forte;
use App\Models\Payment;
use App\Models\GatewayType;
use App\Models\PaymentHash;
use App\Models\PaymentType;
use App\Utils\Traits\MakesHash;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;
use App\PaymentDrivers\FortePaymentDriver;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
class CreditCard
{
use MakesHash;
public $forte;
private $forte_base_uri="";
private $forte_api_access_id="";
private $forte_secure_key="";
private $forte_auth_organization_id="";
private $forte_organization_id="";
private $forte_location_id="";
public function __construct(FortePaymentDriver $forte)
{
$this->forte = $forte;
$this->forte_base_uri = "https://sandbox.forte.net/api/v3/";
if($this->forte->company_gateway->getConfigField('testMode') == false){
$this->forte_base_uri = "https://api.forte.net/v3/";
}
$this->forte_api_access_id = $this->forte->company_gateway->getConfigField('apiAccessId');
$this->forte_secure_key = $this->forte->company_gateway->getConfigField('secureKey');
$this->forte_auth_organization_id = $this->forte->company_gateway->getConfigField('authOrganizationId');
$this->forte_organization_id = $this->forte->company_gateway->getConfigField('organizationId');
$this->forte_location_id = $this->forte->company_gateway->getConfigField('locationId');
}
public function authorizeView(array $data)
{
return render('gateways.forte.credit_card.authorize', $data);
}
public function authorizeResponse($request)
{
$payment_meta = new \stdClass;
$payment_meta->exp_month = (string) $request->expire_month;
$payment_meta->exp_year = (string) $request->expire_year;
$payment_meta->brand = (string) $request->card_type;
$payment_meta->last4 = (string) $request->last_4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$data = [
'payment_meta' => $payment_meta,
'token' => $request->one_time_token,
'payment_method_id' => $request->payment_method_id,
];
$this->forte->storeGatewayToken($data);
return redirect()->route('client.payment_methods.index')->withSuccess('Payment Method added.');
}
public function paymentView(array $data)
{
$this->forte->payment_hash->data = array_merge((array) $this->forte->payment_hash->data, $data);
$this->forte->payment_hash->save();
$data['gateway'] = $this;
return render('gateways.forte.credit_card.pay', $data);
}
public function paymentResponse(PaymentResponseRequest $request)
{
$payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
$amount_with_fee = $payment_hash->data->total->amount_with_fee;
$invoice_totals = $payment_hash->data->total->invoice_totals;
$fee_total = 0;
for ($i = ($invoice_totals * 100) ; $i < ($amount_with_fee * 100); $i++) {
$calculated_fee = ( 3 * $i) / 100;
$calculated_amount_with_fee = round(($i + $calculated_fee) / 100,2);
if ($calculated_amount_with_fee == $amount_with_fee) {
$fee_total = round($calculated_fee / 100,2);
$amount_with_fee = $calculated_amount_with_fee;
break;
}
}
try {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $this->forte_base_uri.'organizations/'.$this->forte_organization_id.'/locations/'.$this->forte_location_id.'/transactions',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>'{
"action":"sale",
"authorization_amount":'.$amount_with_fee.',
"service_fee_amount":'.$fee_total.',
"billing_address":{
"first_name":"'.$this->forte->client->name.'",
"last_name":"'.$this->forte->client->name.'"
},
"card":{
"one_time_token":"'.$request->payment_token.'"
}
}',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'X-Forte-Auth-Organization-Id: '.$this->forte_organization_id,
'Authorization: Basic '.base64_encode($this->forte_api_access_id.':'.$this->forte_secure_key)
),
));
$response = curl_exec($curl);
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
$response=json_decode($response);
} catch (\Throwable $th) {
throw $th;
}
if ($httpcode>299) {
$error = Validator::make([], []);
$error->getMessageBag()->add('gateway_error', $response->response->response_desc);
return redirect('client/invoices')->withErrors($error);
}
$data = [
'payment_method' => $request->payment_method_id,
'payment_type' => PaymentType::parseCardType(strtolower($request->card_brand)) ?: PaymentType::CREDIT_CARD_OTHER,
'amount' => $payment_hash->data->amount_with_fee,
'transaction_reference' => $response->transaction_id,
'gateway_type_id' => GatewayType::CREDIT_CARD,
];
$payment=$this->forte->createPayment($data, Payment::STATUS_COMPLETED);
return redirect('client/invoices')->withSuccess('Invoice paid.');
}
}

View File

@ -0,0 +1,90 @@
<?php
/**
* 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
*/
namespace App\PaymentDrivers;
use App\Models\SystemLog;
use App\Models\GatewayType;
use App\Utils\Traits\MakesHash;
use App\PaymentDrivers\Forte\ACH;
use App\PaymentDrivers\Forte\CreditCard;
class FortePaymentDriver extends BaseDriver
{
use MakesHash;
public $refundable = true; //does this gateway support refunds?
public $token_billing = true; //does this gateway support token billing?
public $can_authorise_credit_card = true; //does this gateway support authorizations?
public $gateway; //initialized gateway
public $payment_method; //initialized payment method
public static $methods = [
GatewayType::CREDIT_CARD => CreditCard::class,
GatewayType::BANK_TRANSFER => ACH::class,
];
/**
* Returns the gateway types.
*/
public function gatewayTypes(): array
{
$types = [];
$types[] = GatewayType::CREDIT_CARD;
$types[] = GatewayType::BANK_TRANSFER;
return $types;
}
const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model
public function setPaymentMethod($payment_method_id)
{
$class = self::$methods[$payment_method_id];
$this->payment_method = new $class($this);
return $this;
}
public function authorizeView(array $data)
{
return $this->payment_method->authorizeView($data); //this is your custom implementation from here
}
public function authorizeResponse($request)
{
return $this->payment_method->authorizeResponse($request); //this is your custom implementation from here
}
public function processPaymentView(array $data)
{
return $this->payment_method->paymentView($data); //this is your custom implementation from here
}
public function processPaymentResponse($request)
{
return $this->payment_method->paymentResponse($request); //this is your custom implementation from here
}
// public function refund(Payment $payment, $amount, $return_client_response = false)
// {
// return $this->payment_method->yourRefundImplementationHere(); //this is your custom implementation from here
// }
// public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
// {
// return $this->payment_method->yourTokenBillingImplmentation(); //this is your custom implementation from here
// }
}

View File

@ -121,7 +121,19 @@ class PaymentIntentWebhook implements ShouldQueue
nlog("payment intent"); nlog("payment intent");
nlog($this->stripe_request); nlog($this->stripe_request);
if(optional($this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']) && in_array('card', $this->stripe_request['object']['allowed_source_types'])) if(array_key_exists('allowed_source_types', $this->stripe_request['object']) && optional($this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']) && in_array('card', $this->stripe_request['object']['allowed_source_types']))
{
nlog("hash found");
$hash = $this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash'];
$payment_hash = PaymentHash::where('hash', $hash)->first();
$invoice = Invoice::with('client')->find($payment_hash->fee_invoice_id);
$client = $invoice->client;
$this->updateCreditCardPayment($payment_hash, $client);
}
elseif(array_key_exists('payment_method_types', $this->stripe_request['object']) && optional($this->stripe_request['object']['charges']['data'][0]['metadata']['payment_hash']) && in_array('card', $this->stripe_request['object']['payment_method_types']))
{ {
nlog("hash found"); nlog("hash found");

View File

@ -0,0 +1,50 @@
<?php
use App\Models\Gateway;
use App\Models\GatewayType;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class FortePaymentGateway extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$fields = new \stdClass;
$fields->testMode = false;
$fields->apiLoginId = "";
$fields->apiAccessId = "";
$fields->secureKey = "";
$fields->authOrganizationId = "";
$fields->organizationId = "";
$fields->locationId = "";
$forte = new Gateway;
$forte->id = 59;
$forte->name = 'Forte';
$forte->key = 'kivcvjexxvdiyqtj3mju5d6yhpeht2xs';
$forte->provider = 'Forte';
$forte->is_offsite = true;
$forte->fields = \json_encode($fields);
$forte->visible = 1;
$forte->site_url = 'https://www.forte.net/';
$forte->default_gateway_type_id = GatewayType::CREDIT_CARD;
$forte->save();
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -98,7 +98,7 @@ class PaymentLibrariesSeeder extends Seeder
Gateway::query()->update(['visible' => 0]); Gateway::query()->update(['visible' => 0]);
Gateway::whereIn('id', [1,3,7,11,15,20,39,46,55,50,57,52,58])->update(['visible' => 1]); Gateway::whereIn('id', [1,3,7,11,15,20,39,46,55,50,57,52,58,59])->update(['visible' => 1]);
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
Gateway::whereIn('id', [20])->update(['visible' => 0]); Gateway::whereIn('id', [20])->update(['visible' => 0]);

View File

@ -8,7 +8,7 @@ const RESOURCES = {
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900", "canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd", "canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba", "canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
"/": "30687e88a9f23c64baf0d15fc0ae2a5a", "/": "17a515c261fe3010e0533ce4573dca71",
"flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67", "flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67",
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35", "icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed", "icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
@ -39,7 +39,7 @@ const RESOURCES = {
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629", "assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56", "assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",
"assets/NOTICES": "9b6b63256d3a6491659b71127ee9f3b6", "assets/NOTICES": "9b6b63256d3a6491659b71127ee9f3b6",
"main.dart.js": "2f7859d1cf21aac7162b3a60ed31a00b" "main.dart.js": "c2902a32d34abff107d9e1e71c2858b2"
}; };
// The application shell files that are downloaded before a service worker can // The application shell files that are downloaded before a service worker can

View File

@ -0,0 +1,81 @@
/******/ (() => { // webpackBootstrap
var __webpack_exports__ = {};
/*!************************************************************!*\
!*** ./resources/js/clients/payments/forte-ach-payment.js ***!
\************************************************************/
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* 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
*/
var ForteAuthorizeACH = function ForteAuthorizeACH(apiLoginId) {
var _this = this;
_classCallCheck(this, ForteAuthorizeACH);
_defineProperty(this, "handleAuthorization", function () {
var account_number = document.getElementById('account-number').value;
var routing_number = document.getElementById('routing-number').value;
var data = {
api_login_id: _this.apiLoginId,
account_number: account_number,
routing_number: routing_number,
account_type: 'checking'
};
var payNowButton = document.getElementById('pay-now');
if (payNowButton) {
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
} // console.log(data);
forte.createToken(data).success(_this.successResponseHandler).error(_this.failedResponseHandler);
return false;
});
_defineProperty(this, "successResponseHandler", function (response) {
document.getElementById('payment_token').value = response.onetime_token;
document.getElementById('server_response').submit();
return false;
});
_defineProperty(this, "failedResponseHandler", function (response) {
var errors = '<div class="alert alert-failure mb-4"><ul><li>' + response.response_description + '</li></ul></div>';
document.getElementById('forte_errors').innerHTML = errors;
document.getElementById('pay-now').disabled = false;
document.querySelector('#pay-now > svg').classList.add('hidden');
document.querySelector('#pay-now > span').classList.remove('hidden');
return false;
});
_defineProperty(this, "handle", function () {
var payNowButton = document.getElementById('pay-now');
if (payNowButton) {
payNowButton.addEventListener('click', function (e) {
_this.handleAuthorization();
});
}
return _this;
});
this.apiLoginId = apiLoginId;
};
var apiLoginId = document.querySelector('meta[name="forte-api-login-id"]').content;
/** @handle */
new ForteAuthorizeACH(apiLoginId).handle();
/******/ })()
;

View File

@ -0,0 +1,669 @@
(() => {
function t(t) {
(this.elem = jQuery(t)),
(this.captureName =
!!this.elem.data('capture-name') &&
this.elem.data('capture-name')),
(this.iconColour =
!!this.elem.data('icon-colour') &&
this.elem.data('icon-colour')),
(this.stripe =
!!this.elem.data('stripe') && this.elem.data('stripe')),
this.stripe && (this.captureName = !1),
this.initCardNumberInput(),
this.initNameInput(),
this.initExpiryMonthInput(),
this.initExpiryYearInput(),
this.initCvcInput(),
this.elem.empty(),
this.setupCardNumberInput(),
this.setupNameInput(),
this.setupExpiryInput(),
this.setupCvcInput(),
this.iconColour && this.setIconColour(this.iconColour),
this.refreshCreditCardTypeIcon();
}
!(function (e) {
var r = {
init: function () {
return this.data('cardjs', new t(this)), this;
},
cardNumber: function () {
return this.data('cardjs').getCardNumber();
},
cardType: function () {
return this.data('cardjs').getCardType();
},
name: function () {
return this.data('cardjs').getName();
},
expiryMonth: function () {
return this.data('cardjs').getExpiryMonth();
},
expiryYear: function () {
return this.data('cardjs').getExpiryYear();
},
cvc: function () {
return this.data('cardjs').getCvc();
},
};
e.fn.CardJs = function (t) {
return r[t]
? r[t].apply(this, Array.prototype.slice.call(arguments, 1))
: 'object' != typeof t && t
? void e.error(
'Method ' + t + ' does not exist on jQuery.CardJs'
)
: r.init.apply(this, arguments);
};
})(jQuery),
$(function () {
$('.card-js').each(function (t, e) {
$(e).CardJs();
});
}),
(t.prototype.constructor = t),
(t.KEYS = {
0: 48,
9: 57,
NUMPAD_0: 96,
NUMPAD_9: 105,
DELETE: 46,
BACKSPACE: 8,
ARROW_LEFT: 37,
ARROW_RIGHT: 39,
ARROW_UP: 38,
ARROW_DOWN: 40,
HOME: 36,
END: 35,
TAB: 9,
A: 65,
X: 88,
C: 67,
V: 86,
}),
(t.CREDIT_CARD_NUMBER_DEFAULT_MASK = 'XXXX XXXX XXXX XXXX'),
(t.CREDIT_CARD_NUMBER_VISA_MASK = 'XXXX XXXX XXXX XXXX'),
(t.CREDIT_CARD_NUMBER_MASTERCARD_MASK = 'XXXX XXXX XXXX XXXX'),
(t.CREDIT_CARD_NUMBER_DISCOVER_MASK = 'XXXX XXXX XXXX XXXX'),
(t.CREDIT_CARD_NUMBER_JCB_MASK = 'XXXX XXXX XXXX XXXX'),
(t.CREDIT_CARD_NUMBER_AMEX_MASK = 'XXXX XXXXXX XXXXX'),
(t.CREDIT_CARD_NUMBER_DINERS_MASK = 'XXXX XXXX XXXX XX'),
(t.prototype.creditCardNumberMask = t.CREDIT_CARD_NUMBER_DEFAULT_MASK),
(t.CREDIT_CARD_NUMBER_PLACEHOLDER = 'Card number'),
(t.NAME_PLACEHOLDER = 'Name on card'),
(t.EXPIRY_MASK = 'XX / XXXX'),
(t.EXPIRY_PLACEHOLDER = 'MM / YYYY'),
(t.EXPIRY_USE_DROPDOWNS = !1),
(t.EXPIRY_NUMBER_OF_YEARS = 10),
(t.CVC_MASK_3 = 'XXX'),
(t.CVC_MASK_4 = 'XXXX'),
(t.CVC_PLACEHOLDER = 'CVC'),
(t.CREDIT_CARD_SVG =
'<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="3px" width="24px" height="17px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><g><path class="svg" d="M182.385,14.258c-2.553-2.553-5.621-3.829-9.205-3.829H42.821c-3.585,0-6.653,1.276-9.207,3.829c-2.553,2.553-3.829,5.621-3.829,9.206v99.071c0,3.585,1.276,6.654,3.829,9.207c2.554,2.553,5.622,3.829,9.207,3.829H173.18c3.584,0,6.652-1.276,9.205-3.829s3.83-5.622,3.83-9.207V23.464C186.215,19.879,184.938,16.811,182.385,14.258z M175.785,122.536c0,0.707-0.258,1.317-0.773,1.834c-0.516,0.515-1.127,0.772-1.832,0.772H42.821c-0.706,0-1.317-0.258-1.833-0.773c-0.516-0.518-0.774-1.127-0.774-1.834V73h135.571V122.536z M175.785,41.713H40.214v-18.25c0-0.706,0.257-1.316,0.774-1.833c0.516-0.515,1.127-0.773,1.833-0.773H173.18c0.705,0,1.316,0.257,1.832,0.773c0.516,0.517,0.773,1.127,0.773,1.833V41.713z"/><rect class="svg" x="50.643" y="104.285" width="20.857" height="10.429"/><rect class="svg" x="81.929" y="104.285" width="31.286" height="10.429"/></g></svg>'),
(t.LOCK_SVG =
'<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="3px" width="24px" height="17px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><path class="svg" d="M152.646,70.067c-1.521-1.521-3.367-2.281-5.541-2.281H144.5V52.142c0-9.994-3.585-18.575-10.754-25.745c-7.17-7.17-15.751-10.755-25.746-10.755s-18.577,3.585-25.746,10.755C75.084,33.567,71.5,42.148,71.5,52.142v15.644h-2.607c-2.172,0-4.019,0.76-5.54,2.281c-1.521,1.52-2.281,3.367-2.281,5.541v46.929c0,2.172,0.76,4.019,2.281,5.54c1.521,1.52,3.368,2.281,5.54,2.281h78.214c2.174,0,4.02-0.76,5.541-2.281c1.52-1.521,2.281-3.368,2.281-5.54V75.607C154.93,73.435,154.168,71.588,152.646,70.067z M128.857,67.786H87.143V52.142c0-5.757,2.037-10.673,6.111-14.746c4.074-4.074,8.989-6.11,14.747-6.11s10.673,2.036,14.746,6.11c4.073,4.073,6.11,8.989,6.11,14.746V67.786z"/></svg>'),
(t.CALENDAR_SVG =
'<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="4px" width="24px" height="16px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><path class="svg" d="M172.691,23.953c-2.062-2.064-4.508-3.096-7.332-3.096h-10.428v-7.822c0-3.584-1.277-6.653-3.83-9.206c-2.554-2.553-5.621-3.83-9.207-3.83h-5.213c-3.586,0-6.654,1.277-9.207,3.83c-2.554,2.553-3.83,5.622-3.83,9.206v7.822H92.359v-7.822c0-3.584-1.277-6.653-3.83-9.206c-2.553-2.553-5.622-3.83-9.207-3.83h-5.214c-3.585,0-6.654,1.277-9.207,3.83c-2.553,2.553-3.83,5.622-3.83,9.206v7.822H50.643c-2.825,0-5.269,1.032-7.333,3.096s-3.096,4.509-3.096,7.333v104.287c0,2.823,1.032,5.267,3.096,7.332c2.064,2.064,4.508,3.096,7.333,3.096h114.714c2.824,0,5.27-1.032,7.332-3.096c2.064-2.064,3.096-4.509,3.096-7.332V31.286C175.785,28.461,174.754,26.017,172.691,23.953z M134.073,13.036c0-0.761,0.243-1.386,0.731-1.874c0.488-0.488,1.113-0.733,1.875-0.733h5.213c0.762,0,1.385,0.244,1.875,0.733c0.488,0.489,0.732,1.114,0.732,1.874V36.5c0,0.761-0.244,1.385-0.732,1.874c-0.49,0.488-1.113,0.733-1.875,0.733h-5.213c-0.762,0-1.387-0.244-1.875-0.733s-0.731-1.113-0.731-1.874V13.036z M71.501,13.036c0-0.761,0.244-1.386,0.733-1.874c0.489-0.488,1.113-0.733,1.874-0.733h5.214c0.761,0,1.386,0.244,1.874,0.733c0.488,0.489,0.733,1.114,0.733,1.874V36.5c0,0.761-0.244,1.386-0.733,1.874c-0.489,0.488-1.113,0.733-1.874,0.733h-5.214c-0.761,0-1.386-0.244-1.874-0.733c-0.488-0.489-0.733-1.113-0.733-1.874V13.036z M165.357,135.572H50.643V52.143h114.714V135.572z"/></svg>'),
(t.USER_SVG =
'<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="4px" width="24px" height="16px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><g><path class="svg" d="M107.999,73c8.638,0,16.011-3.056,22.12-9.166c6.111-6.11,9.166-13.483,9.166-22.12c0-8.636-3.055-16.009-9.166-22.12c-6.11-6.11-13.484-9.165-22.12-9.165c-8.636,0-16.01,3.055-22.12,9.165c-6.111,6.111-9.166,13.484-9.166,22.12c0,8.637,3.055,16.01,9.166,22.12C91.99,69.944,99.363,73,107.999,73z"/><path class="svg" d="M165.07,106.037c-0.191-2.743-0.571-5.703-1.141-8.881c-0.57-3.178-1.291-6.124-2.16-8.84c-0.869-2.715-2.037-5.363-3.504-7.943c-1.466-2.58-3.15-4.78-5.052-6.6s-4.223-3.272-6.965-4.358c-2.744-1.086-5.772-1.63-9.085-1.63c-0.489,0-1.63,0.584-3.422,1.752s-3.815,2.472-6.069,3.911c-2.254,1.438-5.188,2.743-8.799,3.909c-3.612,1.168-7.237,1.752-10.877,1.752c-3.639,0-7.264-0.584-10.876-1.752c-3.611-1.166-6.545-2.471-8.799-3.909c-2.254-1.439-4.277-2.743-6.069-3.911c-1.793-1.168-2.933-1.752-3.422-1.752c-3.313,0-6.341,0.544-9.084,1.63s-5.065,2.539-6.966,4.358c-1.901,1.82-3.585,4.02-5.051,6.6s-2.634,5.229-3.503,7.943c-0.869,2.716-1.589,5.662-2.159,8.84c-0.571,3.178-0.951,6.137-1.141,8.881c-0.19,2.744-0.285,5.554-0.285,8.433c0,6.517,1.983,11.664,5.948,15.439c3.965,3.774,9.234,5.661,15.806,5.661h71.208c6.572,0,11.84-1.887,15.806-5.661c3.966-3.775,5.948-8.921,5.948-15.439C165.357,111.591,165.262,108.78,165.07,106.037z"/></g></svg>'),
(t.MAIL_SVG =
'<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"x="0px" y="4px" width="24px" height="16px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><path class="svg" d="M177.171,19.472c-2.553-2.553-5.622-3.829-9.206-3.829H48.036c-3.585,0-6.654,1.276-9.207,3.829C36.276,22.025,35,25.094,35,28.679v88.644c0,3.585,1.276,6.652,3.829,9.205c2.553,2.555,5.622,3.83,9.207,3.83h119.929c3.584,0,6.653-1.275,9.206-3.83c2.554-2.553,3.829-5.621,3.829-9.205V28.679C181,25.094,179.725,22.025,177.171,19.472zM170.57,117.321c0,0.706-0.258,1.317-0.774,1.833s-1.127,0.773-1.832,0.773H48.035c-0.706,0-1.317-0.257-1.833-0.773c-0.516-0.516-0.774-1.127-0.774-1.833V54.75c1.738,1.955,3.612,3.748,5.622,5.377c14.557,11.189,26.126,20.368,34.708,27.538c2.77,2.336,5.024,4.155,6.762,5.459s4.087,2.62,7.047,3.951s5.744,1.995,8.351,1.995H108h0.081c2.606,0,5.392-0.664,8.351-1.995c2.961-1.331,5.311-2.647,7.049-3.951c1.737-1.304,3.992-3.123,6.762-5.459c8.582-7.17,20.15-16.349,34.707-27.538c2.01-1.629,3.885-3.422,5.621-5.377V117.321z M170.57,30.797v0.896c0,3.204-1.262,6.776-3.787,10.713c-2.525,3.938-5.256,7.075-8.188,9.41c-10.484,8.257-21.373,16.865-32.672,25.827c-0.326,0.271-1.277,1.073-2.852,2.403c-1.574,1.331-2.824,2.351-3.748,3.056c-0.924,0.707-2.131,1.562-3.625,2.566s-2.865,1.752-4.114,2.24s-2.417,0.732-3.503,0.732H108h-0.082c-1.086,0-2.253-0.244-3.503-0.732c-1.249-0.488-2.621-1.236-4.114-2.24c-1.493-1.004-2.702-1.859-3.625-2.566c-0.923-0.705-2.173-1.725-3.748-3.056c-1.575-1.33-2.526-2.132-2.852-2.403c-11.297-8.962-22.187-17.57-32.67-25.827c-7.985-6.3-11.977-14.013-11.977-23.138c0-0.706,0.258-1.317,0.774-1.833c0.516-0.516,1.127-0.774,1.833-0.774h119.929c0.434,0.244,0.814,0.312,1.141,0.204c0.326-0.11,0.57,0.094,0.732,0.61c0.163,0.516,0.312,0.76,0.448,0.733c0.136-0.027,0.218,0.312,0.245,1.019c0.025,0.706,0.039,1.061,0.039,1.061V30.797z"/></svg>'),
(t.INFORMATION_SVG =
'<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="4px" width="24px" height="16px" viewBox="0 0 216 146" enable-background="new 0 0 216 146" xml:space="preserve"><g><path class="svg" d="M97.571,41.714h20.859c1.411,0,2.633-0.516,3.666-1.548c1.031-1.031,1.547-2.254,1.547-3.666V20.857c0-1.412-0.516-2.634-1.549-3.667c-1.031-1.031-2.254-1.548-3.666-1.548H97.571c-1.412,0-2.634,0.517-3.666,1.548c-1.032,1.032-1.548,2.255-1.548,3.667V36.5c0,1.412,0.516,2.635,1.548,3.666C94.937,41.198,96.159,41.714,97.571,41.714z"/><path class="svg" d="M132.523,111.048c-1.031-1.032-2.254-1.548-3.666-1.548h-5.215V62.571c0-1.412-0.516-2.634-1.547-3.666c-1.033-1.032-2.255-1.548-3.666-1.548H87.143c-1.412,0-2.634,0.516-3.666,1.548c-1.032,1.032-1.548,2.254-1.548,3.666V73c0,1.412,0.516,2.635,1.548,3.666c1.032,1.032,2.254,1.548,3.666,1.548h5.215V109.5h-5.215c-1.412,0-2.634,0.516-3.666,1.548c-1.032,1.032-1.548,2.254-1.548,3.666v10.429c0,1.412,0.516,2.635,1.548,3.668c1.032,1.03,2.254,1.547,3.666,1.547h41.714c1.412,0,2.634-0.517,3.666-1.547c1.031-1.033,1.547-2.256,1.547-3.668v-10.429C134.07,113.302,133.557,112.08,132.523,111.048z"/></g></svg>'),
(t.keyCodeFromEvent = function (t) {
return t.which || t.keyCode;
}),
(t.keyIsCommandFromEvent = function (t) {
return t.ctrlKey || t.metaKey;
}),
(t.keyIsNumber = function (e) {
return t.keyIsTopNumber(e) || t.keyIsKeypadNumber(e);
}),
(t.keyIsTopNumber = function (e) {
var r = t.keyCodeFromEvent(e);
return r >= t.KEYS[0] && r <= t.KEYS[9];
}),
(t.keyIsKeypadNumber = function (e) {
var r = t.keyCodeFromEvent(e);
return r >= t.KEYS.NUMPAD_0 && r <= t.KEYS.NUMPAD_9;
}),
(t.keyIsDelete = function (e) {
return t.keyCodeFromEvent(e) == t.KEYS.DELETE;
}),
(t.keyIsBackspace = function (e) {
return t.keyCodeFromEvent(e) == t.KEYS.BACKSPACE;
}),
(t.keyIsDeletion = function (e) {
return t.keyIsDelete(e) || t.keyIsBackspace(e);
}),
(t.keyIsArrow = function (e) {
var r = t.keyCodeFromEvent(e);
return r >= t.KEYS.ARROW_LEFT && r <= t.KEYS.ARROW_DOWN;
}),
(t.keyIsNavigation = function (e) {
var r = t.keyCodeFromEvent(e);
return r == t.KEYS.HOME || r == t.KEYS.END;
}),
(t.keyIsKeyboardCommand = function (e) {
var r = t.keyCodeFromEvent(e);
return (
t.keyIsCommandFromEvent(e) &&
(r == t.KEYS.A ||
r == t.KEYS.X ||
r == t.KEYS.C ||
r == t.KEYS.V)
);
}),
(t.keyIsTab = function (e) {
return t.keyCodeFromEvent(e) == t.KEYS.TAB;
}),
(t.copyAllElementAttributes = function (t, e) {
$.each(t[0].attributes, function (t, r) {
e.attr(r.nodeName, r.nodeValue);
});
}),
(t.numbersOnlyString = function (t) {
for (var e = '', r = 0; r < t.length; r++) {
var n = t.charAt(r);
!isNaN(parseInt(n)) && (e += n);
}
return e;
}),
(t.applyFormatMask = function (t, e) {
for (var r = '', n = 0, i = 0; i < e.length; i++) {
var a = e[i];
if ('X' == a) {
if (!t.charAt(n)) break;
(r += t.charAt(n)), n++;
} else r += a;
}
return r;
}),
(t.cardTypeFromNumber = function (t) {
if (((e = new RegExp('^30[0-5]')), null != t.match(e)))
return 'Diners - Carte Blanche';
if (((e = new RegExp('^(30[6-9]|36|38)')), null != t.match(e)))
return 'Diners';
if (((e = new RegExp('^35(2[89]|[3-8][0-9])')), null != t.match(e)))
return 'JCB';
if (((e = new RegExp('^3[47]')), null != t.match(e))) return 'AMEX';
if (
((e = new RegExp('^(4026|417500|4508|4844|491(3|7))')),
null != t.match(e))
)
return 'Visa Electron';
var e = new RegExp('^4');
return null != t.match(e)
? 'Visa'
: ((e = new RegExp('^5[1-5]')),
null != t.match(e)
? 'Mastercard'
: ((e = new RegExp(
'^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)'
)),
null != t.match(e) ? 'Discover' : ''));
}),
(t.caretStartPosition = function (t) {
return 'number' == typeof t.selectionStart && t.selectionStart;
}),
(t.caretEndPosition = function (t) {
return 'number' == typeof t.selectionEnd && t.selectionEnd;
}),
(t.setCaretPosition = function (t, e) {
if (null != t)
if (t.createTextRange) {
var r = t.createTextRange();
r.move('character', e), r.select();
} else
t.selectionStart
? (t.focus(), t.setSelectionRange(e, e))
: t.focus();
}),
(t.normaliseCaretPosition = function (t, e) {
var r = 0;
if (0 > e || e > t.length) return 0;
for (var n = 0; n < t.length; n++) {
if (n == e) return r;
'X' == t[n] && r++;
}
return r;
}),
(t.denormaliseCaretPosition = function (t, e) {
var r = 0;
if (0 > e || e > t.length) return 0;
for (var n = 0; n < t.length; n++) {
if (r == e) return n;
'X' == t[n] && r++;
}
return t.length;
}),
(t.filterNumberOnlyKey = function (e) {
var r = t.keyIsNumber(e),
n = t.keyIsDeletion(e),
i = t.keyIsArrow(e),
a = t.keyIsNavigation(e),
s = t.keyIsKeyboardCommand(e),
p = t.keyIsTab(e);
r || n || i || a || s || p || e.preventDefault();
}),
(t.digitFromKeyCode = function (e) {
return e >= t.KEYS[0] && e <= t.KEYS[9]
? e - t.KEYS[0]
: e >= t.KEYS.NUMPAD_0 && e <= t.KEYS.NUMPAD_9
? e - t.KEYS.NUMPAD_0
: null;
}),
(t.handleMaskedNumberInputKey = function (e, r) {
t.filterNumberOnlyKey(e);
var n = e.which || e.keyCode,
i = e.target,
a = t.caretStartPosition(i),
s = t.caretEndPosition(i),
p = t.normaliseCaretPosition(r, a),
c = t.normaliseCaretPosition(r, s),
o = a,
u = t.keyIsNumber(e),
h = t.keyIsDelete(e),
d = t.keyIsBackspace(e);
if (u || h || d) {
e.preventDefault();
var l = $(i).val(),
y = t.numbersOnlyString(l),
m = t.digitFromKeyCode(n),
C = c > p;
C && (y = y.slice(0, p) + y.slice(c)),
a != r.length &&
(u &&
l.length <= r.length &&
((y = y.slice(0, p) + m + y.slice(p)),
(o = Math.max(
t.denormaliseCaretPosition(r, p + 1),
t.denormaliseCaretPosition(r, p + 2) - 1
))),
h && (y = y.slice(0, p) + y.slice(p + 1))),
0 != a &&
d &&
!C &&
((y = y.slice(0, p - 1) + y.slice(p)),
(o = t.denormaliseCaretPosition(r, p - 1))),
$(i).val(t.applyFormatMask(y, r)),
t.setCaretPosition(i, o);
}
}),
(t.handleCreditCardNumberKey = function (e, r) {
t.handleMaskedNumberInputKey(e, r);
}),
(t.handleCreditCardNumberChange = function (t) {}),
(t.handleExpiryKey = function (e) {
t.handleMaskedNumberInputKey(e, t.EXPIRY_MASK);
}),
(t.prototype.getCardNumber = function () {
return this.cardNumberInput.val();
}),
(t.prototype.getCardType = function () {
return t.cardTypeFromNumber(this.getCardNumber());
}),
(t.prototype.getName = function () {
return this.nameInput.val();
}),
(t.prototype.getExpiryMonth = function () {
return this.expiryMonthInput.val();
}),
(t.prototype.getExpiryYear = function () {
return this.expiryYearInput.val();
}),
(t.prototype.getCvc = function () {
return this.cvcInput.val();
}),
(t.prototype.setIconColour = function (t) {
this.elem.find('.icon .svg').css({ fill: t });
}),
(t.prototype.setIconColour = function (t) {
this.elem.find('.icon .svg').css({ fill: t });
}),
(t.prototype.refreshCreditCardTypeIcon = function () {
this.setCardTypeIconFromNumber(
t.numbersOnlyString(this.cardNumberInput.val())
);
}),
(t.prototype.clearCardTypeIcon = function () {
this.elem
.find('.card-number-wrapper .card-type-icon')
.removeClass('show');
}),
(t.prototype.setCardTypeIconAsVisa = function () {
this.elem
.find('.card-number-wrapper .card-type-icon')
.attr('class', 'card-type-icon show visa');
}),
(t.prototype.setCardTypeIconAsMasterCard = function () {
this.elem
.find('.card-number-wrapper .card-type-icon')
.attr('class', 'card-type-icon show master-card');
}),
(t.prototype.setCardTypeIconAsAmericanExpress = function () {
this.elem
.find('.card-number-wrapper .card-type-icon')
.attr('class', 'card-type-icon show american-express');
}),
(t.prototype.setCardTypeIconAsDiscover = function () {
this.elem
.find('.card-number-wrapper .card-type-icon')
.attr('class', 'card-type-icon show discover');
}),
(t.prototype.setCardTypeIconAsDiners = function () {
this.elem
.find('.card-number-wrapper .card-type-icon')
.attr('class', 'card-type-icon show diners');
}),
(t.prototype.setCardTypeIconAsJcb = function () {
this.elem
.find('.card-number-wrapper .card-type-icon')
.attr('class', 'card-type-icon show jcb');
}),
(t.prototype.setCardTypeIconFromNumber = function (e) {
switch (t.cardTypeFromNumber(e)) {
case 'Visa Electron':
case 'Visa':
this.setCardTypeAsVisa();
break;
case 'Mastercard':
this.setCardTypeAsMasterCard();
break;
case 'AMEX':
this.setCardTypeAsAmericanExpress();
break;
case 'Discover':
this.setCardTypeAsDiscover();
break;
case 'Diners - Carte Blanche':
case 'Diners':
this.setCardTypeAsDiners();
break;
case 'JCB':
this.setCardTypeAsJcb();
break;
default:
this.clearCardType();
}
}),
(t.prototype.setCardMask = function (t) {
(this.creditCardNumberMask = t),
this.cardNumberInput.attr('maxlength', t.length);
}),
(t.prototype.setCvc3 = function () {
this.cvcInput.attr('maxlength', t.CVC_MASK_3.length);
}),
(t.prototype.setCvc4 = function () {
this.cvcInput.attr('maxlength', t.CVC_MASK_4.length);
}),
(t.prototype.clearCardType = function () {
this.clearCardTypeIcon(),
this.setCardMask(t.CREDIT_CARD_NUMBER_DEFAULT_MASK),
this.setCvc3();
}),
(t.prototype.setCardTypeAsVisa = function () {
this.setCardTypeIconAsVisa(),
this.setCardMask(t.CREDIT_CARD_NUMBER_VISA_MASK),
this.setCvc3();
}),
(t.prototype.setCardTypeAsMasterCard = function () {
this.setCardTypeIconAsMasterCard(),
this.setCardMask(t.CREDIT_CARD_NUMBER_MASTERCARD_MASK),
this.setCvc3();
}),
(t.prototype.setCardTypeAsAmericanExpress = function () {
this.setCardTypeIconAsAmericanExpress(),
this.setCardMask(t.CREDIT_CARD_NUMBER_AMEX_MASK),
this.setCvc4();
}),
(t.prototype.setCardTypeAsDiscover = function () {
this.setCardTypeIconAsDiscover(),
this.setCardMask(t.CREDIT_CARD_NUMBER_DISCOVER_MASK),
this.setCvc3();
}),
(t.prototype.setCardTypeAsDiners = function () {
this.setCardTypeIconAsDiners(),
this.setCardMask(t.CREDIT_CARD_NUMBER_DINERS_MASK),
this.setCvc3();
}),
(t.prototype.setCardTypeAsJcb = function () {
this.setCardTypeIconAsJcb(),
this.setCardMask(t.CREDIT_CARD_NUMBER_JCB_MASK),
this.setCvc3();
}),
(t.prototype.initCardNumberInput = function () {
var e = this;
(this.cardNumberInput = this.elem.find('.card-number')),
this.cardNumberInput[0]
? this.cardNumberInput.detach()
: (this.cardNumberInput = $(
"<input class='card-number' />"
)),
this.cardNumberInput.attr('type', 'tel'),
this.cardNumberInput.attr('placeholder') ||
this.cardNumberInput.attr(
'placeholder',
t.CREDIT_CARD_NUMBER_PLACEHOLDER
),
this.cardNumberInput.attr(
'maxlength',
this.creditCardNumberMask.length
),
this.cardNumberInput.attr('x-autocompletetype', 'cc-number'),
this.cardNumberInput.attr('autocompletetype', 'cc-number'),
this.cardNumberInput.attr('autocorrect', 'off'),
this.cardNumberInput.attr('spellcheck', 'off'),
this.cardNumberInput.attr('autocapitalize', 'off'),
this.cardNumberInput.keydown(function (r) {
t.handleCreditCardNumberKey(r, e.creditCardNumberMask);
}),
this.cardNumberInput.keyup(function (t) {
e.refreshCreditCardTypeIcon();
}),
this.cardNumberInput.change(t.handleCreditCardNumberChange);
}),
(t.prototype.initNameInput = function () {
(this.nameInput = this.elem.find('.name')),
this.nameInput[0]
? ((this.captureName = !0), this.nameInput.detach())
: (this.nameInput = $("<input class='name' />")),
this.nameInput.attr('placeholder') ||
this.nameInput.attr('placeholder', t.NAME_PLACEHOLDER);
}),
(t.prototype.initExpiryMonthInput = function () {
(this.expiryMonthInput = this.elem.find('.expiry-month')),
this.expiryMonthInput[0]
? this.expiryMonthInput.detach()
: (this.expiryMonthInput = $(
"<input class='expiry-month' />"
));
}),
(t.prototype.initExpiryYearInput = function () {
(this.expiryYearInput = this.elem.find('.expiry-year')),
this.expiryYearInput[0]
? this.expiryYearInput.detach()
: (this.expiryYearInput = $(
"<input class='expiry-year' name='expiry-year' />"
));
}),
(t.prototype.initCvcInput = function () {
(this.cvcInput = this.elem.find('.cvc')),
this.cvcInput[0]
? this.cvcInput.detach()
: (this.cvcInput = $("<input class='cvc' />")),
this.cvcInput.attr('type', 'tel'),
this.cvcInput.attr('placeholder') ||
this.cvcInput.attr('placeholder', t.CVC_PLACEHOLDER),
this.cvcInput.attr('maxlength', t.CVC_MASK_3.length),
this.cvcInput.attr('x-autocompletetype', 'cc-csc'),
this.cvcInput.attr('autocompletetype', 'cc-csc'),
this.cvcInput.attr('autocorrect', 'off'),
this.cvcInput.attr('spellcheck', 'off'),
this.cvcInput.attr('autocapitalize', 'off'),
this.cvcInput.keydown(t.filterNumberOnlyKey);
}),
(t.prototype.setupCardNumberInput = function () {
this.stripe && this.cardNumberInput.attr('data-stripe', 'number'),
this.elem.append("<div class='card-number-wrapper'></div>");
var e = this.elem.find('.card-number-wrapper');
e.append(this.cardNumberInput),
e.append("<div class='card-type-icon'></div>"),
e.append("<div class='icon'></div>"),
e.find('.icon').append(t.CREDIT_CARD_SVG);
}),
(t.prototype.setupNameInput = function () {
if (this.captureName) {
this.elem.append("<div class='name-wrapper'></div>");
var e = this.elem.find('.name-wrapper');
e.append(this.nameInput),
e.append("<div class='icon'></div>"),
e.find('.icon').append(t.USER_SVG);
}
}),
(t.prototype.setupExpiryInput = function () {
this.elem.append(
"<div class='expiry-container'><div class='expiry-wrapper'></div></div>"
);
var e,
r = this.elem.find('.expiry-wrapper');
if (this.EXPIRY_USE_DROPDOWNS) {
e = $('<div></div>');
var n = $(
"<select><option value='any' selected='' hidden=''>MM</option><option value='1'>01</option><option value='2'>02</option><option value='3'>03</option><option value='4'>04</option><option value='5'>05</option><option value='6'>06</option><option value='7'>07</option><option value='8'>08</option><option value='9'>09</option><option value='10'>10</option><option value='11'>11</option><option value='12'>12</option></select>"
),
i = this.expiryMonthInput;
t.copyAllElementAttributes(i, n),
this.expiryMonthInput.remove(),
(this.expiryMonthInput = n);
for (
var a = $(
"<select><option value='any' selected='' hidden=''>YY</option></select>"
),
s = parseInt(
new Date().getFullYear().toString().substring(2, 4)
),
p = 0;
p < t.EXPIRY_NUMBER_OF_YEARS;
p++
)
a.append("<option value='" + s + "'>" + s + '</option>'),
(s = (s + 1) % 100);
var c = this.expiryYearInput;
t.copyAllElementAttributes(c, a),
this.expiryYearInput.remove(),
(this.expiryYearInput = a),
e.append(this.expiryMonthInput),
e.append(this.expiryYearInput);
} else {
(e = $('<div></div>')),
(this.expiryMonthInput = $(
"<input type='hidden' name='expiry-month' />"
)),
(this.expiryYearInput = $(
"<input type='hidden' name='expiry-year' />"
)),
this.stripe &&
(this.expiryMonthInput.attr('data-stripe', 'exp-month'),
this.expiryYearInput.attr('data-stripe', 'exp-year')),
(this.expiryMonthYearInput = $("<input class='expiry' />")),
this.expiryMonthYearInput.attr('type', 'tel'),
this.expiryMonthYearInput.attr('placeholder') ||
this.expiryMonthYearInput.attr(
'placeholder',
t.EXPIRY_PLACEHOLDER
),
this.expiryMonthYearInput.attr(
'maxlength',
t.EXPIRY_MASK.length
),
this.expiryMonthYearInput.attr(
'x-autocompletetype',
'cc-exp'
),
this.expiryMonthYearInput.attr(
'autocompletetype',
'cc-exp'
),
this.expiryMonthYearInput.attr('autocorrect', 'off'),
this.expiryMonthYearInput.attr('spellcheck', 'off'),
this.expiryMonthYearInput.attr('autocapitalize', 'off');
var o = this;
this.expiryMonthYearInput.keydown(function (e) {
t.handleExpiryKey(e);
var r = o.expiryMonthYearInput.val();
1 == r.length &&
parseInt(r) > 1 &&
t.keyIsNumber(e) &&
o.expiryMonthYearInput.val(
t.applyFormatMask('0' + r, t.EXPIRY_MASK)
),
o.EXPIRY_USE_DROPDOWNS ||
null == o.expiryMonthYearInput ||
(o.expiryMonthInput.val(o.expiryMonth()),
o.expiryYearInput.val(
9 == r.length ? r.substr(5, 4) : null
));
}),
this.expiryMonthYearInput.blur(function (t) {
o.refreshExpiryMonthValidation();
}),
e.append(this.expiryMonthYearInput),
e.append(this.expiryMonthInput),
e.append(this.expiryYearInput);
}
r.append(e),
r.append("<div class='icon'></div>"),
r.find('.icon').append(t.CALENDAR_SVG);
}),
(t.prototype.setupCvcInput = function () {
this.stripe && this.cvcInput.attr('data-stripe', 'cvc'),
this.elem.append(
"<div class='cvc-container'><div class='cvc-wrapper'></div></div>"
);
var e = this.elem.find('.cvc-wrapper');
e.append(this.cvcInput),
e.append("<div class='icon'></div>"),
e.find('.icon').append(t.LOCK_SVG);
}),
(t.prototype.expiryMonth = function () {
if (
!this.EXPIRY_USE_DROPDOWNS &&
null != this.expiryMonthYearInput
) {
var t = this.expiryMonthYearInput.val();
return t.length >= 2 ? parseInt(t.substr(0, 2)) : null;
}
return null;
}),
(t.isValidMonth = function (t) {
return t >= 1 && 12 >= t;
}),
(t.isExpiryValid = function (e, r) {
var n = new Date(),
i = n.getMonth() + 1,
a = '' + n.getFullYear();
return (
2 == ('' + r).length && (r = a.substring(0, 2) + '' + r),
(i = parseInt(i)),
(a = parseInt(a)),
(e = parseInt(e)),
(r = parseInt(r)),
t.isValidMonth(e) && (r > a || (r == a && e >= i))
);
}),
(t.prototype.refreshExpiryMonthValidation = function () {
t.isExpiryValid(this.getExpiryMonth(), this.getExpiryYear())
? this.setExpiryMonthAsValid()
: this.setExpiryMonthAsInvalid();
}),
(t.prototype.setExpiryMonthAsValid = function () {
this.EXPIRY_USE_DROPDOWNS ||
this.expiryMonthYearInput.parent().removeClass('has-error');
}),
(t.prototype.setExpiryMonthAsInvalid = function () {
this.EXPIRY_USE_DROPDOWNS ||
this.expiryMonthYearInput.parent().addClass('has-error');
});
})();

View File

@ -0,0 +1,82 @@
/******/ (() => { // webpackBootstrap
var __webpack_exports__ = {};
/*!********************************************************************!*\
!*** ./resources/js/clients/payments/forte-credit-card-payment.js ***!
\********************************************************************/
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* 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
*/
var ForteAuthorizeCard = function ForteAuthorizeCard(apiLoginId) {
var _this = this;
_classCallCheck(this, ForteAuthorizeCard);
_defineProperty(this, "handleAuthorization", function () {
var myCard = $('#my-card');
var data = {
api_login_id: _this.apiLoginId,
card_number: myCard.CardJs('cardNumber').replace(/[^\d]/g, ''),
expire_year: myCard.CardJs('expiryYear').replace(/[^\d]/g, ''),
expire_month: myCard.CardJs('expiryMonth').replace(/[^\d]/g, ''),
cvv: document.getElementById('cvv').value.replace(/[^\d]/g, '')
};
var payNowButton = document.getElementById('pay-now');
if (payNowButton) {
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
}
forte.createToken(data).success(_this.successResponseHandler).error(_this.failedResponseHandler);
return false;
});
_defineProperty(this, "successResponseHandler", function (response) {
document.getElementById('payment_token').value = response.onetime_token;
document.getElementById('card_brand').value = response.card_type;
document.getElementById('server_response').submit();
return false;
});
_defineProperty(this, "failedResponseHandler", function (response) {
var errors = '<div class="alert alert-failure mb-4"><ul><li>' + response.response_description + '</li></ul></div>';
document.getElementById('forte_errors').innerHTML = errors;
document.getElementById('pay-now').disabled = false;
document.querySelector('#pay-now > svg').classList.add('hidden');
document.querySelector('#pay-now > span').classList.remove('hidden');
return false;
});
_defineProperty(this, "handle", function () {
var payNowButton = document.getElementById('pay-now');
if (payNowButton) {
payNowButton.addEventListener('click', function (e) {
_this.handleAuthorization();
});
}
return _this;
});
this.apiLoginId = apiLoginId;
this.cardHolderName = document.getElementById('cardholder_name');
};
var apiLoginId = document.querySelector('meta[name="forte-api-login-id"]').content;
/** @handle */
new ForteAuthorizeCard(apiLoginId).handle();
/******/ })()
;

255929
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

250223
public/main.foss.dart.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,81 @@
/**
* 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 ForteAuthorizeACH {
constructor(apiLoginId) {
this.apiLoginId = apiLoginId;
}
handleAuthorization = () => {
var account_number = document.getElementById('account-number').value;
var routing_number = document.getElementById('routing-number').value;
var data = {
api_login_id: this.apiLoginId,
account_number: account_number,
routing_number: routing_number,
account_type: 'checking',
};
let payNowButton = document.getElementById('pay-now');
if (payNowButton) {
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
}
// console.log(data);
forte
.createToken(data)
.success(this.successResponseHandler)
.error(this.failedResponseHandler);
return false;
};
successResponseHandler = (response) => {
document.getElementById('payment_token').value = response.onetime_token;
document.getElementById('server_response').submit();
return false;
};
failedResponseHandler = (response) => {
var errors =
'<div class="alert alert-failure mb-4"><ul><li>' +
response.response_description +
'</li></ul></div>';
document.getElementById('forte_errors').innerHTML = errors;
document.getElementById('pay-now').disabled = false;
document.querySelector('#pay-now > svg').classList.add('hidden');
document.querySelector('#pay-now > span').classList.remove('hidden');
return false;
};
handle = () => {
let payNowButton = document.getElementById('pay-now');
if (payNowButton) {
payNowButton.addEventListener('click', (e) => {
this.handleAuthorization();
});
}
return this;
};
}
const apiLoginId = document.querySelector(
'meta[name="forte-api-login-id"]'
).content;
/** @handle */
new ForteAuthorizeACH(apiLoginId).handle();

View File

@ -0,0 +1,83 @@
/**
* 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 ForteAuthorizeCard {
constructor(apiLoginId) {
this.apiLoginId = apiLoginId;
this.cardHolderName = document.getElementById('cardholder_name');
}
handleAuthorization = () => {
var myCard = $('#my-card');
var data = {
api_login_id: this.apiLoginId,
card_number: myCard.CardJs('cardNumber').replace(/[^\d]/g, ''),
expire_year: myCard.CardJs('expiryYear').replace(/[^\d]/g, ''),
expire_month: myCard.CardJs('expiryMonth').replace(/[^\d]/g, ''),
cvv: document.getElementById('cvv').value.replace(/[^\d]/g, ''),
};
let payNowButton = document.getElementById('pay-now');
if (payNowButton) {
document.getElementById('pay-now').disabled = true;
document.querySelector('#pay-now > svg').classList.remove('hidden');
document.querySelector('#pay-now > span').classList.add('hidden');
}
forte
.createToken(data)
.success(this.successResponseHandler)
.error(this.failedResponseHandler);
return false;
};
successResponseHandler = (response) => {
document.getElementById('payment_token').value = response.onetime_token;
document.getElementById('card_brand').value = response.card_type;
document.getElementById('server_response').submit();
return false;
};
failedResponseHandler = (response) => {
var errors =
'<div class="alert alert-failure mb-4"><ul><li>' +
response.response_description +
'</li></ul></div>';
document.getElementById('forte_errors').innerHTML = errors;
document.getElementById('pay-now').disabled = false;
document.querySelector('#pay-now > svg').classList.add('hidden');
document.querySelector('#pay-now > span').classList.remove('hidden');
return false;
};
handle = () => {
let payNowButton = document.getElementById('pay-now');
if (payNowButton) {
payNowButton.addEventListener('click', (e) => {
this.handleAuthorization();
});
}
return this;
};
}
const apiLoginId = document.querySelector(
'meta[name="forte-api-login-id"]'
).content;
/** @handle */
new ForteAuthorizeCard(apiLoginId).handle();

View File

@ -0,0 +1,131 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'Bank Details', 'card_title' => 'Bank Details'])
@section('gateway_head')
@if($gateway->getConfigField('testMode'))
<script type="text/javascript" src="https://sandbox.forte.net/api/js/v1"></script>
@else
<script type="text/javascript" src="https://api.forte.net/js/v1"></script>
@endif
@endsection
@section('gateway_content')
@if(session()->has('ach_error'))
<div class="alert alert-failure mb-4">
<p>{{ session('ach_error') }}</p>
</div>
@endif
@if(Session::has('error'))
<div class="alert alert-failure mb-4" id="errors">{{ Session::get('error') }}</div>
@endif
<div id="forte_errors"></div>
@if ($errors->any())
<div class="alert alert-failure mb-4">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::BANK_TRANSFER]) }}" method="post" id="server_response">
@csrf
<input type="hidden" name="gateway_type_id" value="2">
<input type="hidden" name="gateway_response" id="gateway_response">
<input type="hidden" name="is_default" id="is_default">
<input type="hidden" name="last_4" id="last_4">
<input type="hidden" name="one_time_token" id="one_time_token">
<div class="alert alert-failure mb-4" hidden id="errors"></div>
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_type')])
<span class="flex items-center mr-4">
<input class="form-radio mr-2" type="radio" value="individual" name="account-holder-type" checked>
<span>{{ __('texts.individual_account') }}</span>
</span>
<span class="flex items-center">
<input class="form-radio mr-2" type="radio" value="company" name="account-holder-type">
<span>{{ __('texts.company_account') }}</span>
</span>
@endcomponent
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_name')])
<input class="input w-full" id="account-holder-name" type="text" name="account_holder_name" placeholder="{{ ctrans('texts.name') }}" required>
@endcomponent
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.country')])
<select name="countries" id="country" name="country" class="form-select input w-full" required>
@foreach($countries as $country)
<option value="{{ $country->iso_3166_2 }}" {{$country->iso_3166_2 == 'US' ? "selected" : ""}}>{{ $country->iso_3166_2 }} ({{ $country->name }})</option>
@endforeach
</select>
@endcomponent
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.currency')])
<select name="currencies" id="currency" name="currency" class="form-select input w-full">
@foreach($currencies as $currency)
<option value="{{ $currency->code }}" {{$currency->code == 'USD' ? "selected" : ""}}>{{ $currency->code }} ({{ $currency->name }})</option>
@endforeach
</select>
@endcomponent
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.routing_number')])
<input class="input w-full" id="routing-number" type="text" required>
@endcomponent
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_number')])
<input class="input w-full" id="account-number" type="text" required>
@endcomponent
@component('portal.ninja2020.components.general.card-element-single')
<input type="checkbox" class="form-checkbox mr-1" name="accept_terms" id="accept-terms" required>
<label for="accept-terms" class="cursor-pointer">{{ ctrans('texts.ach_authorization', ['company' => auth()->user()->company->present()->name, 'email' => auth('contact')->user()->client->company->settings->email]) }}</label>
@endcomponent
<div class="bg-white px-4 py-5 flex justify-end">
<button type="button"
onclick="submitACH()"
class="button button-primary bg-primary {{ $class ?? '' }}">
<svg class="animate-spin h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span>{{ $slot ?? ctrans('texts.add_payment_method') }}</span>
</button>
<input type="submit" style="display: none" id="form_btn">
</div>
</form>
@endsection
@section('gateway_footer')
<script>
function onTokenCreated(params) {
document.getElementById('one_time_token').value=params.onetime_token;
document.getElementById('last_4').value=params.last_4;
let button = document.querySelector("#form_btn");
button.click();
}
function onTokenFailed(params) {
var errors = '<div class="alert alert-failure mb-4"><ul><li>'+ params.response_description +'</li></ul></div>';
document.getElementById("forte_errors").innerHTML = errors;
}
function submitACH(){
var account_number=document.getElementById('account-number').value;
var routing_number=document.getElementById('routing-number').value;
var data = {
api_login_id: '{{$gateway->getConfigField("apiLoginId")}}',
account_number: account_number,
routing_number: routing_number,
account_type: "checking",
}
forte.createToken(data)
.success(onTokenCreated)
.error(onTokenFailed);
return false;
}
</script>
@endsection

View File

@ -0,0 +1,53 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'Bank Transfer', 'card_title' => 'Bank Transfer'])
@section('gateway_head')
<meta name="forte-api-login-id" content="{{$gateway->forte->company_gateway->getConfigField("apiLoginId")}}">
@endsection
@section('gateway_content')
<form action="{{ route('client.payments.response') }}" method="post" id="server_response">
@csrf
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
<input type="hidden" name="company_gateway_id" value="{{ $gateway->forte->company_gateway->id }}">
<input type="hidden" name="payment_method_id" value="{{$payment_method_id}}">
<input type="hidden" name="gateway_response" id="gateway_response">
<input type="hidden" name="dataValue" id="dataValue"/>
<input type="hidden" name="dataDescriptor" id="dataDescriptor"/>
<input type="hidden" name="token" id="token"/>
<input type="hidden" name="store_card" id="store_card"/>
<input type="submit" style="display: none" id="form_btn">
</form>
<div id="forte_errors"></div>
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')])
Bank Transfer
@endcomponent
@include('portal.ninja2020.gateways.includes.payment_details')
@component('portal.ninja2020.components.general.card-element', ['title' => 'Pay with Bank Transfer'])
<input type="hidden" name="payment_token" id="payment_token">
<div class="bg-white px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
style="display: flex!important; justify-content: center!important;">
<input class="input w-full" id="routing-number" type="text" placeholder="{{ctrans('texts.routing_number')}}" required>
</div>
<div class="bg-white px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
style="display: flex!important; justify-content: center!important;">
<input class="input w-full" id="account-number" type="text" placeholder="{{ctrans('texts.account_number')}}" required>
</div>
@endcomponent
@include('portal.ninja2020.gateways.includes.pay_now')
@endsection
@section('gateway_footer')
@if($gateway->forte->company_gateway->getConfigField('testMode'))
<script type="text/javascript" src="https://sandbox.forte.net/api/js/v1"></script>
@else
<script type="text/javascript" src="https://api.forte.net/js/v1"></script>
@endif
<script src="{{ asset('js/clients/payments/forte-ach-payment.js') }}"></script>
@endsection

View File

@ -0,0 +1,122 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' => ctrans('texts.credit_card')])
@section('gateway_head')
<meta name="year-invalid" content="{{ ctrans('texts.year_invalid') }}">
<meta name="month-invalid" content="{{ ctrans('texts.month_invalid') }}">
<meta name="credit-card-invalid" content="{{ ctrans('texts.credit_card_invalid') }}">
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="{{ asset('js/clients/payments/forte-card-js.min.js') }}"></script>
<link href="{{ asset('css/card-js.min.css') }}" rel="stylesheet" type="text/css">
@if($gateway->getConfigField('testMode'))
<script type="text/javascript" src="https://sandbox.forte.net/api/js/v1"></script>
@else
<script type="text/javascript" src="https://api.forte.net/js/v1"></script>
@endif
@endsection
@section('gateway_content')
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::CREDIT_CARD]) }}"
method="post" id="server_response">
@csrf
<input type="hidden" name="payment_method_id" value="1">
<input type="hidden" name="one_time_token" id="one_time_token">
<input type="hidden" name="card_type" id="card_type">
<input type="hidden" name="expire_year" id="expire_year">
<input type="hidden" name="expire_month" id="expire_month">
<input type="hidden" name="last_4" id="last_4">
@if(!Request::isSecure())
<p class="alert alert-failure">{{ ctrans('texts.https_required') }}</p>
@endif
@if(Session::has('error'))
<div class="alert alert-failure mb-4" id="errors">{{ Session::get('error') }}</div>
@endif
<div id="forte_errors"></div>
@if ($errors->any())
<div class="alert alert-failure mb-4">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
{{ ctrans('texts.credit_card') }}
@endcomponent
@include('portal.ninja2020.gateways.forte.includes.credit_card')
<div class="bg-white px-4 py-5 flex justify-end">
<button type="button"
onclick="submitCard()"
class="button button-primary bg-primary {{ $class ?? '' }}">
<svg class="animate-spin h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<span>{{ $slot ?? ctrans('texts.add_payment_method') }}</span>
</button>
<input type="submit" style="display: none" id="form_btn">
</div>
</form>
@endsection
@section('gateway_footer')
<script>
function onTokenCreated(params) {
document.getElementById('one_time_token').value=params.onetime_token;
document.getElementById('last_4').value=params.last_4;
let button = document.querySelector("#form_btn");
button.click();
}
function onTokenFailed(params) {
var errors = '<div class="alert alert-failure mb-4"><ul><li>'+ params.response_description +'</li></ul></div>';
document.getElementById("forte_errors").innerHTML = errors;
}
function submitCard(){
var doc = document.getElementsByClassName("card-number-wrapper");
var cardType=doc[0].childNodes[1].classList[2];
if (cardType=='master-card') {
document.getElementById('card_type').value='mast';
} else if(cardType=='visa') {
document.getElementById('card_type').value='visa';
}else if(cardType=='jcb') {
document.getElementById('card_type').value='jcb';
}else if(cardType=='discover') {
document.getElementById('card_type').value='disc';
}else if(cardType=='american-express') {
document.getElementById('card_type').value='amex';
}else{
document.getElementById('card_type').value=cardType;
}
var month=document.querySelector('input[name=expiry-month]').value;
var year=document.querySelector('input[name=expiry-year]').value;
var cc=document.getElementById('card_number').value.replaceAll(' ','');
var cvv=document.getElementById('cvv').value;
document.getElementById('expire_year').value=year;
document.getElementById('expire_month').value=month;
var data = {
api_login_id: '{{$gateway->getConfigField("apiLoginId")}}',
card_number: cc,
expire_year: year,
expire_month: month,
cvv: cvv,
}
forte.createToken(data)
.success(onTokenCreated)
.error(onTokenFailed);
return false;
}
</script>
@endsection

View File

@ -0,0 +1,51 @@
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title' => ctrans('texts.payment_type_credit_card')])
@section('gateway_head')
<meta name="forte-api-login-id" content="{{$gateway->forte->company_gateway->getConfigField("apiLoginId")}}">
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="{{ asset('js/clients/payments/forte-card-js.min.js') }}"></script>
<link href="{{ asset('css/card-js.min.css') }}" rel="stylesheet" type="text/css">
@endsection
@section('gateway_content')
<form action="{{ route('client.payments.response') }}" method="post" id="server_response">
@csrf
<input type="hidden" name="card_brand" id="card_brand">
<input type="hidden" name="payment_token" id="payment_token">
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
<input type="hidden" name="company_gateway_id" value="{{ $gateway->forte->company_gateway->id }}">
<input type="hidden" name="payment_method_id" value="{{$payment_method_id}}">
<input type="hidden" name="gateway_response" id="gateway_response">
<input type="hidden" name="dataValue" id="dataValue"/>
<input type="hidden" name="dataDescriptor" id="dataDescriptor"/>
<input type="hidden" name="token" id="token"/>
<input type="hidden" name="store_card" id="store_card"/>
<input type="submit" style="display: none" id="form_btn">
</form>
<div id="forte_errors"></div>
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')])
{{ ctrans('texts.credit_card') }}
@endcomponent
@include('portal.ninja2020.gateways.includes.payment_details')
@component('portal.ninja2020.components.general.card-element', ['title' => 'Pay with Credit Card'])
@include('portal.ninja2020.gateways.forte.includes.credit_card')
@endcomponent
@include('portal.ninja2020.gateways.includes.pay_now')
@endsection
@section('gateway_footer')
@if($gateway->forte->company_gateway->getConfigField('testMode'))
<script type="text/javascript" src="https://sandbox.forte.net/api/js/v1"></script>
@else
<script type="text/javascript" src="https://api.forte.net/js/v1"></script>
@endif
<script src="{{ asset('js/clients/payments/forte-credit-card-payment.js') }}"></script>
@endsection

View File

@ -0,0 +1,12 @@
<div class="bg-white px-4 py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6"
style="display: flex!important; justify-content: center!important;" id="authorize--credit-card-container">
<div class="card-js" id="my-card" data-capture-name="true">
<input class="name" id="cardholder_name" name="card_holders_name" placeholder="{{ ctrans('texts.name')}}">
<input class="card-number my-custom-class" id="card_number">
<input type="hidden" name="expiry_month" id="expiration_month">
<input type="hidden" name="expiry_year" id="expiration_year">
<input class="cvc" name="cvc" id="cvv">
</div>
<div id="errors"></div>
</div>

View File

@ -3,7 +3,7 @@
@push('head') @push('head')
<meta name="show-purchase_order-terms" content="false"> <meta name="show-purchase_order-terms" content="false">
<meta name="require-purchase_order-signature" content="{{ $purchase_order->company->account->hasFeature(\App\Models\Account::FEATURE_INVOICE_SETTINGS) && $settings->require_purchase_order_signature }}"> <meta name="require-purchase_order-signature" content="{{ $purchase_order->company->account->hasFeature(\App\Models\Account::FEATURE_INVOICE_SETTINGS) && property_exists($settings, 'require_purchase_order_signature') && $settings->require_purchase_order_signature }}">
@include('portal.ninja2020.components.no-cache') @include('portal.ninja2020.components.no-cache')
<script src="{{ asset('vendor/signature_pad@2.3.2/signature_pad.min.js') }}"></script> <script src="{{ asset('vendor/signature_pad@2.3.2/signature_pad.min.js') }}"></script>

8
webpack.mix.js vendored
View File

@ -10,6 +10,14 @@ mix.js("resources/js/app.js", "public/js")
"resources/js/clients/payments/authorize-credit-card-payment.js", "resources/js/clients/payments/authorize-credit-card-payment.js",
"public/js/clients/payments/authorize-credit-card-payment.js" "public/js/clients/payments/authorize-credit-card-payment.js"
) )
.js(
"resources/js/clients/payments/forte-credit-card-payment.js",
"public/js/clients/payments/forte-credit-card-payment.js"
)
.js(
"resources/js/clients/payments/forte-ach-payment.js",
"public/js/clients/payments/forte-ach-payment.js"
)
.js( .js(
"resources/js/clients/payments/stripe-ach.js", "resources/js/clients/payments/stripe-ach.js",
"public/js/clients/payments/stripe-ach.js" "public/js/clients/payments/stripe-ach.js"