Updates for payfast token billing
This commit is contained in:
parent
3a3664e8c6
commit
0f16f8e98c
|
|
@ -138,7 +138,7 @@ class AuthorizeCreditCard implements LivewireMethodInterface
|
||||||
{
|
{
|
||||||
$client_gateway_token = ClientGatewayToken::query()
|
$client_gateway_token = ClientGatewayToken::query()
|
||||||
->where('id', $this->decodePrimaryKey($request->token))
|
->where('id', $this->decodePrimaryKey($request->token))
|
||||||
->where('company_id', auth()->guard('contact')->user()->client->company->id)
|
->where('company_id', auth()->guard('contact')->user()->client->company_id)
|
||||||
->first();
|
->first();
|
||||||
|
|
||||||
if (! $client_gateway_token) {
|
if (! $client_gateway_token) {
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,11 @@ class CreditCard implements LivewireMethodInterface
|
||||||
*/
|
*/
|
||||||
public function paymentResponse(Request $request)
|
public function paymentResponse(Request $request)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if($request->token){
|
||||||
|
return $this->processTokenPayment($request->token, $request->payment_hash);
|
||||||
|
}
|
||||||
|
|
||||||
$response_array = $request->all();
|
$response_array = $request->all();
|
||||||
|
|
||||||
nlog($request->all());
|
nlog($request->all());
|
||||||
|
|
@ -216,6 +221,27 @@ class CreditCard implements LivewireMethodInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function processTokenPayment(string $token, string $payment_hash)
|
||||||
|
{
|
||||||
|
|
||||||
|
$client_gateway_token = \App\Models\ClientGatewayToken::query()
|
||||||
|
->where('token', $token)
|
||||||
|
->where('company_id', auth()->guard('contact')->user()->client->company_id)
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (! $client_gateway_token) {
|
||||||
|
throw new \App\Exceptions\PaymentFailed(ctrans('texts.payment_token_not_found'), 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$payment_hash = \App\Models\PaymentHash::with('fee_invoice')->where('hash', $payment_hash)->firstOrFail();
|
||||||
|
|
||||||
|
$payment = $this->payfast->tokenBilling($client_gateway_token, $payment_hash);
|
||||||
|
|
||||||
|
return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private function processSuccessfulPayment($response_array)
|
private function processSuccessfulPayment($response_array)
|
||||||
{
|
{
|
||||||
$payment_record = [];
|
$payment_record = [];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\PaymentDrivers\PayFast;
|
||||||
|
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
use App\Models\PaymentHash;
|
||||||
|
use App\Models\PaymentType;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use App\Models\CompanyGateway;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class PaymentCompletedWebhook implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public function __construct(public array $data, public string $company_key, public int $company_gateway_id){}
|
||||||
|
// 'm_payment_id' => 'aobgUGfYHQXCdFdXYyfXiEolPOOYIdbb',
|
||||||
|
// 'pf_payment_id' => '2579',
|
||||||
|
// 'payment_status' => 'COMPLETE',
|
||||||
|
// 'item_name' => 'Invoices: ["0081"]',
|
||||||
|
// 'item_description' => 'Credit Card Pre Authorization',
|
||||||
|
// 'amount_gross' => '1481.55',
|
||||||
|
// 'amount_fee' => '-68.75',
|
||||||
|
// 'amount_net' => '1412.80',
|
||||||
|
// 'custom_str1' => NULL,
|
||||||
|
// 'custom_str2' => NULL,
|
||||||
|
// 'custom_str3' => NULL,
|
||||||
|
// 'custom_str4' => NULL,
|
||||||
|
// 'custom_str5' => NULL,
|
||||||
|
// 'custom_int1' => NULL,
|
||||||
|
// 'custom_int2' => NULL,
|
||||||
|
// 'custom_int3' => NULL,
|
||||||
|
// 'custom_int4' => NULL,
|
||||||
|
// 'custom_int5' => NULL,
|
||||||
|
// 'name_first' => NULL,
|
||||||
|
// 'name_last' => NULL,
|
||||||
|
// 'email_address' => NULL,
|
||||||
|
// 'merchant_id' => '10023100',
|
||||||
|
// 'token' => '8e1bf463-0c75-4f9c-836b-9bd02de14fc4',
|
||||||
|
// 'billing_date' => '2025-06-16',
|
||||||
|
// 'signature' => 'acfddcf33967679bcc743532dfef9a89',
|
||||||
|
// 'q' => '/payment_notification_webhook/M2zB4QN6EabKLGV319vzqXFy0J2Xvxer/4w9aAOdvMR/7LDdwRb1YK',
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
nlog("PaymentCompletedWebhook");
|
||||||
|
nlog(now()->format('Y-m-d H:i:s'));
|
||||||
|
MultiDB::findAndSetDbByCompanyKey($this->company_key);
|
||||||
|
|
||||||
|
$company = Company::query()->where('company_key', $this->company_key)->first();
|
||||||
|
|
||||||
|
$p = Payment::query()
|
||||||
|
->where('company_id', $company->id)
|
||||||
|
->where('transaction_reference', $this->data['pf_payment_id'])
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if($p){
|
||||||
|
nlog("payment found returning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlog("yolo");
|
||||||
|
$payment_hash = PaymentHash::where('hash', $this->data['m_payment_id'])->first();
|
||||||
|
|
||||||
|
$company_gateway = CompanyGateway::query()->where('company_id', $company->id)->where('id', $this->company_gateway_id)->first();
|
||||||
|
$driver = $company_gateway->driver($payment_hash->fee_invoice->client)->init();
|
||||||
|
$driver->setPaymentHash($payment_hash);
|
||||||
|
|
||||||
|
$payment_record = [];
|
||||||
|
$payment_record['amount'] = $this->data['amount_gross'];
|
||||||
|
$payment_record['payment_type'] = PaymentType::CREDIT_CARD_OTHER;
|
||||||
|
$payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD;
|
||||||
|
$payment_record['transaction_reference'] = $this->data['pf_payment_id'];
|
||||||
|
$payment_record['idempotency_key'] = $this->data['pf_payment_id'].$payment_hash->hash;
|
||||||
|
|
||||||
|
$payment = $driver->createPayment($payment_record, Payment::STATUS_COMPLETED);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,10 +12,15 @@
|
||||||
|
|
||||||
namespace App\PaymentDrivers\PayFast;
|
namespace App\PaymentDrivers\PayFast;
|
||||||
|
|
||||||
use App\Models\ClientGatewayToken;
|
use App\Models\Payment;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\Models\GatewayType;
|
||||||
use App\Models\PaymentHash;
|
use App\Models\PaymentHash;
|
||||||
|
use App\Models\PaymentType;
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Exceptions\PaymentFailed;
|
||||||
|
use App\Models\ClientGatewayToken;
|
||||||
use App\PaymentDrivers\PayFastPaymentDriver;
|
use App\PaymentDrivers\PayFastPaymentDriver;
|
||||||
use GuzzleHttp\RequestOptions;
|
|
||||||
|
|
||||||
class Token
|
class Token
|
||||||
{
|
{
|
||||||
|
|
@ -29,98 +34,93 @@ class Token
|
||||||
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||||
{
|
{
|
||||||
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
|
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
|
||||||
$amount = round(($amount * pow(10, $this->payfast->client->currency()->precision)), 0);
|
$amount = (int)round(($amount * pow(10, $this->payfast->client->currency()->precision)), 0);
|
||||||
|
|
||||||
$header = [
|
try {
|
||||||
'merchant-id' => $this->payfast->company_gateway->getConfigField('merchantId'),
|
$payfast = new \PayFast\PayFastApi(
|
||||||
'version' => 'v1',
|
|
||||||
'timestamp' => now()->format('c'),
|
|
||||||
];
|
|
||||||
|
|
||||||
$body = [
|
|
||||||
'amount' => $amount,
|
|
||||||
'item_name' => 'purchase',
|
|
||||||
'item_description' => ctrans('texts.invoices').': '.collect($payment_hash->invoices())->pluck('invoice_number'),
|
|
||||||
'm_payment_id' => $payment_hash->hash,
|
|
||||||
];
|
|
||||||
|
|
||||||
$header['signature'] = $this->payfast->generateTokenSignature(array_merge($body, $header));
|
|
||||||
|
|
||||||
// nlog($header['signature']);
|
|
||||||
|
|
||||||
$result = $this->send($header, $body, $cgt->token);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function generate_parameter_string($api_data, $sort_data_before_merge = true, $skip_empty_values = true)
|
|
||||||
{
|
|
||||||
// if sorting is required the passphrase should be added in before sort.
|
|
||||||
if (! empty($this->payfast->company_gateway->getConfigField('passphrase')) && $sort_data_before_merge) {
|
|
||||||
$api_data['passphrase'] = $this->payfast->company_gateway->getConfigField('passphrase');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($sort_data_before_merge) {
|
|
||||||
ksort($api_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// concatenate the array key value pairs.
|
|
||||||
$parameter_string = '';
|
|
||||||
foreach ($api_data as $key => $val) {
|
|
||||||
if ($skip_empty_values && empty($val)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('signature' !== $key) {
|
|
||||||
$val = urlencode($val);
|
|
||||||
$parameter_string .= "$key=$val&";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// when not sorting passphrase should be added to the end before md5
|
|
||||||
if ($sort_data_before_merge) {
|
|
||||||
$parameter_string = rtrim($parameter_string, '&');
|
|
||||||
} elseif (! empty($this->pass_phrase)) {
|
|
||||||
$parameter_string .= 'passphrase='.urlencode($this->payfast->company_gateway->getConfigField('passphrase'));
|
|
||||||
} else {
|
|
||||||
$parameter_string = rtrim($parameter_string, '&');
|
|
||||||
}
|
|
||||||
|
|
||||||
// nlog($parameter_string);
|
|
||||||
|
|
||||||
return $parameter_string;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function genSig($data)
|
|
||||||
{
|
|
||||||
$fields = [];
|
|
||||||
|
|
||||||
ksort($data);
|
|
||||||
|
|
||||||
foreach ($data as $key => $value) {
|
|
||||||
if (! empty($data[$key])) {
|
|
||||||
$fields[$key] = $data[$key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nlog(http_build_query($fields));
|
|
||||||
|
|
||||||
return md5(http_build_query($fields));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function send($headers, $body, $token)
|
|
||||||
{
|
|
||||||
$client = new \GuzzleHttp\Client(
|
|
||||||
[
|
[
|
||||||
'headers' => $headers,
|
'merchantId' => (string)$this->payfast->company_gateway->getConfigField('merchantId'),
|
||||||
|
'merchantKey' => $this->payfast->company_gateway->getConfigField('merchantKey'),
|
||||||
|
'passPhrase' => $this->payfast->company_gateway->getConfigField('passphrase'),
|
||||||
|
'testMode' => $this->payfast->company_gateway->getConfigField('testMode')
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
$data = [
|
||||||
$response = $client->post("https://api.payfast.co.za/subscriptions/{$token}/adhoc?testing=true", [
|
'amount' => $amount,
|
||||||
RequestOptions::JSON => ['body' => $body], RequestOptions::ALLOW_REDIRECTS => false,
|
'item_name' => ctrans('texts.invoices').': '.collect($payment_hash->invoices())->pluck('invoice_number'),
|
||||||
]);
|
'm_payment_id' => $payment_hash->hash,
|
||||||
|
];
|
||||||
|
|
||||||
return json_decode($response->getBody(), true);
|
$response = $payfast->subscriptions->adhoc($cgt->token, $data);
|
||||||
} catch (\Exception $e) {
|
|
||||||
nlog($e->getMessage());
|
nlog("TokenBilling");
|
||||||
|
nlog($response);
|
||||||
|
nlog(now()->format('Y-m-d H:i:s'));
|
||||||
|
|
||||||
|
if($response['code'] == 200 && $response['status'] == 'success') {
|
||||||
|
return $this->processSuccessfulPayment($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->processUnsuccessfulPayment($response, $payment_hash);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo 'There was an exception: '.$e->getMessage();
|
||||||
|
return $this->processUnsuccessfulPayment($e->getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array
|
||||||
|
// (
|
||||||
|
// [code] => 200
|
||||||
|
// [status] => success
|
||||||
|
// [data] => Array
|
||||||
|
// (
|
||||||
|
// [response] => true
|
||||||
|
// [message] => Transaction was successful (00)
|
||||||
|
// [pf_payment_id] => 2577761
|
||||||
|
// )
|
||||||
|
|
||||||
|
// )
|
||||||
|
|
||||||
|
private function processSuccessfulPayment(array $response)
|
||||||
|
{
|
||||||
|
|
||||||
|
$payment_record = [];
|
||||||
|
$payment_record['amount'] = array_sum(array_column($this->payfast->payment_hash->invoices(), 'amount')) + $this->payfast->payment_hash->fee_total;
|
||||||
|
$payment_record['payment_type'] = PaymentType::CREDIT_CARD_OTHER;
|
||||||
|
$payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD;
|
||||||
|
$payment_record['transaction_reference'] = $response['data']['pf_payment_id'];
|
||||||
|
$payment_record['idempotency_key'] = $response['data']['pf_payment_id'].$this->payfast->payment_hash->hash;
|
||||||
|
$payment = $this->payfast->createPayment($payment_record, Payment::STATUS_COMPLETED);
|
||||||
|
|
||||||
|
return $payment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processUnsuccessfulPayment($response)
|
||||||
|
{
|
||||||
|
$error_message = $response['data']['message'];
|
||||||
|
$error_code = $response['code'];
|
||||||
|
|
||||||
|
$this->payfast->sendFailureMail($error_message);
|
||||||
|
|
||||||
|
$message = [
|
||||||
|
'server_response' => $response,
|
||||||
|
'data' => $this->payfast->payment_hash->data,
|
||||||
|
];
|
||||||
|
|
||||||
|
SystemLogger::dispatch(
|
||||||
|
$message,
|
||||||
|
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||||
|
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||||
|
SystemLog::TYPE_PAYFAST,
|
||||||
|
$this->payfast->client,
|
||||||
|
$this->payfast->client->company,
|
||||||
|
);
|
||||||
|
|
||||||
|
throw new PaymentFailed('Failed to process the payment.', 500);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,18 @@
|
||||||
|
|
||||||
namespace App\PaymentDrivers;
|
namespace App\PaymentDrivers;
|
||||||
|
|
||||||
use App\Models\ClientGatewayToken;
|
|
||||||
use App\Models\GatewayType;
|
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\PaymentHash;
|
|
||||||
use App\Models\SystemLog;
|
use App\Models\SystemLog;
|
||||||
use App\PaymentDrivers\PayFast\CreditCard;
|
use App\Models\GatewayType;
|
||||||
use App\PaymentDrivers\PayFast\Token;
|
use App\Models\PaymentHash;
|
||||||
use App\Utils\Traits\MakesHash;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use App\Models\ClientGatewayToken;
|
||||||
|
use App\PaymentDrivers\PayFast\Token;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use App\PaymentDrivers\PayFast\CreditCard;
|
||||||
|
use App\PaymentDrivers\PayFast\PaymentCompletedWebhook;
|
||||||
|
use App\Http\Requests\Payments\PaymentNotificationWebhookRequest;
|
||||||
|
|
||||||
class PayFastPaymentDriver extends BaseDriver
|
class PayFastPaymentDriver extends BaseDriver
|
||||||
{
|
{
|
||||||
|
|
@ -69,19 +71,6 @@ class PayFastPaymentDriver extends BaseDriver
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
// try {
|
|
||||||
// $this->payfast = new \Payfast\PayFastPayment(
|
|
||||||
// [
|
|
||||||
// 'merchantId' => $this->company_gateway->getConfigField('merchantId'),
|
|
||||||
// 'merchantKey' => $this->company_gateway->getConfigField('merchantKey'),
|
|
||||||
// 'passPhrase' => $this->company_gateway->getConfigField('passphrase'),
|
|
||||||
// 'testMode' => $this->company_gateway->getConfigField('testMode'),
|
|
||||||
// ]
|
|
||||||
// );
|
|
||||||
// } catch (\Exception $e) {
|
|
||||||
// nlog('##PAYFAST## There was an exception: '.$e->getMessage());
|
|
||||||
// }
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,12 +185,17 @@ class PayFastPaymentDriver extends BaseDriver
|
||||||
return md5(http_build_query($fields));
|
return md5(http_build_query($fields));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processWebhookRequest(Request $request, Payment $payment = null)
|
public function processWebhookRequest(PaymentNotificationWebhookRequest $request, Payment $payment = null)
|
||||||
{
|
{
|
||||||
$data = $request->all();
|
$data = $request->all();
|
||||||
// nlog("payfast");
|
// nlog("payfast");
|
||||||
// nlog($data);
|
// nlog($data);
|
||||||
|
|
||||||
|
if(array_key_exists('pf_payment_id', $data) && strlen($data['pf_payment_id']) > 1) {
|
||||||
|
PaymentCompletedWebhook::dispatch($data, $request->company_key, $this->company_gateway->id)->delay(10);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (array_key_exists('m_payment_id', $data)) {
|
if (array_key_exists('m_payment_id', $data)) {
|
||||||
$hash = Cache::get($data['m_payment_id']);
|
$hash = Cache::get($data['m_payment_id']);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@
|
||||||
"hyvor/php-json-exporter": "^0.0.3",
|
"hyvor/php-json-exporter": "^0.0.3",
|
||||||
"imdhemy/laravel-purchases": "^1.7",
|
"imdhemy/laravel-purchases": "^1.7",
|
||||||
"intervention/image": "^2.5",
|
"intervention/image": "^2.5",
|
||||||
|
"invoiceninja/admin-api": "dev-main",
|
||||||
"invoiceninja/einvoice": "dev-main",
|
"invoiceninja/einvoice": "dev-main",
|
||||||
"invoiceninja/inspector": "^3.0",
|
"invoiceninja/inspector": "^3.0",
|
||||||
"invoiceninja/ubl_invoice": "^2",
|
"invoiceninja/ubl_invoice": "^2",
|
||||||
|
|
@ -89,6 +90,7 @@
|
||||||
"nelexa/zip": "^4.0",
|
"nelexa/zip": "^4.0",
|
||||||
"nordigen/nordigen-php": "^1.1",
|
"nordigen/nordigen-php": "^1.1",
|
||||||
"nwidart/laravel-modules": "^11.0",
|
"nwidart/laravel-modules": "^11.0",
|
||||||
|
"payfast/payfast-php-sdk": "^1.1",
|
||||||
"phpoffice/phpspreadsheet": "^2.2",
|
"phpoffice/phpspreadsheet": "^2.2",
|
||||||
"pragmarx/google2fa": "^8.0",
|
"pragmarx/google2fa": "^8.0",
|
||||||
"predis/predis": "^2",
|
"predis/predis": "^2",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "4361272676d998d08fb1926198065b39",
|
"content-hash": "afc109ee881bc826259c15922048972d",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adrienrn/php-mimetyper",
|
"name": "adrienrn/php-mimetyper",
|
||||||
|
|
@ -4667,6 +4667,65 @@
|
||||||
],
|
],
|
||||||
"time": "2022-05-21T17:30:32+00:00"
|
"time": "2022-05-21T17:30:32+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "invoiceninja/admin-api",
|
||||||
|
"version": "dev-main",
|
||||||
|
"dist": {
|
||||||
|
"type": "path",
|
||||||
|
"url": "../admin-api",
|
||||||
|
"reference": "4d95a2318a4dc41cdea95793d85ffe5589ed9117"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"afosto/yaac": "^1.5",
|
||||||
|
"asm/php-ansible": "dev-main",
|
||||||
|
"ext-curl": "*",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"illuminate/database": "^11",
|
||||||
|
"illuminate/support": "^11",
|
||||||
|
"imdhemy/laravel-purchases": "^1.7",
|
||||||
|
"php": "^8.2|^8.3|^8.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"larastan/larastan": "^3.0",
|
||||||
|
"orchestra/testbench": "^9.0",
|
||||||
|
"phpstan/phpstan": "^2.0",
|
||||||
|
"phpunit/phpunit": "^11.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"laravel": {
|
||||||
|
"providers": [
|
||||||
|
"InvoiceNinja\\AdminApi\\Providers\\AdminApiServiceProvider"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"InvoiceNinja\\AdminApi\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"InvoiceNinja\\AdminApi\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"license": [
|
||||||
|
"Elastic"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "David Bomba",
|
||||||
|
"email": "turbo124@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "API endpoints for the admin interface",
|
||||||
|
"transport-options": {
|
||||||
|
"relative": true
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "invoiceninja/einvoice",
|
"name": "invoiceninja/einvoice",
|
||||||
"version": "dev-main",
|
"version": "dev-main",
|
||||||
|
|
@ -9088,6 +9147,59 @@
|
||||||
},
|
},
|
||||||
"time": "2024-09-04T12:51:01+00:00"
|
"time": "2024-09-04T12:51:01+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "payfast/payfast-php-sdk",
|
||||||
|
"version": "v1.1.6",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Payfast/payfast-php-sdk.git",
|
||||||
|
"reference": "015efcd2df3e580e023dae6e16c943328d38bb78"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Payfast/payfast-php-sdk/zipball/015efcd2df3e580e023dae6e16c943328d38bb78",
|
||||||
|
"reference": "015efcd2df3e580e023dae6e16c943328d38bb78",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-json": "*",
|
||||||
|
"guzzlehttp/guzzle": ">=6.0.0",
|
||||||
|
"php": ">=8.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.10",
|
||||||
|
"phpunit/phpunit": "^9",
|
||||||
|
"squizlabs/php_codesniffer": "^3.8"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PayFast\\": "lib/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Payfast",
|
||||||
|
"email": "support@payfast.help"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Payfast PHP Library",
|
||||||
|
"keywords": [
|
||||||
|
"api",
|
||||||
|
"onsite",
|
||||||
|
"payfast",
|
||||||
|
"php"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/Payfast/payfast-php-sdk/issues",
|
||||||
|
"source": "https://github.com/Payfast/payfast-php-sdk/tree/v1.1.6"
|
||||||
|
},
|
||||||
|
"time": "2024-02-28T09:54:10+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "php-http/client-common",
|
"name": "php-http/client-common",
|
||||||
"version": "2.7.2",
|
"version": "2.7.2",
|
||||||
|
|
@ -9883,16 +9995,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpseclib/phpseclib",
|
"name": "phpseclib/phpseclib",
|
||||||
"version": "3.0.43",
|
"version": "3.0.44",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||||
"reference": "709ec107af3cb2f385b9617be72af8cf62441d02"
|
"reference": "1d0b5e7e1434678411787c5a0535e68907cf82d9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02",
|
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/1d0b5e7e1434678411787c5a0535e68907cf82d9",
|
||||||
"reference": "709ec107af3cb2f385b9617be72af8cf62441d02",
|
"reference": "1d0b5e7e1434678411787c5a0535e68907cf82d9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -9973,7 +10085,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.43"
|
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.44"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -9989,7 +10101,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-12-14T21:12:59+00:00"
|
"time": "2025-06-15T09:59:26+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpstan/phpdoc-parser",
|
"name": "phpstan/phpdoc-parser",
|
||||||
|
|
@ -21396,6 +21508,7 @@
|
||||||
"asm/php-ansible": 20,
|
"asm/php-ansible": 20,
|
||||||
"beganovich/snappdf": 20,
|
"beganovich/snappdf": 20,
|
||||||
"horstoeko/orderx": 20,
|
"horstoeko/orderx": 20,
|
||||||
|
"invoiceninja/admin-api": 20,
|
||||||
"invoiceninja/einvoice": 20,
|
"invoiceninja/einvoice": 20,
|
||||||
"socialiteproviders/apple": 20
|
"socialiteproviders/apple": 20
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
var h=Object.defineProperty;var w=(a,e,n)=>e in a?h(a,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):a[e]=n;var u=(a,e,n)=>(w(a,typeof e!="symbol"?e+"":e,n),n);import{i as y,w as p}from"./wait-8f4ae121.js";/**
|
|
||||||
* 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 b{constructor(){u(this,"startTimer",e=>{const n=new Date().getTime()+e*1e3;document.getElementById("countdown").innerHTML="10:00 min";const c=()=>{const r=new Date().getTime(),t=n-r;if(document.getElementsByClassName("btc-value")[0].innerHTML.includes("Refreshing"))return;if(t<0){refreshBTCPrice();return}const s=Math.floor(t%(1e3*60*60)/(1e3*60)),i=Math.floor(t%(1e3*60)/1e3),d=String(s).padStart(2,"0"),m=String(i).padStart(2,"0");document.getElementById("countdown").innerHTML=d+":"+m+" min"};clearInterval(window.countdownInterval),window.countdownInterval=setInterval(c,1e3)});this.copyToClipboard=this.copyToClipboard.bind(this),this.refreshBTCPrice=this.refreshBTCPrice.bind(this),this.fetchAndDisplayQRCode=this.fetchAndDisplayQRCode.bind(this),this.startTimer=this.startTimer.bind(this)}copyToClipboard(e,n,c){const r=c?n.nextElementSibling:n,t=r.src,o=document.createElement("input"),s=document.getElementById(e),{value:i,innerText:d}=s||{},m=i||d;o.value=m,document.body.appendChild(o),o.select(),document.execCommand("copy"),document.body.removeChild(o),r.src="data:image/svg+xml;base64,"+btoa(`
|
|
||||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M4.04706 14C4.04706 8.55609 8.46025 4.1429 13.9042 4.1429C19.3482 4.1429 23.7613 8.55609 23.7613 14C23.7613 19.444 19.3482 23.8572 13.9042 23.8572C8.46025 23.8572 4.04706 19.444 4.04706 14Z" stroke="#000" stroke-width="2.19048" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
<path d="M9.52325 14L12.809 17.2858L18.2852 11.8096" stroke="#000" stroke-width="2.19048" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
</svg>
|
|
||||||
`),setTimeout(()=>{r.src=t},5e3)}async fetchAndDisplayQRCode(e=null){try{const n=document.querySelector('meta[name="btc_address"]').content,r=encodeURIComponent(`bitcoin:${n}?amount=${e||"{{$btc_amount}}"}`),t=await fetch(`/api/v1/get-blockonomics-qr-code?qr_string=${r}`);if(!t.ok)throw new Error(`HTTP error! status: ${t.status}`);const o=await t.text();document.getElementById("qrcode-container").innerHTML=o}catch(n){console.error("Error fetching QR code:",n),document.getElementById("qrcode-container").textContent="Error loading QR code"}}async refreshBTCPrice(){const e=document.querySelector(".icon-refresh");e.classList.add("rotating"),document.getElementsByClassName("btc-value")[0].innerHTML="Refreshing...";const n=async()=>{try{const c=document.querySelector('meta[name="currency"]').content,r=await fetch(`/api/v1/get-btc-price?currency=${c}`);if(!r.ok)throw new Error("Network response was not ok");return(await r.json()).price}catch(c){console.error("There was a problem with the BTC price fetch operation:",c)}};try{const c=await n();if(c){const r=document.querySelector('meta[name="currency"]').content;document.getElementsByClassName("btc-value")[0].innerHTML="1 BTC = "+(c||"N/A")+" "+r+", updates in <span id='countdown'></span>";const t=(document.querySelector('meta[name="amount"]').content/c).toFixed(10);document.querySelector('input[name="btc_price"]').value=c,document.querySelector('input[name="btc_amount"]').value=t,document.getElementById("btc-amount").textContent=t;const o=document.querySelector('meta[name="btc_address"]').content,s=document.getElementById("qr-code-link"),i=document.getElementById("open-in-wallet-link");s.href=`bitcoin:${o}?amount=${t}`,i.href=`bitcoin:${o}?amount=${t}`,await this.fetchAndDisplayQRCode(t),this.startTimer(600)}}finally{e.classList.remove("rotating")}}handle(){window.copyToClipboard=this.copyToClipboard,window.refreshBTCPrice=this.refreshBTCPrice,window.fetchAndDisplayQRCode=this.fetchAndDisplayQRCode,window.startTimer=this.startTimer;const e=()=>{const c=`wss://www.blockonomics.co/payment/${document.querySelector('meta[name="btc_address"]').content}`,r=new WebSocket(c);r.onmessage=function(t){const o=JSON.parse(t.data);console.log("Payment status:",o.status);const s=o.status===0,i=o.status===1,d=o.status===2;(s||i||d)&&(document.querySelector('input[name="txid"]').value=o.txid||"",document.getElementById("server-response").submit())}};startTimer(600),e(),fetchAndDisplayQRCode()}}function l(){new b().handle(),window.bootBlockonomics=l}y()?l():p("#blockonomics-payment").then(()=>l());
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
var h=Object.defineProperty;var y=(a,t,e)=>t in a?h(a,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):a[t]=e;var l=(a,t,e)=>(y(a,typeof t!="symbol"?t+"":t,e),e);import{i as w,w as p}from"./wait-8f4ae121.js";/**
|
||||||
|
* 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 f{constructor(){l(this,"startTimer",t=>{const e=new Date().getTime()+t*1e3;document.getElementById("countdown").innerHTML="10:00 min";const o=()=>{const c=new Date().getTime(),n=e-c;if(document.getElementsByClassName("btc-value")[0].innerHTML.includes("Refreshing"))return;if(n<0){refreshBTCPrice();return}const s=Math.floor(n%(1e3*60*60)/(1e3*60)),i=Math.floor(n%(1e3*60)/1e3),d=String(s).padStart(2,"0"),m=String(i).padStart(2,"0");document.getElementById("countdown").innerHTML=d+":"+m+" min"};clearInterval(window.countdownInterval),window.countdownInterval=setInterval(o,1e3)});this.copyToClipboard=this.copyToClipboard.bind(this),this.refreshBTCPrice=this.refreshBTCPrice.bind(this),this.fetchAndDisplayQRCode=this.fetchAndDisplayQRCode.bind(this),this.startTimer=this.startTimer.bind(this)}copyToClipboard(t,e,o){const c=o?e.nextElementSibling:e,n=c.src,r=document.createElement("input"),s=document.getElementById(t),{value:i,innerText:d}=s||{},m=i||d;r.value=m,document.body.appendChild(r),r.select(),document.execCommand("copy"),document.body.removeChild(r),c.src="data:image/svg+xml;base64,"+btoa(`
|
||||||
|
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M4.04706 14C4.04706 8.55609 8.46025 4.1429 13.9042 4.1429C19.3482 4.1429 23.7613 8.55609 23.7613 14C23.7613 19.444 19.3482 23.8572 13.9042 23.8572C8.46025 23.8572 4.04706 19.444 4.04706 14Z" stroke="#000" stroke-width="2.19048" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M9.52325 14L12.809 17.2858L18.2852 11.8096" stroke="#000" stroke-width="2.19048" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
`),setTimeout(()=>{c.src=n},5e3)}async fetchAndDisplayQRCode(t=null){try{const e=document.querySelector('meta[name="btc_address"]').content,c=encodeURIComponent(`bitcoin:${e}?amount=${t||"{{$btc_amount}}"}`),n=await fetch(`/api/v1/get-blockonomics-qr-code?qr_string=${c}`);if(!n.ok)throw new Error(`HTTP error! status: ${n.status}`);const r=await n.text();document.getElementById("qrcode-container").innerHTML=r}catch(e){console.error("Error fetching QR code:",e),document.getElementById("qrcode-container").textContent="Error loading QR code"}}async refreshBTCPrice(){const t=document.querySelector(".icon-refresh");t.classList.add("rotating"),document.getElementsByClassName("btc-value")[0].innerHTML="Refreshing...";const e=async()=>{try{const o=document.querySelector('meta[name="currency"]').content,c=await fetch(`/api/v1/get-btc-price?currency=${o}`);if(!c.ok)throw new Error("Network response was not ok");return(await c.json()).price}catch(o){console.error("There was a problem with the BTC price fetch operation:",o)}};try{const o=await e();if(o){const c=document.querySelector('meta[name="currency"]').content;document.getElementsByClassName("btc-value")[0].innerHTML="1 BTC = "+(o||"N/A")+" "+c+", updates in <span id='countdown'></span>";const n=(document.querySelector('meta[name="amount"]').content/o).toFixed(10);document.querySelector('input[name="btc_price"]').value=o,document.querySelector('input[name="btc_amount"]').value=n,document.getElementById("btc-amount").textContent=n;const r=document.querySelector('meta[name="btc_address"]').content,s=document.getElementById("qr-code-link"),i=document.getElementById("open-in-wallet-link");s.href=`bitcoin:${r}?amount=${n}`,i.href=`bitcoin:${r}?amount=${n}`,await this.fetchAndDisplayQRCode(n),this.startTimer(600)}}finally{t.classList.remove("rotating")}}handle(){window.copyToClipboard=this.copyToClipboard,window.refreshBTCPrice=this.refreshBTCPrice,window.fetchAndDisplayQRCode=this.fetchAndDisplayQRCode,window.startTimer=this.startTimer;const t=()=>{const e=document.querySelector('meta[name="btc_address"]').content,o=`wss://www.blockonomics.co/payment/${e}`,c=new WebSocket(o);c.onmessage=function(n){const r=JSON.parse(n.data),{status:s,txid:i,value:d}=r||{};console.log("Payment status:",s),(s===0||s===1||s===2)&&(document.querySelector('input[name="txid"]').value=i||"",document.querySelector('input[name="status"]').value=s||"",document.querySelector('input[name="btc_amount"]').value=d||"",document.querySelector('input[name="btc_address"]').value=e||"",document.getElementById("server-response").submit())}};startTimer(600),t(),fetchAndDisplayQRCode()}}function u(){new f().handle(),window.bootBlockonomics=u}w()?u():p("#blockonomics-payment").then(()=>u());
|
||||||
|
|
@ -99,7 +99,7 @@
|
||||||
"src": "resources/js/clients/payments/authorize-credit-card-payment.js"
|
"src": "resources/js/clients/payments/authorize-credit-card-payment.js"
|
||||||
},
|
},
|
||||||
"resources/js/clients/payments/blockonomics.js": {
|
"resources/js/clients/payments/blockonomics.js": {
|
||||||
"file": "assets/blockonomics-56ba6746.js",
|
"file": "assets/blockonomics-c3966bec.js",
|
||||||
"imports": [
|
"imports": [
|
||||||
"_wait-8f4ae121.js"
|
"_wait-8f4ae121.js"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
@section('gateway_content')
|
@section('gateway_content')
|
||||||
<form action="{{ $payment_endpoint_url }}" method="post" id="server_response">
|
<form action="{{ $payment_endpoint_url }}" method="post" id="server_response">
|
||||||
|
@csrf
|
||||||
<input type="hidden" name="merchant_id" value="{{ $merchant_id }}">
|
<input type="hidden" name="merchant_id" value="{{ $merchant_id }}">
|
||||||
<input type="hidden" name="merchant_key" value="{{ $merchant_key }}">
|
<input type="hidden" name="merchant_key" value="{{ $merchant_key }}">
|
||||||
<input type="hidden" name="return_url" value="{{ $return_url }}">
|
<input type="hidden" name="return_url" value="{{ $return_url }}">
|
||||||
|
|
@ -20,6 +21,12 @@
|
||||||
<input type="hidden" name="passphrase" value="{{ $passphrase }}">
|
<input type="hidden" name="passphrase" value="{{ $passphrase }}">
|
||||||
<input type="hidden" name="signature" value="{{ $signature }}">
|
<input type="hidden" name="signature" value="{{ $signature }}">
|
||||||
|
|
||||||
|
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
|
||||||
|
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
|
||||||
|
<input type="hidden" name="payment_method_id" value="1">
|
||||||
|
<input type="hidden" name="gateway_response" id="gateway_response">
|
||||||
|
<input type="hidden" name="token" id="token">
|
||||||
|
|
||||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
|
||||||
|
|
@ -29,28 +36,34 @@
|
||||||
@include('portal.ninja2020.gateways.includes.payment_details')
|
@include('portal.ninja2020.gateways.includes.payment_details')
|
||||||
|
|
||||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
||||||
|
<ul class="list-none space-y-2">
|
||||||
@if(count($tokens) > 0)
|
@if(count($tokens) > 0)
|
||||||
@foreach($tokens as $token)
|
@foreach($tokens as $token)
|
||||||
<label class="mr-4">
|
<li class="py-2 hover:bg-gray-100 rounded transition-colors duration-150">
|
||||||
|
<label class="flex items-center cursor-pointer px-2">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
data-token="{{ $token->token }}"
|
data-token="{{ $token->token }}"
|
||||||
name="payment-type"
|
name="payment-type"
|
||||||
class="form-radio cursor-pointer toggle-payment-with-token"/>
|
class="form-radio text-indigo-600 rounded-full cursor-pointer toggle-payment-with-token"/>
|
||||||
<span class="ml-1 cursor-pointer">**** {{ $token->meta?->last4 }}</span>
|
<span class="ml-2 cursor-pointer">**** {{ $token->meta?->last4 }}</span>
|
||||||
</label>
|
</label>
|
||||||
|
</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endisset
|
@endisset
|
||||||
|
|
||||||
<label>
|
<li class="py-2 hover:bg-gray-100 rounded transition-colors duration-150">
|
||||||
|
<label class="flex items-center cursor-pointer px-2">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
id="toggle-payment-with-credit-card"
|
id="toggle-payment-with-credit-card"
|
||||||
class="form-radio cursor-pointer"
|
class="form-radio text-indigo-600 rounded-full cursor-pointer"
|
||||||
name="payment-type"
|
name="payment-type"
|
||||||
checked/>
|
checked/>
|
||||||
<span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span>
|
<span class="ml-2 cursor-pointer">{{ __('texts.new_card') }}</span>
|
||||||
</label>
|
</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
@endcomponent
|
@endcomponent
|
||||||
|
|
||||||
@include('portal.ninja2020.gateways.includes.save_card')
|
@include('portal.ninja2020.gateways.includes.save_card')
|
||||||
|
|
@ -62,11 +75,49 @@
|
||||||
|
|
||||||
@section('gateway_footer')
|
@section('gateway_footer')
|
||||||
<script>
|
<script>
|
||||||
|
// Add click listeners to all token radio buttons
|
||||||
|
Array.from(document.getElementsByClassName('toggle-payment-with-token'))
|
||||||
document.getElementById('pay-now').addEventListener('click', function() {
|
.forEach((element) => {
|
||||||
document.getElementById('server_response').submit();
|
element.addEventListener('click', (e) => {
|
||||||
|
const sourceInput = document.querySelector('input[name=payment-type]');
|
||||||
|
if (sourceInput) {
|
||||||
|
sourceInput.value = e.target.dataset.token;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle the pay now button click
|
||||||
|
const payNowButton = document.getElementById('pay-now');
|
||||||
|
if (payNowButton) {
|
||||||
|
payNowButton.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
payNowButton.disabled = true;
|
||||||
|
payNowButton.querySelector('#pay-now svg').classList.remove('hidden');
|
||||||
|
payNowButton.querySelector('#pay-now span').classList.add('hidden');
|
||||||
|
|
||||||
|
const form = document.getElementById('server_response');
|
||||||
|
const selectedToken = document.querySelector('input[name="payment-type"]:checked');
|
||||||
|
|
||||||
|
if (selectedToken && selectedToken?.dataset?.token) {
|
||||||
|
form.action = "{{ route('client.payments.response') }}";
|
||||||
|
document.querySelector('input[name=token]').value = selectedToken.value;
|
||||||
|
} else {
|
||||||
|
const endpointUrl = document.getElementById('payment_endpoint_url');
|
||||||
|
if (endpointUrl) {
|
||||||
|
form.action = endpointUrl.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.submit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-select the first payment option if it exists
|
||||||
|
const first = document.querySelector('input[name="payment-type"]');
|
||||||
|
if (first) {
|
||||||
|
first.click();
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
<meta name="client-postal-code" content="{{ $contact->client->postal_code }}">
|
<meta name="client-postal-code" content="{{ $contact->client->postal_code }}">
|
||||||
|
|
||||||
<form action="{{ $payment_endpoint_url }}" method="post" id="server_response">
|
<form action="{{ $payment_endpoint_url }}" method="post" id="server_response">
|
||||||
|
@csrf
|
||||||
<input type="hidden" name="merchant_id" value="{{ $merchant_id }}">
|
<input type="hidden" name="merchant_id" value="{{ $merchant_id }}">
|
||||||
<input type="hidden" name="merchant_key" value="{{ $merchant_key }}">
|
<input type="hidden" name="merchant_key" value="{{ $merchant_key }}">
|
||||||
<input type="hidden" name="return_url" value="{{ $return_url }}">
|
<input type="hidden" name="return_url" value="{{ $return_url }}">
|
||||||
|
|
@ -16,6 +17,12 @@
|
||||||
<input type="hidden" name="passphrase" value="{{ $passphrase }}">
|
<input type="hidden" name="passphrase" value="{{ $passphrase }}">
|
||||||
<input type="hidden" name="signature" value="{{ $signature }}">
|
<input type="hidden" name="signature" value="{{ $signature }}">
|
||||||
|
|
||||||
|
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
|
||||||
|
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
|
||||||
|
<input type="hidden" name="payment_method_id" value="1">
|
||||||
|
<input type="hidden" name="gateway_response" id="gateway_response">
|
||||||
|
<input type="hidden" name="token" id="token">
|
||||||
|
|
||||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
|
||||||
|
|
@ -25,28 +32,34 @@
|
||||||
@include('portal.ninja2020.gateways.includes.payment_details')
|
@include('portal.ninja2020.gateways.includes.payment_details')
|
||||||
|
|
||||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
||||||
|
<ul class="list-none space-y-2">
|
||||||
@if(count($tokens) > 0)
|
@if(count($tokens) > 0)
|
||||||
@foreach($tokens as $token)
|
@foreach($tokens as $token)
|
||||||
<label class="mr-4">
|
<li class="py-2 hover:bg-gray-100 rounded transition-colors duration-150">
|
||||||
|
<label class="flex items-center cursor-pointer px-2">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
data-token="{{ $token->token }}"
|
data-token="{{ $token->token }}"
|
||||||
name="payment-type"
|
name="payment-type"
|
||||||
class="form-radio cursor-pointer toggle-payment-with-token"/>
|
class="form-radio text-indigo-600 rounded-full cursor-pointer toggle-payment-with-token"/>
|
||||||
<span class="ml-1 cursor-pointer">**** {{ $token->meta?->last4 }}</span>
|
<span class="ml-2 cursor-pointer">**** {{ $token->meta?->last4 }}</span>
|
||||||
</label>
|
</label>
|
||||||
|
</li>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endisset
|
@endisset
|
||||||
|
|
||||||
<label>
|
<li class="py-2 hover:bg-gray-100 rounded transition-colors duration-150">
|
||||||
|
<label class="flex items-center cursor-pointer px-2">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
id="toggle-payment-with-credit-card"
|
id="toggle-payment-with-credit-card"
|
||||||
class="form-radio cursor-pointer"
|
class="form-radio text-indigo-600 rounded-full cursor-pointer"
|
||||||
name="payment-type"
|
name="payment-type"
|
||||||
checked/>
|
checked/>
|
||||||
<span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span>
|
<span class="ml-2 cursor-pointer">{{ __('texts.new_card') }}</span>
|
||||||
</label>
|
</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
@endcomponent
|
@endcomponent
|
||||||
|
|
||||||
@include('portal.ninja2020.gateways.includes.save_card')
|
@include('portal.ninja2020.gateways.includes.save_card')
|
||||||
|
|
@ -57,9 +70,50 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@script
|
@script
|
||||||
<script>
|
<script defer>
|
||||||
document.getElementById('pay-now').addEventListener('click', function() {
|
// Add click listeners to all token radio buttons
|
||||||
document.getElementById('server_response').submit();
|
Array.from(document.getElementsByClassName('toggle-payment-with-token'))
|
||||||
|
.forEach((element) => {
|
||||||
|
element.addEventListener('click', (e) => {
|
||||||
|
const sourceInput = document.querySelector('input[name=payment-type]');
|
||||||
|
if (sourceInput) {
|
||||||
|
sourceInput.value = e.target.dataset.token;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle the pay now button click
|
||||||
|
const payNowButton = document.getElementById('pay-now');
|
||||||
|
if (payNowButton) {
|
||||||
|
payNowButton.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
payNowButton.disabled = true;
|
||||||
|
payNowButton.querySelector('#pay-now svg').classList.remove('hidden');
|
||||||
|
payNowButton.querySelector('#pay-now span').classList.add('hidden');
|
||||||
|
|
||||||
|
const form = document.getElementById('server_response');
|
||||||
|
const selectedToken = document.querySelector('input[name="payment-type"]:checked');
|
||||||
|
|
||||||
|
if (selectedToken && selectedToken?.dataset?.token) {
|
||||||
|
form.action = "{{ route('client.payments.response') }}";
|
||||||
|
document.querySelector('input[name=token]').value = selectedToken.value;
|
||||||
|
} else {
|
||||||
|
const endpointUrl = document.getElementById('payment_endpoint_url');
|
||||||
|
if (endpointUrl) {
|
||||||
|
form.action = endpointUrl.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.submit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-select the first payment option if it exists
|
||||||
|
const first = document.querySelector('input[name="payment-type"]');
|
||||||
|
if (first) {
|
||||||
|
first.click();
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@endscript
|
@endscript
|
||||||
Loading…
Reference in New Issue