Authorize.net eCheck
This commit is contained in:
parent
19804f0574
commit
d30441c36f
|
|
@ -123,7 +123,10 @@ class Gateway extends StaticModel
|
||||||
{
|
{
|
||||||
switch ($this->id) {
|
switch ($this->id) {
|
||||||
case 1:
|
case 1:
|
||||||
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Authorize.net
|
return [
|
||||||
|
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true],
|
||||||
|
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true],
|
||||||
|
]; //Authorize.net
|
||||||
case 3:
|
case 3:
|
||||||
return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true]]; //eWay
|
return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true]]; //eWay
|
||||||
case 11:
|
case 11:
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\PaymentDrivers\Authorize;
|
||||||
|
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
use App\Models\PaymentHash;
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Exceptions\PaymentFailed;
|
||||||
|
use App\Models\ClientGatewayToken;
|
||||||
|
use App\Models\PaymentType as PType;
|
||||||
|
use App\PaymentDrivers\AuthorizePaymentDriver;
|
||||||
|
use App\PaymentDrivers\Common\MethodInterface;
|
||||||
|
use net\authorize\api\contract\v1\PaymentType;
|
||||||
|
use net\authorize\api\contract\v1\BankAccountType;
|
||||||
|
use App\PaymentDrivers\Common\LivewireMethodInterface;
|
||||||
|
use net\authorize\api\contract\v1\CustomerAddressType;
|
||||||
|
use App\PaymentDrivers\Authorize\AuthorizePaymentMethod;
|
||||||
|
use net\authorize\api\contract\v1\CustomerPaymentProfileType;
|
||||||
|
use net\authorize\api\contract\v1\CreateCustomerPaymentProfileRequest;
|
||||||
|
use net\authorize\api\controller\CreateCustomerPaymentProfileController;
|
||||||
|
|
||||||
|
class AuthorizeACH implements LivewireMethodInterface
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
/** @var AuthorizePaymentDriver */
|
||||||
|
public $authorize;
|
||||||
|
|
||||||
|
public function __construct(AuthorizePaymentDriver $authorize)
|
||||||
|
{
|
||||||
|
$this->authorize = $authorize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function livewirePaymentView(array $data): string
|
||||||
|
{
|
||||||
|
$data['gateway'] = $this->authorize;
|
||||||
|
$data['public_client_id'] = $this->authorize->init()->getPublicClientKey();
|
||||||
|
$data['api_login_id'] = $this->authorize->company_gateway->getConfigField('apiLoginId');
|
||||||
|
return render('gateways.authorize.ach.authorize', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paymentData(array $data): array
|
||||||
|
{
|
||||||
|
|
||||||
|
$tokens = ClientGatewayToken::where('client_id', $this->authorize->client->id)
|
||||||
|
->where('company_gateway_id', $this->authorize->company_gateway->id)
|
||||||
|
->where('gateway_type_id', GatewayType::BANK_TRANSFER)
|
||||||
|
->orderBy('is_default', 'desc')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
|
||||||
|
$data['tokens'] = $tokens;
|
||||||
|
$data['gateway'] = $this->authorize;
|
||||||
|
$data['public_client_id'] = $this->authorize->init()->getPublicClientKey();
|
||||||
|
$data['api_login_id'] = $this->authorize->company_gateway->getConfigField('apiLoginId');
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processPaymentView(array $data)
|
||||||
|
{
|
||||||
|
$data = $this->paymentData($data);
|
||||||
|
|
||||||
|
return render('gateways.authorize.ach.pay', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processPaymentResponse($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$this->authorize->init();
|
||||||
|
|
||||||
|
if($request->token) {
|
||||||
|
$client_gateway_token = ClientGatewayToken::query()
|
||||||
|
->where('id', $this->decodePrimaryKey($request->token))
|
||||||
|
->first();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$data = $request->all();
|
||||||
|
|
||||||
|
$data['is_running_payment'] = true;
|
||||||
|
$data['gateway_type_id'] = \App\Models\GatewayType::BANK_TRANSFER;
|
||||||
|
$client_gateway_token = (new AuthorizePaymentMethod($this->authorize))->authorizeBankTransferResponse($data);
|
||||||
|
|
||||||
|
if(!$client_gateway_token) {
|
||||||
|
throw new PaymentFailed('Could not find the payment profile', 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$payment_hash = PaymentHash::where('hash', $request->payment_hash)->firstOrFail();
|
||||||
|
|
||||||
|
$data = (new ChargePaymentProfile($this->authorize))
|
||||||
|
->chargeCustomerProfile($client_gateway_token->gateway_customer_reference, $client_gateway_token->token, $payment_hash->data->amount_with_fee);
|
||||||
|
|
||||||
|
$response = $data['raw_response'];
|
||||||
|
|
||||||
|
if ($response->getMessages()->getResultCode() == 'Ok') {
|
||||||
|
$payment = $this->createPayment($payment_hash, $response);
|
||||||
|
|
||||||
|
SystemLogger::dispatch(
|
||||||
|
['response' => $response, 'data' => $payment_hash->data],
|
||||||
|
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||||
|
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||||
|
SystemLog::TYPE_AUTHORIZE,
|
||||||
|
$this->authorize->client,
|
||||||
|
$this->authorize->client->company,
|
||||||
|
);
|
||||||
|
|
||||||
|
return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$error_messages = $response->getMessages()->getMessage();
|
||||||
|
$error = $error_messages[0]->getText();
|
||||||
|
|
||||||
|
$this->authorize->sendFailureMail($error);
|
||||||
|
|
||||||
|
throw new PaymentFailed($error, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createPayment($payment_hash, $response)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'payment_method' => PType::BANK_TRANSFER,
|
||||||
|
'payment_type' => PType::BANK_TRANSFER,
|
||||||
|
'amount' => $payment_hash->data->amount_with_fee,
|
||||||
|
'transaction_reference' => $response->getTransactionResponse()->getTransId(),
|
||||||
|
'gateway_type_id' => GatewayType::BANK_TRANSFER,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->authorize->createPayment($data, Payment::STATUS_COMPLETED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -54,28 +54,6 @@ class AuthorizeCreateCustomer
|
||||||
$customerProfile->setMerchantCustomerId('M_'.time());
|
$customerProfile->setMerchantCustomerId('M_'.time());
|
||||||
$customerProfile->setEmail($this->client->present()->email());
|
$customerProfile->setEmail($this->client->present()->email());
|
||||||
|
|
||||||
// if($this->client) {
|
|
||||||
|
|
||||||
// $primary_contact = $this->client->primary_contact()->first() ?? $this->client->contacts()->first();
|
|
||||||
|
|
||||||
// $shipTo = new CustomerAddressType();
|
|
||||||
// $shipTo->setFirstName(substr($primary_contact->present()->first_name(), 0, 50));
|
|
||||||
// $shipTo->setLastName(substr($primary_contact->present()->last_name(), 0, 50));
|
|
||||||
// $shipTo->setCompany(substr($this->client->present()->name(), 0, 50));
|
|
||||||
// $shipTo->setAddress(substr($this->client->shipping_address1, 0, 60));
|
|
||||||
// $shipTo->setCity(substr($this->client->shipping_city, 0, 40));
|
|
||||||
// $shipTo->setState(substr($this->client->shipping_state, 0, 40));
|
|
||||||
// $shipTo->setZip(substr($this->client->shipping_postal_code, 0, 20));
|
|
||||||
|
|
||||||
// if ($this->client->country_id) {
|
|
||||||
// $shipTo->setCountry($this->client->shipping_country->name);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $shipTo->setPhoneNumber(substr($this->client->phone, 0, 20));
|
|
||||||
// $customerProfile->setShipToList([$shipTo]);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Assemble the complete transaction request
|
// Assemble the complete transaction request
|
||||||
$request = new CreateCustomerProfileRequest();
|
$request = new CreateCustomerProfileRequest();
|
||||||
$request->setMerchantAuthentication($this->authorize->merchant_authentication);
|
$request->setMerchantAuthentication($this->authorize->merchant_authentication);
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,11 @@ class AuthorizePaymentMethod
|
||||||
return $this->authorizeCreditCard();
|
return $this->authorizeCreditCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
// case GatewayType::BANK_TRANSFER:
|
if ($this->authorize->payment_method instanceof AuthorizeACH) {
|
||||||
// return $this->authorizeBankTransfer();
|
$this->payment_method_id = GatewayType::BANK_TRANSFER;
|
||||||
// break;
|
|
||||||
|
return $this->authorizeBankTransfer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function authorizeResponseView($request)
|
public function authorizeResponseView($request)
|
||||||
|
|
@ -88,6 +90,15 @@ class AuthorizePaymentMethod
|
||||||
|
|
||||||
public function authorizeBankTransfer()
|
public function authorizeBankTransfer()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
$data['gateway'] = $this->authorize;
|
||||||
|
$data['public_client_id'] = $this->authorize->init()->getPublicClientKey();
|
||||||
|
$data['api_login_id'] = $this->authorize->company_gateway->getConfigField('apiLoginId');
|
||||||
|
|
||||||
|
return render('gateways.authorize.ach.authorize', $data);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function authorizeCreditCardResponse($data)
|
public function authorizeCreditCardResponse($data)
|
||||||
|
|
@ -110,6 +121,25 @@ class AuthorizePaymentMethod
|
||||||
|
|
||||||
public function authorizeBankTransferResponse($data)
|
public function authorizeBankTransferResponse($data)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
$client_profile_id = null;
|
||||||
|
$this->payment_method_id = GatewayType::BANK_TRANSFER; //override in case we have come from a payment.
|
||||||
|
|
||||||
|
if ($client_gateway_token = $this->authorize->findClientGatewayRecord()) {
|
||||||
|
$payment_profile = $this->addPaymentMethodToClient($client_gateway_token->gateway_customer_reference, $data);
|
||||||
|
$gateway_customer_reference = $client_gateway_token->gateway_customer_reference;
|
||||||
|
} else {
|
||||||
|
$gateway_customer_reference = (new AuthorizeCreateCustomer($this->authorize, $this->authorize->client))->create($data);
|
||||||
|
$payment_profile = $this->addPaymentMethodToClient($gateway_customer_reference, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$cgt = $this->createClientGatewayToken($payment_profile, $gateway_customer_reference);
|
||||||
|
|
||||||
|
if(isset($data['is_running_payment']))
|
||||||
|
return $cgt;
|
||||||
|
|
||||||
|
return redirect()->route('client.payment_methods.index');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createClientGatewayToken($payment_profile, $gateway_customer_reference)
|
public function createClientGatewayToken($payment_profile, $gateway_customer_reference)
|
||||||
|
|
@ -119,21 +149,28 @@ class AuthorizePaymentMethod
|
||||||
|
|
||||||
$data['token'] = $payment_profile->getPaymentProfile()->getCustomerPaymentProfileId();
|
$data['token'] = $payment_profile->getPaymentProfile()->getCustomerPaymentProfileId();
|
||||||
$data['payment_method_id'] = $this->payment_method_id;
|
$data['payment_method_id'] = $this->payment_method_id;
|
||||||
$data['payment_meta'] = $this->buildPaymentMethod($payment_profile);
|
$data['payment_meta'] = $this->buildPaymentMethod($payment_profile, true);
|
||||||
$data['payment_method_id'] = GatewayType::CREDIT_CARD;
|
|
||||||
|
|
||||||
$additional['gateway_customer_reference'] = $gateway_customer_reference;
|
$additional['gateway_customer_reference'] = $gateway_customer_reference;
|
||||||
|
|
||||||
$this->authorize->storeGatewayToken($data, $additional);
|
return $this->authorize->storeGatewayToken($data, $additional);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildPaymentMethod($payment_profile)
|
public function buildPaymentMethod($payment_profile, $is_ach = false)
|
||||||
{
|
{
|
||||||
|
if ($is_ach) {
|
||||||
|
$brand = sprintf($payment_profile->getPaymentProfile()->getPayment()->getBankAccount()->getBankName());
|
||||||
|
$last4 = (string) $payment_profile->getPaymentProfile()->getPayment()->getBankAccount()->getAccountNumber();
|
||||||
|
} else {
|
||||||
|
$brand = (string) $payment_profile->getPaymentProfile()->getPayment()->getCreditCard()->getCardType();
|
||||||
|
$last4 = (string) $payment_profile->getPaymentProfile()->getPayment()->getCreditCard()->getCardNumber();
|
||||||
|
}
|
||||||
|
|
||||||
$payment_meta = new stdClass();
|
$payment_meta = new stdClass();
|
||||||
$payment_meta->exp_month = 'xx';
|
$payment_meta->exp_month = 'xx';
|
||||||
$payment_meta->exp_year = 'xx';
|
$payment_meta->exp_year = 'xx';
|
||||||
$payment_meta->brand = (string) $payment_profile->getPaymentProfile()->getPayment()->getCreditCard()->getCardType();
|
$payment_meta->brand = $brand;
|
||||||
$payment_meta->last4 = (string) $payment_profile->getPaymentProfile()->getPayment()->getCreditCard()->getCardNumber();
|
$payment_meta->last4 = $last4;
|
||||||
$payment_meta->type = $this->payment_method;
|
$payment_meta->type = $this->payment_method;
|
||||||
|
|
||||||
return $payment_meta;
|
return $payment_meta;
|
||||||
|
|
@ -191,7 +228,6 @@ class AuthorizePaymentMethod
|
||||||
|
|
||||||
$paymentprofile->setPayment($paymentOne);
|
$paymentprofile->setPayment($paymentOne);
|
||||||
$paymentprofile->setDefaultPaymentProfile(true);
|
$paymentprofile->setDefaultPaymentProfile(true);
|
||||||
$paymentprofiles[] = $paymentprofile;
|
|
||||||
|
|
||||||
// Assemble the complete transaction request
|
// Assemble the complete transaction request
|
||||||
$paymentprofilerequest = new CreateCustomerPaymentProfileRequest();
|
$paymentprofilerequest = new CreateCustomerPaymentProfileRequest();
|
||||||
|
|
@ -200,7 +236,7 @@ class AuthorizePaymentMethod
|
||||||
// Add an existing profile id to the request
|
// Add an existing profile id to the request
|
||||||
$paymentprofilerequest->setCustomerProfileId($gateway_customer_reference);
|
$paymentprofilerequest->setCustomerProfileId($gateway_customer_reference);
|
||||||
$paymentprofilerequest->setPaymentProfile($paymentprofile);
|
$paymentprofilerequest->setPaymentProfile($paymentprofile);
|
||||||
$paymentprofilerequest->setValidationMode('liveMode');
|
$paymentprofilerequest->setValidationMode($this->authorize->validationMode());
|
||||||
|
|
||||||
// Create the controller and get the response
|
// Create the controller and get the response
|
||||||
$controller = new CreateCustomerPaymentProfileController($paymentprofilerequest);
|
$controller = new CreateCustomerPaymentProfileController($paymentprofilerequest);
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ class ChargePaymentProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'raw_response' => $response,
|
||||||
'response' => $tresponse,
|
'response' => $tresponse,
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'profile_id' => $profile_id,
|
'profile_id' => $profile_id,
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,17 @@
|
||||||
|
|
||||||
namespace App\PaymentDrivers;
|
namespace App\PaymentDrivers;
|
||||||
|
|
||||||
use App\Models\ClientGatewayToken;
|
|
||||||
use App\Models\GatewayType;
|
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\PaymentHash;
|
|
||||||
use App\Models\SystemLog;
|
use App\Models\SystemLog;
|
||||||
use App\PaymentDrivers\Authorize\AuthorizeCreditCard;
|
use App\Models\GatewayType;
|
||||||
use App\PaymentDrivers\Authorize\AuthorizeCustomer;
|
use App\Models\PaymentHash;
|
||||||
use App\PaymentDrivers\Authorize\AuthorizePaymentMethod;
|
use App\Models\ClientGatewayToken;
|
||||||
use App\PaymentDrivers\Authorize\RefundTransaction;
|
use App\PaymentDrivers\Authorize\AuthorizeACH;
|
||||||
use net\authorize\api\constants\ANetEnvironment;
|
use net\authorize\api\constants\ANetEnvironment;
|
||||||
|
use App\PaymentDrivers\Authorize\AuthorizeCustomer;
|
||||||
|
use App\PaymentDrivers\Authorize\RefundTransaction;
|
||||||
|
use App\PaymentDrivers\Authorize\AuthorizeCreditCard;
|
||||||
|
use App\PaymentDrivers\Authorize\AuthorizePaymentMethod;
|
||||||
use net\authorize\api\contract\v1\GetMerchantDetailsRequest;
|
use net\authorize\api\contract\v1\GetMerchantDetailsRequest;
|
||||||
use net\authorize\api\contract\v1\MerchantAuthenticationType;
|
use net\authorize\api\contract\v1\MerchantAuthenticationType;
|
||||||
use net\authorize\api\controller\GetMerchantDetailsController;
|
use net\authorize\api\controller\GetMerchantDetailsController;
|
||||||
|
|
@ -39,6 +40,7 @@ class AuthorizePaymentDriver extends BaseDriver
|
||||||
|
|
||||||
public static $methods = [
|
public static $methods = [
|
||||||
GatewayType::CREDIT_CARD => AuthorizeCreditCard::class,
|
GatewayType::CREDIT_CARD => AuthorizeCreditCard::class,
|
||||||
|
GatewayType::BANK_TRANSFER => AuthorizeACH::class,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const SYSTEM_LOG_TYPE = SystemLog::TYPE_AUTHORIZE;
|
public const SYSTEM_LOG_TYPE = SystemLog::TYPE_AUTHORIZE;
|
||||||
|
|
@ -60,6 +62,7 @@ class AuthorizePaymentDriver extends BaseDriver
|
||||||
$types = [];
|
$types = [];
|
||||||
|
|
||||||
$types[] = GatewayType::CREDIT_CARD;
|
$types[] = GatewayType::CREDIT_CARD;
|
||||||
|
$types[] = GatewayType::BANK_TRANSFER;
|
||||||
|
|
||||||
return $types;
|
return $types;
|
||||||
}
|
}
|
||||||
|
|
@ -173,6 +176,11 @@ class AuthorizePaymentDriver extends BaseDriver
|
||||||
return $env = ANetEnvironment::PRODUCTION;
|
return $env = ANetEnvironment::PRODUCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function validationMode()
|
||||||
|
{
|
||||||
|
return $this->company_gateway->getConfigField('testMode') ? 'testMode' : 'liveMode';
|
||||||
|
}
|
||||||
|
|
||||||
public function findClientGatewayRecord(): ?ClientGatewayToken
|
public function findClientGatewayRecord(): ?ClientGatewayToken
|
||||||
{
|
{
|
||||||
return ClientGatewayToken::where('client_id', $this->client->id)
|
return ClientGatewayToken::where('client_id', $this->client->id)
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,10 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/class u{constructor(t,e){this.form=document.getElementById("server_response"),this.submitButton=document.getElementById("card_button"),this.errorDiv=document.getElementById("errors"),this.publicKey=t,this.loginId=e,this.accountHolderName=document.getElementById("account_holder_name"),this.routingNumber=document.getElementById("routing_number"),this.accountNumber=document.getElementById("account_number"),this.acceptTerms=document.getElementById("accept-terms"),this.isValid={accountHolderName:!1,routingNumber:!1,accountNumber:!1,acceptTerms:!1},this.setupEventListeners(),this.updateSubmitButton()}setupEventListeners(){this.accountHolderName.addEventListener("input",()=>{this.validateAccountHolderName(),this.updateSubmitButton()}),this.routingNumber.addEventListener("input",()=>{this.validateRoutingNumber(),this.updateSubmitButton()}),this.accountNumber.addEventListener("input",()=>{this.validateAccountNumber(),this.updateSubmitButton()}),this.acceptTerms.addEventListener("change",()=>{this.validateAcceptTerms(),this.updateSubmitButton()}),this.submitButton.addEventListener("click",t=>{t.preventDefault(),this.isFormValid()&&this.handleSubmit()})}validateAcceptTerms(){this.isValid.acceptTerms=this.acceptTerms.checked,this.isValid.acceptTerms?this.acceptTerms.classList.remove("border-red-500"):this.acceptTerms.classList.add("border-red-500")}validateAccountHolderName(){const t=this.accountHolderName.value.trim();this.isValid.accountHolderName=t.length>0&&t.length<=22,this.isValid.accountHolderName?this.accountHolderName.classList.remove("border-red-500"):this.accountHolderName.classList.add("border-red-500")}validateRoutingNumber(){const t=this.routingNumber.value.replace(/\D/g,"");this.isValid.routingNumber=t.length===9,this.isValid.routingNumber?this.routingNumber.classList.remove("border-red-500"):this.routingNumber.classList.add("border-red-500")}validateAccountNumber(){const t=this.accountNumber.value.replace(/\D/g,"");this.isValid.accountNumber=t.length>=1&&t.length<=17,this.isValid.accountNumber?this.accountNumber.classList.remove("border-red-500"):this.accountNumber.classList.add("border-red-500")}isFormValid(){return Object.values(this.isValid).every(Boolean)}updateSubmitButton(){const t=this.isFormValid();this.submitButton.disabled=!t,t?(this.submitButton.classList.remove("opacity-50","cursor-not-allowed"),this.submitButton.classList.add("hover:bg-primary-dark")):(this.submitButton.classList.add("opacity-50","cursor-not-allowed"),this.submitButton.classList.remove("hover:bg-primary-dark"))}handleSubmit(){var i,r;if(!this.isFormValid())return;this.submitButton.disabled=!0,(i=this.submitButton.querySelector("svg"))==null||i.classList.remove("hidden"),(r=this.submitButton.querySelector("span"))==null||r.classList.add("hidden");const t=document.querySelector('input[name="account_type"]:checked').value??"checking";var e={};e.clientKey=this.publicKey,e.apiLoginID=this.loginId;var s={};s.accountType=t,s.routingNumber=this.routingNumber.value,s.accountNumber=this.accountNumber.value,s.nameOnAccount=this.accountHolderName.value;var a={};a.authData=e,a.bankData=s,Accept.dispatchData(a,this.handleResponse.bind(this))}handleResponse(t){var e,s;if(t.messages.resultCode==="Error"){let a="";for(let i=0;i<t.messages.message.length;i++)a+=`${t.messages.message[i].code}: ${t.messages.message[i].text}
|
||||||
|
`;this.errorDiv.textContent=a,this.errorDiv.hidden=!1,this.submitButton.disabled=!1,(e=this.submitButton.querySelector("svg"))==null||e.classList.add("hidden"),(s=this.submitButton.querySelector("span"))==null||s.classList.remove("hidden");return}document.getElementById("dataDescriptor").value=t.opaqueData.dataDescriptor,document.getElementById("dataValue").value=t.opaqueData.dataValue,this.form.submit()}}const n=document.querySelector('meta[name="authorize-public-key"]').content,o=document.querySelector('meta[name="authorize-login-id"]').content;document.addEventListener("DOMContentLoaded",()=>{new u(n,o)});
|
||||||
|
|
@ -38,6 +38,11 @@
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
"src": "resources/js/clients/linkify-urls.js"
|
"src": "resources/js/clients/linkify-urls.js"
|
||||||
},
|
},
|
||||||
|
"resources/js/clients/payment_methods/authorize-authorize-ach.js": {
|
||||||
|
"file": "assets/authorize-authorize-ach-4ab153a6.js",
|
||||||
|
"isEntry": true,
|
||||||
|
"src": "resources/js/clients/payment_methods/authorize-authorize-ach.js"
|
||||||
|
},
|
||||||
"resources/js/clients/payment_methods/authorize-authorize-card.js": {
|
"resources/js/clients/payment_methods/authorize-authorize-card.js": {
|
||||||
"file": "assets/authorize-authorize-card-39be6d93.js",
|
"file": "assets/authorize-authorize-card-39be6d93.js",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
|
|
@ -77,6 +82,14 @@
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
"src": "resources/js/clients/payment_methods/wepay-bank-account.js"
|
"src": "resources/js/clients/payment_methods/wepay-bank-account.js"
|
||||||
},
|
},
|
||||||
|
"resources/js/clients/payments/authorize-ach-payment.js": {
|
||||||
|
"file": "assets/authorize-ach-payment-76cf3d3d.js",
|
||||||
|
"imports": [
|
||||||
|
"_wait-8f4ae121.js"
|
||||||
|
],
|
||||||
|
"isEntry": true,
|
||||||
|
"src": "resources/js/clients/payments/authorize-ach-payment.js"
|
||||||
|
},
|
||||||
"resources/js/clients/payments/authorize-credit-card-payment.js": {
|
"resources/js/clients/payments/authorize-credit-card-payment.js": {
|
||||||
"file": "assets/authorize-credit-card-payment-4a21c1d6.js",
|
"file": "assets/authorize-credit-card-payment-4a21c1d6.js",
|
||||||
"imports": [
|
"imports": [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AuthorizeACH {
|
||||||
|
constructor(publicKey, loginId) {
|
||||||
|
this.form = document.getElementById('server_response');
|
||||||
|
this.submitButton = document.getElementById('card_button');
|
||||||
|
this.errorDiv = document.getElementById('errors');
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.loginId = loginId;
|
||||||
|
// Input fields
|
||||||
|
this.accountHolderName = document.getElementById('account_holder_name');
|
||||||
|
this.routingNumber = document.getElementById('routing_number');
|
||||||
|
this.accountNumber = document.getElementById('account_number');
|
||||||
|
this.acceptTerms = document.getElementById('accept-terms');
|
||||||
|
|
||||||
|
// Validation state
|
||||||
|
this.isValid = {
|
||||||
|
accountHolderName: false,
|
||||||
|
routingNumber: false,
|
||||||
|
accountNumber: false,
|
||||||
|
acceptTerms: false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setupEventListeners();
|
||||||
|
this.updateSubmitButton(); // Initial state
|
||||||
|
}
|
||||||
|
|
||||||
|
setupEventListeners() {
|
||||||
|
// Monitor account holder name
|
||||||
|
this.accountHolderName.addEventListener('input', () => {
|
||||||
|
this.validateAccountHolderName();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Monitor routing number
|
||||||
|
this.routingNumber.addEventListener('input', () => {
|
||||||
|
this.validateRoutingNumber();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Monitor account number
|
||||||
|
this.accountNumber.addEventListener('input', () => {
|
||||||
|
this.validateAccountNumber();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.acceptTerms.addEventListener('change', () => {
|
||||||
|
this.validateAcceptTerms();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Submit button handler
|
||||||
|
this.submitButton.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (this.isFormValid()) {
|
||||||
|
this.handleSubmit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAcceptTerms() {
|
||||||
|
this.isValid.acceptTerms = this.acceptTerms.checked;
|
||||||
|
if (!this.isValid.acceptTerms) {
|
||||||
|
this.acceptTerms.classList.add('border-red-500');
|
||||||
|
} else {
|
||||||
|
this.acceptTerms.classList.remove('border-red-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAccountHolderName() {
|
||||||
|
const name = this.accountHolderName.value.trim();
|
||||||
|
this.isValid.accountHolderName = name.length > 0 && name.length <= 22;
|
||||||
|
|
||||||
|
if (!this.isValid.accountHolderName) {
|
||||||
|
this.accountHolderName.classList.add('border-red-500');
|
||||||
|
} else {
|
||||||
|
this.accountHolderName.classList.remove('border-red-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateRoutingNumber() {
|
||||||
|
const routing = this.routingNumber.value.replace(/\D/g, '');
|
||||||
|
this.isValid.routingNumber = routing.length === 9;
|
||||||
|
|
||||||
|
if (!this.isValid.routingNumber) {
|
||||||
|
this.routingNumber.classList.add('border-red-500');
|
||||||
|
} else {
|
||||||
|
this.routingNumber.classList.remove('border-red-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAccountNumber() {
|
||||||
|
const account = this.accountNumber.value.replace(/\D/g, '');
|
||||||
|
this.isValid.accountNumber = account.length >= 1 && account.length <= 17;
|
||||||
|
|
||||||
|
if (!this.isValid.accountNumber) {
|
||||||
|
this.accountNumber.classList.add('border-red-500');
|
||||||
|
} else {
|
||||||
|
this.accountNumber.classList.remove('border-red-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isFormValid() {
|
||||||
|
return Object.values(this.isValid).every(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSubmitButton() {
|
||||||
|
const isValid = this.isFormValid();
|
||||||
|
this.submitButton.disabled = !isValid;
|
||||||
|
|
||||||
|
// Visual feedback
|
||||||
|
if (isValid) {
|
||||||
|
this.submitButton.classList.remove('opacity-50', 'cursor-not-allowed');
|
||||||
|
this.submitButton.classList.add('hover:bg-primary-dark');
|
||||||
|
} else {
|
||||||
|
this.submitButton.classList.add('opacity-50', 'cursor-not-allowed');
|
||||||
|
this.submitButton.classList.remove('hover:bg-primary-dark');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit() {
|
||||||
|
if (!this.isFormValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the submit button and show loading state
|
||||||
|
this.submitButton.disabled = true;
|
||||||
|
this.submitButton.querySelector('svg')?.classList.remove('hidden');
|
||||||
|
this.submitButton.querySelector('span')?.classList.add('hidden');
|
||||||
|
|
||||||
|
// Get the selected account type
|
||||||
|
const accountType = document.querySelector('input[name="account_type"]:checked').value ?? 'checking';
|
||||||
|
|
||||||
|
var authData = {};
|
||||||
|
authData.clientKey = this.publicKey;
|
||||||
|
authData.apiLoginID = this.loginId;
|
||||||
|
|
||||||
|
// Prepare the data for Authorize.net
|
||||||
|
var bankData = {};
|
||||||
|
bankData.accountType = accountType;
|
||||||
|
bankData.routingNumber = this.routingNumber.value;
|
||||||
|
bankData.accountNumber = this.accountNumber.value;
|
||||||
|
bankData.nameOnAccount = this.accountHolderName.value;
|
||||||
|
|
||||||
|
var secureData = {};
|
||||||
|
secureData.authData = authData;
|
||||||
|
secureData.bankData = bankData;
|
||||||
|
|
||||||
|
// Initialize Accept.js
|
||||||
|
Accept.dispatchData(secureData, this.handleResponse.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleResponse(response) {
|
||||||
|
if (response.messages.resultCode === 'Error') {
|
||||||
|
let errorMessage = '';
|
||||||
|
for (let i = 0; i < response.messages.message.length; i++) {
|
||||||
|
errorMessage += `${response.messages.message[i].code}: ${response.messages.message[i].text}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.errorDiv.textContent = errorMessage;
|
||||||
|
this.errorDiv.hidden = false;
|
||||||
|
|
||||||
|
// Re-enable the submit button
|
||||||
|
this.submitButton.disabled = false;
|
||||||
|
this.submitButton.querySelector('svg')?.classList.add('hidden');
|
||||||
|
this.submitButton.querySelector('span')?.classList.remove('hidden');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On success, update the hidden form fields
|
||||||
|
document.getElementById('dataDescriptor').value = response.opaqueData.dataDescriptor;
|
||||||
|
document.getElementById('dataValue').value = response.opaqueData.dataValue;
|
||||||
|
|
||||||
|
// Submit the form
|
||||||
|
this.form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const publicKey = document.querySelector(
|
||||||
|
'meta[name="authorize-public-key"]'
|
||||||
|
).content;
|
||||||
|
|
||||||
|
const loginId = document.querySelector(
|
||||||
|
'meta[name="authorize-login-id"]'
|
||||||
|
).content;
|
||||||
|
|
||||||
|
// Initialize when the DOM is ready
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
new AuthorizeACH(publicKey, loginId);
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,283 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { wait, instant } from '../wait';
|
||||||
|
|
||||||
|
class AuthorizeAuthorizeACH {
|
||||||
|
constructor(publicKey, loginId) {
|
||||||
|
this.form = document.getElementById('server_response');
|
||||||
|
this.submitButton = document.getElementById('pay-now');
|
||||||
|
this.errorDiv = document.getElementById('errors');
|
||||||
|
this.publicKey = publicKey;
|
||||||
|
this.loginId = loginId;
|
||||||
|
// Input fields
|
||||||
|
this.accountHolderName = document.getElementById('account_holder_name');
|
||||||
|
this.routingNumber = document.getElementById('routing_number');
|
||||||
|
this.accountNumber = document.getElementById('account_number');
|
||||||
|
this.acceptTerms = document.getElementById('accept-terms');
|
||||||
|
// Validation state
|
||||||
|
this.isValid = {
|
||||||
|
accountHolderName: false,
|
||||||
|
routingNumber: false,
|
||||||
|
accountNumber: false,
|
||||||
|
acceptTerms: false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setupEventListeners();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAuthorization = () => {
|
||||||
|
|
||||||
|
if (!this.isFormValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable the submit button and show loading state
|
||||||
|
this.submitButton.disabled = true;
|
||||||
|
this.submitButton.querySelector('svg')?.classList.remove('hidden');
|
||||||
|
this.submitButton.querySelector('span')?.classList.add('hidden');
|
||||||
|
|
||||||
|
// Get the selected account type
|
||||||
|
const accountType = document.querySelector('input[name="account_type"]:checked').value ?? 'checking';
|
||||||
|
|
||||||
|
var authData = {};
|
||||||
|
authData.clientKey = this.publicKey;
|
||||||
|
authData.apiLoginID = this.loginId;
|
||||||
|
|
||||||
|
// Prepare the data for Authorize.net
|
||||||
|
var bankData = {};
|
||||||
|
bankData.accountType = accountType;
|
||||||
|
bankData.routingNumber = this.routingNumber.value;
|
||||||
|
bankData.accountNumber = this.accountNumber.value;
|
||||||
|
bankData.nameOnAccount = this.accountHolderName.value;
|
||||||
|
|
||||||
|
var secureData = {};
|
||||||
|
secureData.authData = authData;
|
||||||
|
secureData.bankData = bankData;
|
||||||
|
|
||||||
|
Accept.dispatchData(secureData, this.responseHandler);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
setupEventListeners() {
|
||||||
|
// Monitor account holder name
|
||||||
|
this.accountHolderName.addEventListener('input', () => {
|
||||||
|
this.validateAccountHolderName();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Monitor routing number
|
||||||
|
this.routingNumber.addEventListener('input', () => {
|
||||||
|
this.validateRoutingNumber();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Monitor account number
|
||||||
|
this.accountNumber.addEventListener('input', () => {
|
||||||
|
this.validateAccountNumber();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Submit button handler
|
||||||
|
this.submitButton.addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (this.isFormValid()) {
|
||||||
|
this.handleAuthorization();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.acceptTerms.addEventListener('change', () => {
|
||||||
|
this.validateAcceptTerms();
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
validateAcceptTerms() {
|
||||||
|
this.isValid.acceptTerms = this.acceptTerms.checked;
|
||||||
|
if (!this.isValid.acceptTerms) {
|
||||||
|
this.acceptTerms.classList.add('border-red-500');
|
||||||
|
} else {
|
||||||
|
this.acceptTerms.classList.remove('border-red-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
validateAccountHolderName() {
|
||||||
|
const name = this.accountHolderName.value.trim();
|
||||||
|
this.isValid.accountHolderName = name.length > 0 && name.length <= 22;
|
||||||
|
|
||||||
|
if (!this.isValid.accountHolderName) {
|
||||||
|
this.accountHolderName.classList.add('border-red-500');
|
||||||
|
} else {
|
||||||
|
this.accountHolderName.classList.remove('border-red-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateRoutingNumber() {
|
||||||
|
const routing = this.routingNumber.value.replace(/\D/g, '');
|
||||||
|
this.isValid.routingNumber = routing.length === 9;
|
||||||
|
|
||||||
|
if (!this.isValid.routingNumber) {
|
||||||
|
this.routingNumber.classList.add('border-red-500');
|
||||||
|
} else {
|
||||||
|
this.routingNumber.classList.remove('border-red-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateAccountNumber() {
|
||||||
|
const account = this.accountNumber.value.replace(/\D/g, '');
|
||||||
|
this.isValid.accountNumber = account.length >= 1 && account.length <= 17;
|
||||||
|
|
||||||
|
if (!this.isValid.accountNumber) {
|
||||||
|
this.accountNumber.classList.add('border-red-500');
|
||||||
|
} else {
|
||||||
|
this.accountNumber.classList.remove('border-red-500');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isFormValid() {
|
||||||
|
return Object.values(this.isValid).every(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSubmitButton() {
|
||||||
|
const isValid = this.isFormValid();
|
||||||
|
this.submitButton.disabled = !isValid;
|
||||||
|
|
||||||
|
// Visual feedback
|
||||||
|
if (isValid) {
|
||||||
|
this.submitButton.classList.remove('opacity-50', 'cursor-not-allowed');
|
||||||
|
this.submitButton.classList.add('hover:bg-primary-dark');
|
||||||
|
} else {
|
||||||
|
this.submitButton.classList.add('opacity-50', 'cursor-not-allowed');
|
||||||
|
this.submitButton.classList.remove('hover:bg-primary-dark');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePayNowAction(token_hashed_id) {
|
||||||
|
document.getElementById('pay-now').disabled = true;
|
||||||
|
document.querySelector('#pay-now > svg').classList.remove('hidden');
|
||||||
|
document.querySelector('#pay-now > span').classList.add('hidden');
|
||||||
|
|
||||||
|
document.getElementById('token').value = token_hashed_id;
|
||||||
|
document.getElementById('server_response').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
responseHandler = (response) => {
|
||||||
|
if (response.messages.resultCode === 'Error') {
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
const $errors = document.getElementById('errors'); // get the reference of the div
|
||||||
|
|
||||||
|
if ($errors) {
|
||||||
|
$errors.innerText = `${response.messages.message[i].code}: ${response.messages.message[i].text}`;
|
||||||
|
$errors.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('pay-now').disabled = false;
|
||||||
|
document.querySelector('#pay-now > svg').classList.add('hidden');
|
||||||
|
document
|
||||||
|
.querySelector('#pay-now > span')
|
||||||
|
.classList.remove('hidden');
|
||||||
|
} else if (response.messages.resultCode === 'Ok') {
|
||||||
|
document.getElementById('dataDescriptor').value =
|
||||||
|
response.opaqueData.dataDescriptor;
|
||||||
|
document.getElementById('dataValue').value =
|
||||||
|
response.opaqueData.dataValue;
|
||||||
|
|
||||||
|
let storeCard = document.querySelector(
|
||||||
|
'input[name=token-billing-checkbox]:checked'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (storeCard) {
|
||||||
|
document.getElementById('store_card').value = storeCard.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('server_response').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
handle = () => {
|
||||||
|
Array.from(
|
||||||
|
document.getElementsByClassName('toggle-payment-with-token')
|
||||||
|
).forEach((element) =>
|
||||||
|
element.addEventListener('click', (e) => {
|
||||||
|
document.getElementById(
|
||||||
|
'authorize-ach-container'
|
||||||
|
).style.display = 'none';
|
||||||
|
|
||||||
|
document.getElementById('token').value = e.target.dataset.token;
|
||||||
|
|
||||||
|
document.getElementById('pay-now').disabled = false;
|
||||||
|
document.querySelector('#pay-now > svg').classList.add('hidden');
|
||||||
|
document
|
||||||
|
.querySelector('#pay-now > span')
|
||||||
|
.classList.remove('hidden');
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
let payWithACHToggle = document.getElementById(
|
||||||
|
'toggle-payment-with-ach'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (payWithACHToggle) {
|
||||||
|
payWithACHToggle.addEventListener('click', () => {
|
||||||
|
document.getElementById(
|
||||||
|
'authorize-ach-container'
|
||||||
|
).style.display = 'grid';
|
||||||
|
|
||||||
|
document.getElementById('token').value = null;
|
||||||
|
|
||||||
|
this.updateSubmitButton();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let payNowButton = document.getElementById('pay-now');
|
||||||
|
|
||||||
|
if (payNowButton) {
|
||||||
|
payNowButton.addEventListener('click', (e) => {
|
||||||
|
let token = document.getElementById('token');
|
||||||
|
|
||||||
|
token.value
|
||||||
|
? this.handlePayNowAction(token.value)
|
||||||
|
: this.handleAuthorization();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function boot() {
|
||||||
|
const publicKey = document.querySelector(
|
||||||
|
'meta[name="authorize-public-key"]'
|
||||||
|
).content;
|
||||||
|
|
||||||
|
const loginId = document.querySelector(
|
||||||
|
'meta[name="authorize-login-id"]'
|
||||||
|
).content;
|
||||||
|
|
||||||
|
/** @handle */
|
||||||
|
new AuthorizeAuthorizeACH(publicKey, loginId).handle();
|
||||||
|
|
||||||
|
/** @type {NodeListOf<HTMLInputElement>} */
|
||||||
|
const tokens = document.querySelectorAll('input.toggle-payment-with-token');
|
||||||
|
|
||||||
|
if (tokens.length > 0) {
|
||||||
|
tokens[0].click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instant() ? boot() : wait('#authorize-ach-payment').then(() => boot());
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'ACH', 'card_title' => ctrans('texts.ach')])
|
||||||
|
|
||||||
|
|
||||||
|
@section('gateway_head')
|
||||||
|
<meta name="authorize-public-key" content="{{ $public_client_id }}">
|
||||||
|
<meta name="authorize-login-id" content="{{ $api_login_id }}">
|
||||||
|
<meta name="instant-payment" content="yes">
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_content')
|
||||||
|
|
||||||
|
|
||||||
|
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::BANK_TRANSFER]) }}"
|
||||||
|
method="post" id="server_response">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
|
||||||
|
<input type="hidden" name="payment_method_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="dataValue" id="dataValue"/>
|
||||||
|
<input type="hidden" name="dataDescriptor" id="dataDescriptor"/>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="alert alert-failure mb-4" id="errors" hidden></div>
|
||||||
|
|
||||||
|
@include('portal.ninja2020.gateways.authorize.includes.ach_form')
|
||||||
|
|
||||||
|
@component('portal.ninja2020.gateways.includes.pay_now', ['id' => 'card_button'])
|
||||||
|
{{ ctrans('texts.add_payment_method') }}
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('footer')
|
||||||
|
|
||||||
|
@section('gateway_footer')
|
||||||
|
@if($gateway->company_gateway->getConfigField('testMode'))
|
||||||
|
<script src="https://jstest.authorize.net/v1/Accept.js" charset="utf-8"></script>
|
||||||
|
@else
|
||||||
|
<script src="https://js.authorize.net/v1/Accept.js" charset="utf-8"></script>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
|
||||||
|
@vite('resources/js/clients/payment_methods/authorize-authorize-ach.js')
|
||||||
|
@endsection
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.ach'), 'card_title' => ctrans('texts.bank_transfer')])
|
||||||
|
|
||||||
|
@section('gateway_head')
|
||||||
|
<meta name="authorize-public-key" content="{{ $public_client_id }}">
|
||||||
|
<meta name="authorize-login-id" content="{{ $api_login_id }}">
|
||||||
|
<meta name="instant-payment" content="yes" />
|
||||||
|
@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->company_gateway->id }}">
|
||||||
|
<input type="hidden" name="payment_method_id" value="2">
|
||||||
|
<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="hidden" name="amount_with_fee" id="amount_with_fee" value="{{ $total['amount_with_fee'] }}"/>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')])
|
||||||
|
{{ ctrans('texts.ach') }}
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@include('portal.ninja2020.gateways.includes.payment_details')
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
||||||
|
<ul class="list-none">
|
||||||
|
@if(count($tokens) > 0)
|
||||||
|
@foreach($tokens as $token)
|
||||||
|
<li class="py-2 cursor-pointer">
|
||||||
|
<label class="mr-4">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
data-token="{{ $token->hashed_id }}"
|
||||||
|
name="payment-type"
|
||||||
|
class="form-radio cursor-pointer toggle-payment-with-token"/>
|
||||||
|
<span class="ml-1 cursor-pointer">**** {{ $token->meta?->last4 }}</span>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
<li class="py-2 cursor-pointer">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
id="toggle-payment-with-ach"
|
||||||
|
class="form-radio cursor-pointer"
|
||||||
|
name="payment-type"
|
||||||
|
checked/>
|
||||||
|
<span class="ml-1 cursor-pointer">{{ __('texts.add_bank_account') }}</span>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@include('portal.ninja2020.gateways.authorize.includes.ach_form')
|
||||||
|
@include('portal.ninja2020.gateways.includes.pay_now')
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_footer')
|
||||||
|
@if($gateway->company_gateway->getConfigField('testMode'))
|
||||||
|
<script src="https://jstest.authorize.net/v1/Accept.js" charset="utf-8"></script>
|
||||||
|
@else
|
||||||
|
<script src="https://js.authorize.net/v1/Accept.js" charset="utf-8"></script>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@vite('resources/js/clients/payments/authorize-ach-payment.js')
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('footer')
|
||||||
|
@endpush
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<div id="authorize-ach-container">
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_holder_name')])
|
||||||
|
<input class="input w-full" id="account_holder_name" type="text" placeholder="{{ ctrans('texts.account_holder_name') }}"
|
||||||
|
maxlength="22" required>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_type')])
|
||||||
|
<span class="flex items-center mr-4">
|
||||||
|
<input class="form-radio mr-2" type="radio" value="checking" name="account_type" checked>
|
||||||
|
<span>Checking</span>
|
||||||
|
</span>
|
||||||
|
<span class="flex items-center mt-2">
|
||||||
|
<input class="form-radio mr-2" type="radio" value="savings" name="account_type">
|
||||||
|
<span>Savings</span>
|
||||||
|
</span>
|
||||||
|
<span class="flex items-center mt-2">
|
||||||
|
<input class="form-radio mr-2" type="radio" value="businessChecking" name="account_type">
|
||||||
|
<span>Business Checking</span>
|
||||||
|
</span>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.routing_number')])
|
||||||
|
<input class="input w-full" id="routing_number" type="text" pattern="[0-9]{9}"
|
||||||
|
minlength="9" maxlength="9" inputmode="numeric"
|
||||||
|
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
|
||||||
|
placeholder="9 digits" required>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.account_number')])
|
||||||
|
<input class="input w-full" id="account_number" type="text" pattern="[0-9]{1,17}"
|
||||||
|
minlength="1" maxlength="17" inputmode="numeric"
|
||||||
|
oninput="this.value = this.value.replace(/[^0-9]/g, '')"
|
||||||
|
placeholder="1-17 digits" required>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element-single')
|
||||||
|
<input type="checkbox" class="form-checkbox mr-1" id="accept-terms" required>
|
||||||
|
<label for="accept-terms" class="cursor-pointer">{{ ctrans('texts.ach_authorization', ['company' => auth()->guard('contact')->user()->company->present()->name, 'email' => auth()->guard('contact')->user()->client->company->settings->email]) }}</label>
|
||||||
|
@endcomponent
|
||||||
|
</div>
|
||||||
|
|
@ -8,7 +8,9 @@ export default defineConfig({
|
||||||
'resources/js/app.js',
|
'resources/js/app.js',
|
||||||
'resources/sass/app.scss',
|
'resources/sass/app.scss',
|
||||||
'resources/js/clients/payment_methods/authorize-authorize-card.js',
|
'resources/js/clients/payment_methods/authorize-authorize-card.js',
|
||||||
|
'resources/js/clients/payment_methods/authorize-authorize-ach.js',
|
||||||
'resources/js/clients/payments/authorize-credit-card-payment.js',
|
'resources/js/clients/payments/authorize-credit-card-payment.js',
|
||||||
|
'resources/js/clients/payments/authorize-ach-payment.js',
|
||||||
'resources/js/clients/payments/forte-credit-card-payment.js',
|
'resources/js/clients/payments/forte-credit-card-payment.js',
|
||||||
'resources/js/clients/payments/forte-ach-payment.js',
|
'resources/js/clients/payments/forte-ach-payment.js',
|
||||||
'resources/js/clients/payments/stripe-ach.js',
|
'resources/js/clients/payments/stripe-ach.js',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue