mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-11 05:32:39 +01:00
commit
398382fb69
@ -787,6 +787,27 @@ class CreateSingleAccount extends Command
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
if (config('ninja.testvars.square') && ($this->gateway == 'all' || $this->gateway == 'square')) {
|
||||
$cg = new CompanyGateway;
|
||||
$cg->company_id = $company->id;
|
||||
$cg->user_id = $user->id;
|
||||
$cg->gateway_key = '65faab2ab6e3223dbe848b1686490baz';
|
||||
$cg->require_cvv = true;
|
||||
$cg->require_billing_address = true;
|
||||
$cg->require_shipping_address = true;
|
||||
$cg->update_details = true;
|
||||
$cg->config = encrypt(config('ninja.testvars.square'));
|
||||
$cg->save();
|
||||
|
||||
$gateway_types = $cg->driver(new Client)->gatewayTypes();
|
||||
|
||||
$fees_and_limits = new stdClass;
|
||||
$fees_and_limits->{$gateway_types[0]} = new FeesAndLimits;
|
||||
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
}
|
||||
|
||||
private function createRecurringInvoice($client)
|
||||
|
@ -81,9 +81,13 @@ class Gateway extends StaticModel
|
||||
case 1:
|
||||
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]];//Authorize.net
|
||||
break;
|
||||
case 1:
|
||||
case 11:
|
||||
return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false]];//Payfast
|
||||
break;
|
||||
case 7:
|
||||
return [
|
||||
GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true], // Mollie
|
||||
];
|
||||
case 15:
|
||||
return [GatewayType::PAYPAL => ['refund' => true, 'token_billing' => false]]; //Paypal
|
||||
break;
|
||||
@ -110,11 +114,12 @@ class Gateway extends StaticModel
|
||||
GatewayType::PAYPAL => ['refund' => true, 'token_billing' => true]
|
||||
];
|
||||
break;
|
||||
case 7:
|
||||
case 57:
|
||||
return [
|
||||
GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true], // Mollie
|
||||
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], //Square
|
||||
];
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
return [];
|
||||
break;
|
||||
|
@ -70,7 +70,8 @@ class SystemLog extends Model
|
||||
const TYPE_PAYFAST = 310;
|
||||
const TYPE_PAYTRACE = 311;
|
||||
const TYPE_MOLLIE = 312;
|
||||
|
||||
const TYPE_SQUARE = 320;
|
||||
|
||||
const TYPE_QUOTA_EXCEEDED = 400;
|
||||
const TYPE_UPSTREAM_FAILURE = 401;
|
||||
|
||||
|
328
app/PaymentDrivers/Square/CreditCard.php
Normal file
328
app/PaymentDrivers/Square/CreditCard.php
Normal file
@ -0,0 +1,328 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\Square;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\SquarePaymentDriver;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class CreditCard
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $square_driver;
|
||||
|
||||
public function __construct(SquarePaymentDriver $square_driver)
|
||||
{
|
||||
$this->square_driver = $square_driver;
|
||||
$this->square_driver->init();
|
||||
}
|
||||
|
||||
public function authorizeView($data)
|
||||
{
|
||||
|
||||
$data['gateway'] = $this->square_driver;
|
||||
|
||||
return render('gateways.square.credit_card.authorize', $data);
|
||||
|
||||
}
|
||||
|
||||
public function authorizeResponse($request)
|
||||
{
|
||||
$payment = false;
|
||||
|
||||
$amount_money = new \Square\Models\Money();
|
||||
$amount_money->setAmount(100); //amount in cents
|
||||
$amount_money->setCurrency($this->square_driver->client->currency()->code);
|
||||
|
||||
$body = new \Square\Models\CreatePaymentRequest(
|
||||
$request->sourceId,
|
||||
Str::random(32),
|
||||
$amount_money
|
||||
);
|
||||
|
||||
$body->setAutocomplete(false);
|
||||
$body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId'));
|
||||
$body->setReferenceId(Str::random(16));
|
||||
|
||||
$api_response = $this->square_driver->square->getPaymentsApi()->createPayment($body);
|
||||
|
||||
if ($api_response->isSuccess()) {
|
||||
// $result = $api_response->getResult();
|
||||
|
||||
$result = $api_response->getBody();
|
||||
$payment = json_decode($result);
|
||||
|
||||
} else {
|
||||
$errors = $api_response->getErrors();
|
||||
nlog($errors);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
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($billing_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();
|
||||
nlog($result);
|
||||
} else {
|
||||
$errors = $api_response->getErrors();
|
||||
nlog($errors);
|
||||
}
|
||||
|
||||
/*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($billing_address);
|
||||
$card->setCustomerId($result->getCustomer()->getId());
|
||||
$card->setReferenceId(Str::random(8));
|
||||
|
||||
$body = new \Square\Models\CreateCardRequest(
|
||||
Str::random(32),
|
||||
$payment->payment->id,
|
||||
$card
|
||||
);
|
||||
|
||||
$api_response = $this->square_driver
|
||||
->square
|
||||
->getCardsApi()
|
||||
->createCard($body);
|
||||
|
||||
if ($api_response->isSuccess()) {
|
||||
$result = $api_response->getResult();
|
||||
nlog($result->getBody());
|
||||
nlog("ressy");
|
||||
nlog($result);
|
||||
} else {
|
||||
$errors = $api_response->getErrors();
|
||||
nlog("i got errors");
|
||||
nlog($errors);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
{
|
||||
"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->getId();
|
||||
$cgt['payment_method_id'] = GatewayType::CREDIT_CARD;
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->exp_month = $result->getExpMonth();
|
||||
$payment_meta->exp_year = $result->getExpYear();
|
||||
$payment_meta->brand = $result->getCardBrand();
|
||||
$payment_meta->last4 = $result->getLast4();
|
||||
$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_driver;
|
||||
$data['client_token'] = $this->braintree->gateway->clientToken()->generate();
|
||||
|
||||
return render('gateways.braintree.credit_card.pay', $data);
|
||||
|
||||
}
|
||||
|
||||
public function processPaymentResponse($request)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* 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_driver->payment_hash->invoices(), 'amount')) + $this->square_driver->payment_hash->fee_total;
|
||||
|
||||
$payment_record = [];
|
||||
$payment_record['amount'] = $amount;
|
||||
$payment_record['payment_type'] = PaymentType::CREDIT_CARD_OTHER;
|
||||
$payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD;
|
||||
// $payment_record['transaction_reference'] = $response->transaction_id;
|
||||
|
||||
$payment = $this->square_driver->createPayment($payment_record, Payment::STATUS_COMPLETED);
|
||||
|
||||
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
|
||||
|
||||
}
|
||||
|
||||
private function processUnsuccessfulPayment($response)
|
||||
{
|
||||
/*Harvest your own errors here*/
|
||||
// $error = $response->status_message;
|
||||
|
||||
// if(property_exists($response, 'approval_message') && $response->approval_message)
|
||||
// $error .= " - {$response->approval_message}";
|
||||
|
||||
// $error_code = property_exists($response, 'approval_message') ? $response->approval_message : 'Undefined code';
|
||||
|
||||
$data = [
|
||||
'response' => $response,
|
||||
'error' => $error,
|
||||
'error_code' => $error_code,
|
||||
];
|
||||
|
||||
return $this->square_driver->processUnsuccessfulTransaction($data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Helpers */
|
||||
|
||||
/*
|
||||
You will need some helpers to handle successful and unsuccessful responses
|
||||
|
||||
Some considerations after a succesful transaction include:
|
||||
|
||||
Logging of events: success +/- failure
|
||||
Recording a payment
|
||||
Notifications
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
105
app/PaymentDrivers/SquarePaymentDriver.php
Normal file
105
app/PaymentDrivers/SquarePaymentDriver.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\Square\CreditCard;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
|
||||
class SquarePaymentDriver extends BaseDriver
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
public $refundable = true; //does this gateway support refunds?
|
||||
|
||||
public $token_billing = true; //does this gateway support token billing?
|
||||
|
||||
public $can_authorise_credit_card = true; //does this gateway support authorizations?
|
||||
|
||||
public $square;
|
||||
|
||||
public $payment_method;
|
||||
|
||||
public static $methods = [
|
||||
GatewayType::CREDIT_CARD => CreditCard::class, //maps GatewayType => Implementation class
|
||||
];
|
||||
|
||||
const SYSTEM_LOG_TYPE = SystemLog::TYPE_SQUARE;
|
||||
|
||||
public function init()
|
||||
{
|
||||
|
||||
$this->square = new \Square\SquareClient([
|
||||
'accessToken' => $this->company_gateway->getConfigField('accessToken'),
|
||||
'environment' => $this->company_gateway->getConfigField('testMode') ? \Square\Environment::SANDBOX : \Square\Environment::PRODUCTION,
|
||||
]);
|
||||
|
||||
return $this; /* This is where you boot the gateway with your auth credentials*/
|
||||
}
|
||||
|
||||
/* Returns an array of gateway types for the payment gateway */
|
||||
public function gatewayTypes(): array
|
||||
{
|
||||
$types = [];
|
||||
|
||||
$types[] = GatewayType::CREDIT_CARD;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/* Sets the payment method initialized */
|
||||
public function setPaymentMethod($payment_method_id)
|
||||
{
|
||||
$class = self::$methods[$payment_method_id];
|
||||
$this->payment_method = new $class($this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function authorizeView(array $data)
|
||||
{
|
||||
return $this->payment_method->authorizeView($data); //this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function authorizeResponse($request)
|
||||
{
|
||||
return $this->payment_method->authorizeResponse($request); //this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function processPaymentView(array $data)
|
||||
{
|
||||
return $this->payment_method->paymentView($data); //this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function processPaymentResponse($request)
|
||||
{
|
||||
return $this->payment_method->paymentResponse($request); //this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||
{
|
||||
//this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||
{
|
||||
//this is your custom implementation from here
|
||||
}
|
||||
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request, Payment $payment = null)
|
||||
{
|
||||
}
|
||||
}
|
@ -69,6 +69,7 @@
|
||||
"pragmarx/google2fa": "^8.0",
|
||||
"predis/predis": "^1.1",
|
||||
"sentry/sentry-laravel": "^2",
|
||||
"square/square": "13.0.0.20210721",
|
||||
"stripe/stripe-php": "^7.50",
|
||||
"symfony/http-client": "^5.2",
|
||||
"tijsverkoyen/css-to-inline-styles": "^2.2",
|
||||
|
175
composer.lock
generated
175
composer.lock
generated
@ -4,8 +4,122 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "275a9dd3910b6ec79607b098406dc6c7",
|
||||
"content-hash": "93253273cd8399a0e083a064160b70bf",
|
||||
"packages": [
|
||||
{
|
||||
"name": "apimatic/jsonmapper",
|
||||
"version": "v2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/apimatic/jsonmapper.git",
|
||||
"reference": "f7588f1ab692c402a9118e65cb9fd42b74e5e0db"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/apimatic/jsonmapper/zipball/f7588f1ab692c402a9118e65cb9fd42b74e5e0db",
|
||||
"reference": "f7588f1ab692c402a9118e65cb9fd42b74e5e0db",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
|
||||
"squizlabs/php_codesniffer": "^3.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"apimatic\\jsonmapper\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"OSL-3.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Christian Weiske",
|
||||
"email": "christian.weiske@netresearch.de",
|
||||
"homepage": "http://www.netresearch.de/",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Mehdi Jaffery",
|
||||
"email": "mehdi.jaffery@apimatic.io",
|
||||
"homepage": "http://apimatic.io/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Map nested JSON structures onto PHP classes",
|
||||
"support": {
|
||||
"email": "mehdi.jaffery@apimatic.io",
|
||||
"issues": "https://github.com/apimatic/jsonmapper/issues",
|
||||
"source": "https://github.com/apimatic/jsonmapper/tree/v2.0.3"
|
||||
},
|
||||
"time": "2021-07-16T09:02:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "apimatic/unirest-php",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/apimatic/unirest-php.git",
|
||||
"reference": "b4e399a8970c3a5c611f734282f306381f9d1eee"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/apimatic/unirest-php/zipball/b4e399a8970c3a5c611f734282f306381f9d1eee",
|
||||
"reference": "b4e399a8970c3a5c611f734282f306381f9d1eee",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"php": ">=5.6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5 || ^6 || ^7"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-json": "Allows using JSON Bodies for sending and parsing requests"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Unirest\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mashape",
|
||||
"email": "opensource@mashape.com",
|
||||
"homepage": "https://www.mashape.com",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "APIMATIC",
|
||||
"email": "opensource@apimatic.io",
|
||||
"homepage": "https://www.apimatic.io",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Unirest PHP",
|
||||
"homepage": "https://github.com/apimatic/unirest-php",
|
||||
"keywords": [
|
||||
"client",
|
||||
"curl",
|
||||
"http",
|
||||
"https",
|
||||
"rest"
|
||||
],
|
||||
"support": {
|
||||
"email": "opensource@apimatic.io",
|
||||
"issues": "https://github.com/apimatic/unirest-php/issues",
|
||||
"source": "https://github.com/apimatic/unirest-php/tree/2.0.0"
|
||||
},
|
||||
"time": "2020-04-07T17:16:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "asm/php-ansible",
|
||||
"version": "dev-main",
|
||||
@ -7459,6 +7573,63 @@
|
||||
],
|
||||
"time": "2021-06-16T09:26:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "square/square",
|
||||
"version": "13.0.0.20210721",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/square/square-php-sdk.git",
|
||||
"reference": "03d90445854cd3b500f75061a9c63956799b8ecf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/square/square-php-sdk/zipball/03d90445854cd3b500f75061a9c63956799b8ecf",
|
||||
"reference": "03d90445854cd3b500f75061a9c63956799b8ecf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"apimatic/jsonmapper": "^2.0.2",
|
||||
"apimatic/unirest-php": "^2.0",
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phan/phan": "^3.0",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Square\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Square Developer Platform",
|
||||
"email": "developers@squareup.com",
|
||||
"homepage": "https://squareup.com/developers"
|
||||
}
|
||||
],
|
||||
"description": "Use Square APIs to manage and run business including payment, customer, product, inventory, and employee management.",
|
||||
"homepage": "https://squareup.com/developers",
|
||||
"keywords": [
|
||||
"api",
|
||||
"sdk",
|
||||
"square"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/square/square-php-sdk/issues",
|
||||
"source": "https://github.com/square/square-php-sdk/tree/13.0.0.20210721"
|
||||
},
|
||||
"time": "2021-07-21T06:43:15+00:00"
|
||||
},
|
||||
{
|
||||
"name": "stripe/stripe-php",
|
||||
"version": "v7.88.0",
|
||||
@ -14972,5 +15143,5 @@
|
||||
"platform-dev": {
|
||||
"php": "^7.3|^7.4|^8.0"
|
||||
},
|
||||
"plugin-api-version": "2.1.0"
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ return [
|
||||
'decrypted' => env('PAYTRACE_KEYS', ''),
|
||||
],
|
||||
'mollie' => env('MOLLIE_KEYS', ''),
|
||||
'square' => env('SQUARE_KEYS',''),
|
||||
],
|
||||
'contact' => [
|
||||
'email' => env('MAIL_FROM_ADDRESS'),
|
||||
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Gateway;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class SquarePaymentDriver extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
|
||||
Model::unguard();
|
||||
|
||||
$fields = new \stdClass;
|
||||
$fields->accessToken = "";
|
||||
$fields->applicationId = "";
|
||||
$fields->locationId = "";
|
||||
$fields->testMode = false;
|
||||
|
||||
$square = new Gateway();
|
||||
$square->id = 57;
|
||||
$square->name = "Square";
|
||||
$square->provider = "Square";
|
||||
$square->key = '65faab2ab6e3223dbe848b1686490baz';
|
||||
$square->sort_order = 4343;
|
||||
$square->is_offsite = false;
|
||||
$square->visible = true;
|
||||
$square->fields = json_encode($fields);
|
||||
$square->save();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
@ -80,6 +80,7 @@ class PaymentLibrariesSeeder extends Seeder
|
||||
['id' => 53, 'name' => 'PagSeguro', 'provider' => 'PagSeguro', 'key' => 'ef498756b54db63c143af0ec433da803', 'fields' => '{"email":"","token":"","sandbox":false}'],
|
||||
['id' => 54, 'name' => 'PAYMILL', 'provider' => 'Paymill', 'key' => 'ca52f618a39367a4c944098ebf977e1c', 'fields' => '{"apiKey":""}'],
|
||||
['id' => 55, 'name' => 'Custom', 'provider' => 'Custom', 'is_offsite' => true, 'sort_order' => 21, 'key' => '54faab2ab6e3223dbe848b1686490baa', 'fields' => '{"name":"","text":""}'],
|
||||
['id' => 57, 'name' => 'Square', 'provider' => 'Square', 'is_offsite' => false, 'sort_order' => 21, 'key' => '65faab2ab6e3223dbe848b1686490baz', 'fields' => '{"accessToken":"","applicationId":"","locationId":"","testMode":"false"}'],
|
||||
];
|
||||
|
||||
foreach ($gateways as $gateway) {
|
||||
@ -96,7 +97,7 @@ class PaymentLibrariesSeeder extends Seeder
|
||||
|
||||
Gateway::query()->update(['visible' => 0]);
|
||||
|
||||
Gateway::whereIn('id', [1,7,15,20,39,46,55,50])->update(['visible' => 1]);
|
||||
Gateway::whereIn('id', [1,7,15,20,39,46,55,50,57])->update(['visible' => 1]);
|
||||
|
||||
if (Ninja::isHosted()) {
|
||||
Gateway::whereIn('id', [20])->update(['visible' => 0]);
|
||||
|
@ -0,0 +1,167 @@
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title'
|
||||
=> ctrans('texts.payment_type_credit_card')])
|
||||
|
||||
@section('gateway_head')
|
||||
@endsection
|
||||
|
||||
@section('gateway_content')
|
||||
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::CREDIT_CARD]) }}"
|
||||
method="post" id="server_response">
|
||||
@csrf
|
||||
<input type="text" name="sourceId" id="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>
|
||||
|
||||
<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>
|
||||
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({
|
||||
style: darkModeCardStyle,
|
||||
});
|
||||
await card.attach('#card-container');
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
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) {
|
||||
console.error('Initializing Card failed', e);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
document.getElementById('sourceId').value = token;
|
||||
document.getElementById('server_response').submit();
|
||||
|
||||
displayPaymentResults('SUCCESS');
|
||||
|
||||
} 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>
|
||||
|
||||
@endsection
|
Loading…
Reference in New Issue
Block a user