1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-08 20:22:42 +01:00

Authorize.net: New payment flow (#68)

* fixes for validation errors

* authorize.net

* pass livewirePaymentView & processPaymentView thru base driver

* add paymentData to the interface

* authorize.net credit card
This commit is contained in:
Benjamin Beganović 2024-08-09 01:07:23 +02:00
parent 364a57c857
commit e7f41c1dba
10 changed files with 156 additions and 90 deletions

View File

@ -21,6 +21,7 @@ use App\Models\PaymentHash;
use App\Models\PaymentType;
use App\Models\SystemLog;
use App\PaymentDrivers\AuthorizePaymentDriver;
use App\PaymentDrivers\Common\LivewireMethodInterface;
use App\Utils\Traits\MakesHash;
use net\authorize\api\contract\v1\DeleteCustomerPaymentProfileRequest;
use net\authorize\api\contract\v1\DeleteCustomerProfileRequest;
@ -30,7 +31,7 @@ use net\authorize\api\controller\DeleteCustomerProfileController;
/**
* Class AuthorizeCreditCard.
*/
class AuthorizeCreditCard
class AuthorizeCreditCard implements LivewireMethodInterface
{
use MakesHash;
@ -41,7 +42,7 @@ class AuthorizeCreditCard
$this->authorize = $authorize;
}
public function processPaymentView($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)
@ -54,6 +55,13 @@ class AuthorizeCreditCard
$data['public_client_id'] = $this->authorize->init()->getPublicClientKey();
$data['api_login_id'] = $this->authorize->company_gateway->getConfigField('apiLoginId');
return $data;
}
public function processPaymentView($data)
{
$data = $this->paymentData($data);
return render('gateways.authorize.credit_card.pay', $data);
}
@ -313,4 +321,9 @@ class AuthorizeCreditCard
'invoices' => $vars['invoices'],
];
}
public function livewirePaymentView(array $data): string
{
return 'gateways.authorize.credit_card.pay_livewire';
}
}

View File

@ -870,4 +870,14 @@ class BaseDriver extends AbstractPaymentDriver
{
}
public function livewirePaymentView(array $data): string
{
return $this->payment_method->livewirePaymentView($data);
}
public function processPaymentViewData(array $data): array
{
return $this->payment_method->paymentData($data);
}
}

View File

@ -108,7 +108,6 @@ class RFFService
if ($return_errors) {
return $validator->getMessageBag()->getMessages();
}
session()->flash('validation_errors', $validator->getMessageBag()->getMessages());
return false;

2
package-lock.json generated
View File

@ -1,5 +1,5 @@
{
"name": "invoiceninja",
"name": "@invoiceninja/invoiceninja",
"lockfileVersion": 2,
"requires": true,
"packages": {

File diff suppressed because one or more lines are too long

View File

@ -1,9 +0,0 @@
var l=Object.defineProperty;var c=(d,e,t)=>e in d?l(d,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):d[e]=t;var o=(d,e,t)=>(c(d,typeof e!="symbol"?e+"":e,t),t);/**
* 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 s{constructor(e,t){o(this,"handleAuthorization",()=>{if(m=="1"&&document.getElementById("cvv").value.length<3){var e=$("#errors");e.show().html("<p>CVV is required</p>"),document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden");return}var t=$("#my-card"),n={};n.clientKey=this.publicKey,n.apiLoginID=this.loginId;var a={};a.cardNumber=t.CardJs("cardNumber").replace(/[^\d]/g,""),a.month=t.CardJs("expiryMonth").replace(/[^\d]/g,""),a.year=t.CardJs("expiryYear").replace(/[^\d]/g,""),a.cardCode=document.getElementById("cvv").value.replace(/[^\d]/g,"");var r={};return r.authData=n,r.cardData=a,document.getElementById("pay-now")&&(document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden")),Accept.dispatchData(r,this.responseHandler),!1});o(this,"responseHandler",e=>{if(e.messages.resultCode==="Error"){var t=0,n=$("#errors");n.show().html("<p>"+e.messages.message[t].code+": "+e.messages.message[t].text+"</p>"),document.getElementById("pay-now").disabled=!1,document.querySelector("#pay-now > svg").classList.add("hidden"),document.querySelector("#pay-now > span").classList.remove("hidden")}else if(e.messages.resultCode==="Ok"){document.getElementById("dataDescriptor").value=e.opaqueData.dataDescriptor,document.getElementById("dataValue").value=e.opaqueData.dataValue;let a=document.querySelector("input[name=token-billing-checkbox]:checked");a&&(document.getElementById("store_card").value=a.value),document.getElementById("server_response").submit()}return!1});o(this,"handle",()=>{Array.from(document.getElementsByClassName("toggle-payment-with-token")).forEach(n=>n.addEventListener("click",a=>{document.getElementById("save-card--container").style.display="none",document.getElementById("authorize--credit-card-container").style.display="none",document.getElementById("token").value=a.target.dataset.token}));let e=document.getElementById("toggle-payment-with-credit-card");e&&e.addEventListener("click",()=>{document.getElementById("save-card--container").style.display="grid",document.getElementById("authorize--credit-card-container").style.display="flex",document.getElementById("token").value=null});let t=document.getElementById("pay-now");return t&&t.addEventListener("click",n=>{let a=document.getElementById("token");a.value?this.handlePayNowAction(a.value):this.handleAuthorization()}),this});this.publicKey=e,this.loginId=t,this.cardHolderName=document.getElementById("cardholder_name")}handlePayNowAction(e){document.getElementById("pay-now").disabled=!0,document.querySelector("#pay-now > svg").classList.remove("hidden"),document.querySelector("#pay-now > span").classList.add("hidden"),document.getElementById("token").value=e,document.getElementById("server_response").submit()}}const u=document.querySelector('meta[name="authorize-public-key"]').content,i=document.querySelector('meta[name="authorize-login-id"]').content,m=document.querySelector('meta[name="authnet-require-cvv"]').content;new s(u,i).handle();

View File

@ -67,7 +67,10 @@
"src": "resources/js/clients/payment_methods/wepay-bank-account.js"
},
"resources/js/clients/payments/authorize-credit-card-payment.js": {
"file": "assets/authorize-credit-card-payment-a217579b.js",
"file": "assets/authorize-credit-card-payment-5206050e.js",
"imports": [
"_wait-8f4ae121.js"
],
"isEntry": true,
"src": "resources/js/clients/payments/authorize-credit-card-payment.js"
},

View File

@ -5,40 +5,65 @@
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
* @license https://www.elastic.co/licensing/elastic-license
*/
class AuthorizeAuthorizeCard {
import { SimpleCard } from '@invoiceninja/simple-card';
import { wait, instant } from '../wait';
class AuthorizeAuthorizeCard {
constructor(publicKey, loginId) {
this.publicKey = publicKey;
this.loginId = loginId;
this.cardHolderName = document.getElementById("cardholder_name");
this.cardHolderName = document.getElementById('cardholder_name');
this.sc = new SimpleCard({
fields: {
card: {
number: '#number',
date: '#date',
cvv: '#cvv',
},
},
});
this.sc.mount();
this.cvvRequired = document.querySelector(
'meta[name="authnet-require-cvv"]'
).content;
}
handleAuthorization = () => {
if (cvvRequired == "1" && document.getElementById("cvv").value.length < 3) {
var $errors = $('#errors');
$errors.show().html("<p>CVV is required</p>");
if (
this.cvvRequired == '1' &&
document.getElementById('cvv').value.length < 3
) {
const $errors = document.getElementById('errors');
if ($errors) {
$errors.innerText = 'CVV is required';
$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');
document
.querySelector('#pay-now > span')
.classList.remove('hidden');
return;
}
var myCard = $('#my-card');
var authData = {};
authData.clientKey = this.publicKey;
authData.apiLoginID = this.loginId;
var cardData = {};
cardData.cardNumber = myCard.CardJs('cardNumber').replace(/[^\d]/g, '');
cardData.month = myCard.CardJs('expiryMonth').replace(/[^\d]/g, '');
cardData.year = myCard.CardJs('expiryYear').replace(/[^\d]/g, '');
cardData.cardCode = document.getElementById("cvv").value.replace(/[^\d]/g, '');
cardData.cardNumber = this.sc.value('number')?.replace(/[^\d]/g, '');
cardData.month = this.sc.value('month')?.replace(/[^\d]/g, '');
cardData.year = `20${this.sc.value('year')?.replace(/[^\d]/g, '')}`;
cardData.cardCode = this.sc.value('cvv')?.replace(/[^\d]/g, '');
var secureData = {};
secureData.authData = authData;
@ -58,102 +83,112 @@ class AuthorizeAuthorizeCard {
Accept.dispatchData(secureData, this.responseHandler);
return false;
}
};
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();
document.getElementById('token').value = token_hashed_id;
document.getElementById('server_response').submit();
}
responseHandler = (response) => {
if (response.messages.resultCode === "Error") {
if (response.messages.resultCode === 'Error') {
var i = 0;
var $errors = $('#errors'); // get the reference of the div
$errors.show().html("<p>" + response.messages.message[i].code + ": " + response.messages.message[i].text + "</p>");
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
.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;
document.getElementById("dataDescriptor").value = response.opaqueData.dataDescriptor;
document.getElementById("dataValue").value = response.opaqueData.dataValue;
let storeCard = document.querySelector('input[name=token-billing-checkbox]:checked');
let storeCard = document.querySelector(
'input[name=token-billing-checkbox]:checked'
);
if (storeCard) {
document.getElementById("store_card").value = storeCard.value;
document.getElementById('store_card').value = storeCard.value;
}
document.getElementById("server_response").submit();
document.getElementById('server_response').submit();
}
return false;
}
};
handle = () => {
Array
.from(document.getElementsByClassName('toggle-payment-with-token'))
.forEach((element) => element.addEventListener('click', (e) => {
document
.getElementById('save-card--container').style.display = 'none';
document
.getElementById('authorize--credit-card-container').style.display = 'none';
Array.from(
document.getElementsByClassName('toggle-payment-with-token')
).forEach((element) =>
element.addEventListener('click', (e) => {
document.getElementById('save-card--container').style.display =
'none';
document.getElementById(
'authorize--credit-card-container'
).style.display = 'none';
document
.getElementById('token').value = e.target.dataset.token;
}));
document.getElementById('token').value = e.target.dataset.token;
})
);
let payWithCreditCardToggle = document.getElementById('toggle-payment-with-credit-card');
let payWithCreditCardToggle = document.getElementById(
'toggle-payment-with-credit-card'
);
if (payWithCreditCardToggle) {
payWithCreditCardToggle
.addEventListener('click', () => {
document
.getElementById('save-card--container').style.display = 'grid';
document
.getElementById('authorize--credit-card-container').style.display = 'flex';
payWithCreditCardToggle.addEventListener('click', () => {
document.getElementById('save-card--container').style.display =
'grid';
document.getElementById(
'authorize--credit-card-container'
).style.display = 'flex';
document
.getElementById('token').value = null;
});
document.getElementById('token').value = null;
});
}
let payNowButton = document.getElementById('pay-now');
if (payNowButton) {
payNowButton
.addEventListener('click', (e) => {
let token = document.getElementById('token');
payNowButton.addEventListener('click', (e) => {
let token = document.getElementById('token');
token.value
? this.handlePayNowAction(token.value)
: this.handleAuthorization();
});
token.value
? this.handlePayNowAction(token.value)
: this.handleAuthorization();
});
}
return this;
}
};
}
const publicKey = document.querySelector(
'meta[name="authorize-public-key"]'
).content;
function boot() {
const publicKey = document.querySelector(
'meta[name="authorize-public-key"]'
).content;
const loginId = document.querySelector(
'meta[name="authorize-login-id"]'
).content;
const loginId = document.querySelector(
'meta[name="authorize-login-id"]'
).content;
const cvvRequired = document.querySelector(
'meta[name="authnet-require-cvv"]'
).content;
/** @handle */
new AuthorizeAuthorizeCard(publicKey, loginId).handle();
}
instant() ? boot() : wait('#authorize-net-credit-card-payment').then(() => boot());
/** @handle */
new AuthorizeAuthorizeCard(publicKey, loginId).handle();

View File

@ -3,6 +3,7 @@
@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" />
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<meta name="authnet-require-cvv" content="{{ $gateway->company_gateway->require_cvv }}">

View File

@ -1,11 +1,13 @@
<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" name="card-number">
<input class="expiry-month" name="expiry-month" id="expiration_month" autocomplete="cc-exp-month" x-autocompletetype="cc-exp-month">
<input class="expiry-year" name="expiry-year" id="expiration_year" autocomplete="cc-exp-year" x-autocompletetype="cc-exp-year">
<input class="cvc" name="cvc" id="cvv">
<div class="card-js" id="my-card" data-capture-name="true">
<input class="input w-full" id="cardholder_name" name="card_holders_name"
placeholder="{{ ctrans('texts.name')}}">
<input type="text" class="input w-full" id="number" placeholder="0000 0000 0000 0000">
<div class="flex items-center gap-2">
<input type="text" class="input w-1/2" id="date" placeholder="MM/YY">
<input type="text" class="input w-1/2" id="cvv" placeholder="000">
</div>
</div>
<div id="errors"></div>