fixes for storing credit card tokens with square

This commit is contained in:
David Bomba 2023-07-07 12:24:09 +10:00
parent d126efe9f5
commit 3b891612a2
8 changed files with 193 additions and 78 deletions

View File

@ -12,6 +12,7 @@
namespace App\PaymentDrivers\Square;
use App\Exceptions\PaymentFailed;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\Models\ClientGatewayToken;
use App\Models\GatewayType;
@ -113,18 +114,23 @@ class CreditCard implements MethodInterface
$body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId'));
$body->setReferenceId(Str::random(16));
if ($request->has('verificationToken') && $request->input('verificationToken')) {
$body->setVerificationToken($request->input('verificationToken'));
}
if ($request->shouldUseToken()) {
$body->setCustomerId($cgt->gateway_customer_reference);
}elseif ($request->has('verificationToken') && $request->input('verificationToken')) {
$body->setVerificationToken($request->input('verificationToken'));
}
/** @var ApiResponse */
$response = $this->square_driver->square->getPaymentsApi()->createPayment($body);
if ($response->isSuccess()) {
$body = json_decode($response->getBody());
if($request->store_card){
$this->createCard($body->payment->id);
}
return $this->processSuccessfulPayment($response);
}
@ -161,6 +167,52 @@ class CreditCard implements MethodInterface
return $this->square_driver->processUnsuccessfulTransaction($data);
}
private function createCard($source_id)
{
$square_card = new \Square\Models\Card();
$square_card->setCustomerId($this->findOrCreateClient());
$body = new \Square\Models\CreateCardRequest(uniqid("st", true), $source_id, $square_card);
$api_response = $this->square_driver
->init()
->square
->getCardsApi()
->createCard($body);
$body = json_decode($api_response->getBody());
if ($api_response->isSuccess()) {
try {
$payment_meta = new \stdClass;
$payment_meta->exp_month = (string) $body->card->exp_month;
$payment_meta->exp_year = (string) $body->card->exp_year;
$payment_meta->brand = (string) $body->card->card_brand;
$payment_meta->last4 = (string) $body->card->last_4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$data = [
'payment_meta' => $payment_meta,
'token' => $body->card->id,
'payment_method_id' => GatewayType::CREDIT_CARD,
];
$this->square_driver->storeGatewayToken($data, ['gateway_customer_reference' => $body->card->customer_id]);
} catch (\Exception $e) {
return $this->square_driver->processInternallyFailedPayment($this->square_driver, $e);
}
}
else {
throw new PaymentFailed($body->errors[0]->detail, 500);
}
return false;
}
private function findOrCreateClient()
{
$email_address = new \Square\Models\CustomerTextFilter();

View File

@ -176,62 +176,79 @@ var SquareCreditCard = /*#__PURE__*/function () {
}, {
key: "handle",
value: function () {
var _handle = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() {
var _document$getElementB,
_this = this,
_document$getElementB2,
_document$getElementB3;
var toggleWithToken, _document$getElementB4;
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
var _handle = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7() {
var _this = this;
return _regeneratorRuntime().wrap(function _callee7$(_context7) {
while (1) switch (_context7.prev = _context7.next) {
case 0:
_context6.next = 2;
return this.init();
case 2:
(_document$getElementB = document.getElementById('authorize-card')) === null || _document$getElementB === void 0 ? void 0 : _document$getElementB.addEventListener('click', function (e) {
return _this.completePaymentWithoutToken(e);
});
(_document$getElementB2 = document.getElementById('pay-now')) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.addEventListener('click', function (e) {
var tokenInput = document.querySelector('input[name=token]');
if (tokenInput.value) {
return _this.completePaymentUsingToken(e);
}
return _this.completePaymentWithoutToken(e);
});
Array.from(document.getElementsByClassName('toggle-payment-with-token')).forEach(function (element) {
return element.addEventListener('click', function (element) {
document.getElementById('card-container').classList.add('hidden');
document.getElementById('save-card--container').style.display = 'none';
document.querySelector('input[name=token]').value = element.target.dataset.token;
document.getElementById('payment-list').classList.add('hidden');
_context7.next = 3;
return this.init().then(function () {
var _document$getElementB, _document$getElementB2, _document$getElementB3, _document$getElementB4;
(_document$getElementB = document.getElementById('authorize-card')) === null || _document$getElementB === void 0 ? void 0 : _document$getElementB.addEventListener('click', function (e) {
return _this.completePaymentWithoutToken(e);
});
});
(_document$getElementB3 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB3 === void 0 ? void 0 : _document$getElementB3.addEventListener('click', /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(element) {
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
document.getElementById('card-container').classList.remove('hidden');
document.getElementById('save-card--container').style.display = 'grid';
document.querySelector('input[name=token]').value = '';
case 3:
case "end":
return _context5.stop();
}
}, _callee5);
}));
return function (_x4) {
return _ref.apply(this, arguments);
};
}());
toggleWithToken = document.querySelector('.toggle-payment-with-token');
if (!toggleWithToken) {
(_document$getElementB2 = document.getElementById('pay-now')) === null || _document$getElementB2 === void 0 ? void 0 : _document$getElementB2.addEventListener('click', function (e) {
var tokenInput = document.querySelector('input[name=token]');
if (tokenInput.value) {
return _this.completePaymentUsingToken(e);
}
return _this.completePaymentWithoutToken(e);
});
Array.from(document.getElementsByClassName('toggle-payment-with-token')).forEach(function (element) {
return element.addEventListener('click', /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(element) {
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
document.getElementById('card-container').classList.add('hidden');
document.getElementById('save-card--container').style.display = 'none';
document.querySelector('input[name=token]').value = element.target.dataset.token;
case 3:
case "end":
return _context5.stop();
}
}, _callee5);
}));
return function (_x4) {
return _ref.apply(this, arguments);
};
}());
});
(_document$getElementB3 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB3 === void 0 ? void 0 : _document$getElementB3.addEventListener('click', /*#__PURE__*/function () {
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(element) {
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
case 0:
document.getElementById('card-container').classList.remove('hidden');
document.getElementById('save-card--container').style.display = 'grid';
document.querySelector('input[name=token]').value = '';
case 3:
case "end":
return _context6.stop();
}
}, _callee6);
}));
return function (_x5) {
return _ref2.apply(this, arguments);
};
}());
// let toggleWithToken = document.querySelector(
// '.toggle-payment-with-token'
// );
// if (!toggleWithToken) {
document.getElementById('loader').classList.add('hidden');
document.getElementById('payment-list').classList.remove('hidden');
(_document$getElementB4 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB4 === void 0 ? void 0 : _document$getElementB4.click();
}
case 8:
// }
});
case 3:
case "end":
return _context6.stop();
return _context7.stop();
}
}, _callee6, this);
}, _callee7, this);
}));
function handle() {
return _handle.apply(this, arguments);

View File

@ -31,8 +31,6 @@ var StripeCreditCard = /*#__PURE__*/function () {
key: "setupStripe",
value: function setupStripe() {
if (this.stripeConnect) {
// this.stripe.stripeAccount = this.stripeConnect;
this.stripe = Stripe(this.key, {
stripeAccount: this.stripeConnect
});

View File

@ -16,7 +16,7 @@
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=a2168c43060a7de40da20b5fc599bcab",
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=4158693089b29ee8e13cb7d9ce4480a9",
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=4e596cec23cdd6487534e6ed5499d791",
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=b483e14d15000c04edfe4c9c80fb97c9",
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=bfa116c1df42c641bc7a3ff4fa8d50dd",
"/js/setup/setup.js": "/js/setup/setup.js?id=086b9e114b0b9ee01f909d686f489162",
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=cf50b5ba1fcd1d184bf0c10d710672c8",
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=c9593b44d66f89874d13f99bc3e6ff33",
@ -30,7 +30,7 @@
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=2f72b969507e6135b5c52a65522ab3ae",
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=0d1c8957b02c5601b7d57c39740bff75",
"/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=2f8e5af9ba5ce266d2ee49b084fbe291",
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=dbd7a15777def575562153c984dee08a",
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=a5e1407a161c3c72545d125dd1100571",
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=bd92ab50acabf1cc5232912d53edc5e1",
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=46e14d31acaf3adf58444a5de4b4122c",
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=ef15c0865a29c3c17f2ad185cad0d28e",

View File

@ -125,7 +125,10 @@ class SquareCreditCard {
}
async handle() {
await this.init();
document.getElementById('payment-list').classList.add('hidden');
await this.init().then(() => {
document
.getElementById('authorize-card')
@ -146,7 +149,7 @@ class SquareCreditCard {
Array.from(
document.getElementsByClassName('toggle-payment-with-token')
).forEach((element) =>
element.addEventListener('click', (element) => {
element.addEventListener('click', async (element) => {
document
.getElementById('card-container')
.classList.add('hidden');
@ -168,13 +171,17 @@ class SquareCreditCard {
document.querySelector('input[name=token]').value = '';
});
let toggleWithToken = document.querySelector(
'.toggle-payment-with-token'
);
// let toggleWithToken = document.querySelector(
// '.toggle-payment-with-token'
// );
if (!toggleWithToken) {
// if (!toggleWithToken) {
document.getElementById('loader').classList.add('hidden');
document.getElementById('payment-list').classList.remove('hidden');
document.getElementById('toggle-payment-with-credit-card')?.click();
}
// }
});
}
}

View File

@ -19,7 +19,6 @@ class StripeCreditCard {
setupStripe() {
if (this.stripeConnect){
// this.stripe.stripeAccount = this.stripeConnect;
this.stripe = Stripe(this.key, {
stripeAccount: this.stripeConnect,

View File

@ -7,7 +7,32 @@
<meta name="square_contact" content="{{ json_encode($square_contact) }}">
<meta name="amount" content="{{ $amount }}">
<meta name="currencyCode" content="{{ $currencyCode }}">
<style>
.loader {
border-top-color: #3498db;
-webkit-animation: spinner 1.5s linear infinite;
animation: spinner 1.5s linear infinite;
}
@-webkit-keyframes spinner {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
@endsection
@section('gateway_content')
@ -33,23 +58,41 @@
@include('portal.ninja2020.gateways.includes.payment_details')
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
<div class="flex flex-col" id="loader">
<div class="loader ease-linear rounded-full border-4 border-t-4 border-gray-200 h-12 w-12 mb-4"></div>
</div>
<ul class="list-none hover:list-disc " id="payment-list">
@if (count($tokens) > 0)
@foreach ($tokens as $token)
@foreach($tokens as $token)
<li class="py-2 hover:text-blue hover:bg-blue-600">
<label class="mr-4">
<input type="radio" data-token="{{ $token->token }}" name="payment-type"
class="form-radio cursor-pointer toggle-payment-with-token" />
<span class="ml-1 cursor-pointer">**** {{ $token->meta?->last4 }}</span>
<input
type="radio"
data-token="{{ $token->token }}"
name="payment-type"
class="form-check-input text-indigo-600 rounded-full cursor-pointer toggle-payment-with-token toggle-payment-with-token"
/>
<span class="ml-1 cursor-pointer">**** {{ $token->meta?->last4 }} - {{ $token->meta?->exp_month ?? 'xx' }}/{{ $token->meta?->exp_year ?? 'xx' }}</span>
</label>
</li>
@endforeach
@endisset
<label>
<input type="radio" id="toggle-payment-with-credit-card" class="form-radio cursor-pointer" name="payment-type"
checked />
<span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span>
</label>
<li class="py-2 hover:text-blue hover:bg-blue-600">
<label>
<input
type="radio"
id="toggle-payment-with-credit-card"
class="form-check-input text-indigo-600 rounded-full cursor-pointer"
name="payment-type"
checked/>
<span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span>
</label>
</li>
</ul>
@endcomponent
@include('portal.ninja2020.gateways.includes.save_card')

View File

@ -141,7 +141,6 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
Route::get('activities', [ActivityController::class, 'index']);
Route::get('activities/download_entity/{activity}', [ActivityController::class, 'downloadHistoricalEntity']);
Route::post('charts/totals', [ChartController::class, 'totals'])->name('chart.totals');
Route::post('charts/chart_summary', [ChartController::class, 'chart_summary'])->name('chart.chart_summary');