Square payments authorize

This commit is contained in:
= 2021-08-14 21:00:52 +10:00
parent 5c8976a50f
commit 19e9aac12b
2 changed files with 330 additions and 57 deletions

View File

@ -31,17 +31,17 @@ class CreditCard
{
use MakesHash;
public $square_class;
public $square_driver;
public function __construct(SquarePaymentDriver $square_class)
public function __construct(SquarePaymentDriver $square_driver)
{
$this->square_class = $square_class;
$this->square_driver = $square_driver;
}
public function authorizeView($data)
{
$data['gateway'] = $this->square_class;
$data['gateway'] = $this->square_driver;
return render('gateways.square.credit_card.authorize', $data);
@ -49,28 +49,21 @@ class CreditCard
public function authorizeRequest($request)
{
$amount_money = new \Square\Models\Money();
$amount_money->setAmount(100); //amount in cents
$amount_money->setCurrency($this->square_driver->client->currency()->code);
$billing_address = new \Square\Models\Address();
$billing_address->setAddressLine1($this->square_class->client->address1);
$billing_address->setAddressLine2($this->square_class->client->address2);
$billing_address->setLocality($this->square_class->client->city);
$billing_address->setAdministrativeDistrictLevel1($this->square_class->client->state);
$billing_address->setPostalCode($this->square_class->client->postal_code);
$billing_address->setCountry($this->square_class->client->country->iso_3166_2);
$card = new \Square\Models\Card();
$card->setCardholderName('Amelia Earhart');
$card->setBillingAddress($billing_address);
$card->setCustomerId('VDKXEEKPJN48QDG3BGGFAK05P8');
$card->setReferenceId('user-id-1');
$body = new \Square\Models\CreateCardRequest(
'4935a656-a929-4792-b97c-8848be85c27c',
'cnon:uIbfJXhXETSP197M3GB',
$card
$body = new \Square\Models\CreatePaymentRequest(
$request->sourceId,
Str::random(32),
$amount_money
);
$api_response = $client->getCardsApi()->createCard($body);
$body->setAutocomplete(false);
$body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId'));
$body->setReferenceId(Str::random(16));
$api_response = $client->getPaymentsApi()->createPayment($body);
if ($api_response->isSuccess()) {
$result = $api_response->getResult();
@ -79,13 +72,179 @@ class CreditCard
}
/*
Success response looks like this:
{
"payment": {
"id": "Dv9xlBgSgVB8i6eT0imRYFjcrOaZY",
"created_at": "2021-03-31T20:56:13.220Z",
"updated_at": "2021-03-31T20:56:13.411Z",
"amount_money": {
"amount": 100,
"currency": "USD"
},
"status": "COMPLETED",
"delay_duration": "PT168H",
"source_type": "CARD",
"card_details": {
"status": "CAPTURED",
"card": {
"card_brand": "AMERICAN_EXPRESS",
"last_4": "6550",
"exp_month": 3,
"exp_year": 2023,
"fingerprint": "sq-1-hPdOWUYtEMft3yQ",
"card_type": "CREDIT",
"prepaid_type": "NOT_PREPAID",
"bin": "371263"
},
"entry_method": "KEYED",
"cvv_status": "CVV_ACCEPTED",
"avs_status": "AVS_ACCEPTED",
"statement_description": "SQ *DEFAULT TEST ACCOUNT",
"card_payment_timeline": {
"authorized_at": "2021-03-31T20:56:13.334Z",
"captured_at": "2021-03-31T20:56:13.411Z"
}
},
"location_id": "VJN4XSBFTVPK9",
"total_money": {
"amount": 100,
"currency": "USD"
},
"approved_money": {
"amount": 100,
"currency": "USD"
}
}
}
*/
$billing_address = new \Square\Models\Address();
$billing_address->setAddressLine1($this->square_driver->client->address1);
$billing_address->setAddressLine2($this->square_driver->client->address2);
$billing_address->setLocality($this->square_driver->client->city);
$billing_address->setAdministrativeDistrictLevel1($this->square_driver->client->state);
$billing_address->setPostalCode($this->square_driver->client->postal_code);
$billing_address->setCountry($this->square_driver->client->country->iso_3166_2);
$body = new \Square\Models\CreateCustomerRequest();
$body->setGivenName($this->square_driver->client->present()->name());
$body->setFamilyName('');
$body->setEmailAddress($this->square_driver->client->present()->email());
$body->setAddress($address);
$body->setPhoneNumber($this->square_driver->client->phone);
$body->setReferenceId($this->square_driver->client->number);
$body->setNote('Created by Invoice Ninja.');
$api_response = $this->square_driver
->square
->getCustomersApi()
->createCustomer($body);
if ($api_response->isSuccess()) {
$result = $api_response->getResult();
} else {
$errors = $api_response->getErrors();
}
/*Customer now created response
{
"customer": {
"id": "Q6VKKKGW8GWQNEYMDRMV01QMK8",
"created_at": "2021-03-31T18:27:07.803Z",
"updated_at": "2021-03-31T18:27:07Z",
"given_name": "Amelia",
"family_name": "Earhart",
"email_address": "Amelia.Earhart@example.com",
"preferences": {
"email_unsubscribed": false
}
}
}
*/
$card = new \Square\Models\Card();
$card->setCardholderName($this->square_driver->client->present()->name());
$card->setBillingAddress($address);
$card->setCustomerId($result->customer->id);
$card->setReferenceId(Str::random(8));
$body = new \Square\Models\CreateCardRequest(
Str::random(32),
$request->sourceId,
$card
);
$api_response = $client->getCardsApi()->createCard($body);
if ($api_response->isSuccess()) {
$result = $api_response->getResult();
} else {
$errors = $api_response->getErrors();
}
/**
*
{
"card": {
"id": "ccof:uIbfJXhXETSP197M3GB", //this is the token
"billing_address": {
"address_line_1": "500 Electric Ave",
"address_line_2": "Suite 600",
"locality": "New York",
"administrative_district_level_1": "NY",
"postal_code": "10003",
"country": "US"
},
"bin": "411111",
"card_brand": "VISA",
"card_type": "CREDIT",
"cardholder_name": "Amelia Earhart",
"customer_id": "Q6VKKKGW8GWQNEYMDRMV01QMK8",
"enabled": true,
"exp_month": 11,
"exp_year": 2018,
"last_4": "1111",
"prepaid_type": "NOT_PREPAID",
"reference_id": "user-id-1",
"version": 1
}
}
*/
$cgt = [];
$cgt['token'] = $result->card->id;
$cgt['payment_method_id'] = GatewayType::CREDIT_CARD;
$payment_meta = new \stdClass;
$payment_meta->exp_month = $result->card->exp_month;
$payment_meta->exp_year = $result->card->exp_year;
$payment_meta->brand = $result->card->card_brand;
$payment_meta->last4 = $result->card->last_4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$cgt['payment_meta'] = $payment_meta;
$token = $this->square_driver->storeGatewayToken($cgt, []);
return back();
}
public function paymentView($data)
{
$data['gateway'] = $this->square_class;
$data['gateway'] = $this->square_driver;
$data['client_token'] = $this->braintree->gateway->clientToken()->generate();
return render('gateways.braintree.credit_card.pay', $data);
@ -100,7 +259,7 @@ class CreditCard
/* This method is stubbed ready to go - you just need to harvest the equivalent 'transaction_reference' */
private function processSuccessfulPayment($response)
{
$amount = array_sum(array_column($this->square_class->payment_hash->invoices(), 'amount')) + $this->square_class->payment_hash->fee_total;
$amount = array_sum(array_column($this->square_driver->payment_hash->invoices(), 'amount')) + $this->square_driver->payment_hash->fee_total;
$payment_record = [];
$payment_record['amount'] = $amount;
@ -108,7 +267,7 @@ class CreditCard
$payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD;
// $payment_record['transaction_reference'] = $response->transaction_id;
$payment = $this->square_class->createPayment($payment_record, Payment::STATUS_COMPLETED);
$payment = $this->square_driver->createPayment($payment_record, Payment::STATUS_COMPLETED);
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
@ -130,7 +289,7 @@ class CreditCard
'error_code' => $error_code,
];
return $this->square_class->processUnsuccessfulTransaction($data);
return $this->square_driver->processUnsuccessfulTransaction($data);
}

View File

@ -8,45 +8,138 @@
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::CREDIT_CARD]) }}"
method="post" id="server_response">
@csrf
<input type="txt" id=HPF_Token name= HPF_Token hidden>
<input type="txt" id=enc_key name= enc_key hidden>
<input type="text" name="token" hidden>
<input type="text" name="sourceId" hidden>
<div class="alert alert-failure mb-4" hidden id="errors"></div>
@component('portal.ninja2020.components.general.card-element-single')
<div id="card-container"></div>
<button id="card-button" type="button">Add</button>
<div id="payment-status-container"></div>
</form>
@endcomponent
@component('portal.ninja2020.gateways.includes.pay_now')
{{ ctrans('texts.add_payment_method') }}
@endcomponent
@endsection
@section('gateway_footer')
<script type="text/javascript" src="https://sandbox.web.squarecdn.com/v1/square.js"></script>.
<script
type="text/javascript"
src="https://sandbox.web.squarecdn.com/v1/square.js"
></script>
<script>
const appId = "{{ $gateway->company_gateway->getConfigField('applicationId') }}";
const locationId = "{{ $gateway->company_gateway->getConfigField('locationId') }}";
const darkModeCardStyle = {
'.input-container': {
borderColor: '#2D2D2D',
borderRadius: '6px',
},
'.input-container.is-focus': {
borderColor: '#006AFF',
},
'.input-container.is-error': {
borderColor: '#ff1600',
},
'.message-text': {
color: '#999999',
},
'.message-icon': {
color: '#999999',
},
'.message-text.is-error': {
color: '#ff1600',
},
'.message-icon.is-error': {
color: '#ff1600',
},
input: {
backgroundColor: '#2D2D2D',
color: '#FFFFFF',
fontFamily: 'helvetica neue, sans-serif',
},
'input::placeholder': {
color: '#999999',
},
'input.is-error': {
color: '#ff1600',
},
};
async function initializeCard(payments) {
const card = await payments.card();
const card = await payments.card({
style: darkModeCardStyle,
});
await card.attach('#card-container');
return card;
}
document.addEventListener('DOMContentLoaded', async function () {
async function createPayment(token) {
document.getElementById('sourceId').value = token;
document.getElementById('server_response').submit();
const errorBody = await paymentResponse.text();
throw new Error(errorBody);
}
async function tokenize(paymentMethod) {
const tokenResult = await paymentMethod.tokenize();
if (tokenResult.status === 'OK') {
return tokenResult.token;
} else {
let errorMessage = `Tokenization failed with status: ${tokenResult.status}`;
if (tokenResult.errors) {
errorMessage += ` and errors: ${JSON.stringify(
tokenResult.errors
)}`;
}
throw new Error(errorMessage);
}
}
// status is either SUCCESS or FAILURE;
function displayPaymentResults(status) {
const statusContainer = document.getElementById(
'payment-status-container'
);
if (status === 'SUCCESS') {
statusContainer.classList.remove('is-failure');
statusContainer.classList.add('is-success');
} else {
statusContainer.classList.remove('is-success');
statusContainer.classList.add('is-failure');
}
statusContainer.style.visibility = 'visible';
}
document.addEventListener('DOMContentLoaded', async function () {
if (!window.Square) {
throw new Error('Square.js failed to load properly');
}
const payments = window.Square.payments(appId, locationId);
let card;
let payments;
try {
payments = window.Square.payments(appId, locationId);
} catch {
const statusContainer = document.getElementById(
'payment-status-container'
);
statusContainer.className = 'missing-credentials';
statusContainer.style.visibility = 'visible';
return;
}
let card;
try {
card = await initializeCard(payments);
} catch (e) {
@ -54,7 +147,28 @@
return;
}
// Step 5.2: create card payment
async function handlePaymentMethodSubmission(event, paymentMethod) {
event.preventDefault();
try {
// disable the submit button as we await tokenization and make a payment request.
cardButton.disabled = true;
const token = await tokenize(paymentMethod);
const paymentResults = await createPayment(token);
displayPaymentResults('SUCCESS');
console.debug('Payment Success', paymentResults);
} catch (e) {
cardButton.disabled = false;
displayPaymentResults('FAILURE');
console.error(e.message);
}
}
const cardButton = document.getElementById('pay-now');
cardButton.addEventListener('click', async function (event) {
await handlePaymentMethodSubmission(event, card);
});
});
</script>