mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
fixes for storing credit card tokens with square
This commit is contained in:
parent
d126efe9f5
commit
3b891612a2
@ -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();
|
||||
|
119
public/js/clients/payments/square-credit-card.js
vendored
119
public/js/clients/payments/square-credit-card.js
vendored
@ -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);
|
||||
|
@ -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
|
||||
});
|
||||
|
@ -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",
|
||||
|
@ -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();
|
||||
}
|
||||
// }
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@ class StripeCreditCard {
|
||||
setupStripe() {
|
||||
|
||||
if (this.stripeConnect){
|
||||
// this.stripe.stripeAccount = this.stripeConnect;
|
||||
|
||||
this.stripe = Stripe(this.key, {
|
||||
stripeAccount: this.stripeConnect,
|
||||
|
@ -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')
|
||||
|
@ -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');
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user