mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 05:02:36 +01:00
commit
a1b19d3067
@ -15,6 +15,7 @@ namespace App\Http\Controllers\ClientPortal;
|
||||
use App\Events\Payment\Methods\MethodDeleted;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ClientPortal\PaymentMethod\CreatePaymentMethodRequest;
|
||||
use App\Http\Requests\ClientPortal\PaymentMethod\VerifyPaymentMethodRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
@ -56,7 +57,6 @@ class PaymentMethodController extends Controller
|
||||
|
||||
$data['gateway'] = $gateway;
|
||||
$data['client'] = auth()->user()->client;
|
||||
|
||||
return $gateway
|
||||
->driver(auth()->user()->client)
|
||||
->setPaymentMethod($request->query('method'))
|
||||
@ -147,6 +147,9 @@ class PaymentMethodController extends Controller
|
||||
if (request()->query('method') == GatewayType::CREDIT_CARD) {
|
||||
return auth()->user()->client->getCreditCardGateway();
|
||||
}
|
||||
if (request()->query('method') == GatewayType::BACS) {
|
||||
return auth()->user()->client->getBACSGateway();
|
||||
}
|
||||
|
||||
if (in_array(request()->query('method'), [GatewayType::BANK_TRANSFER, GatewayType::DIRECT_DEBIT, GatewayType::SEPA])) {
|
||||
return auth()->user()->client->getBankTransferGateway();
|
||||
|
@ -587,6 +587,29 @@ class Client extends BaseModel implements HasLocalePreference
|
||||
|
||||
return null;
|
||||
}
|
||||
public function getBACSGateway() :?CompanyGateway
|
||||
{
|
||||
$pms = $this->service()->getPaymentMethods(-1);
|
||||
|
||||
foreach ($pms as $pm) {
|
||||
if ($pm['gateway_type_id'] == GatewayType::BACS) {
|
||||
$cg = CompanyGateway::find($pm['company_gateway_id']);
|
||||
|
||||
if ($cg && ! property_exists($cg->fees_and_limits, GatewayType::BACS)) {
|
||||
$fees_and_limits = $cg->fees_and_limits;
|
||||
$fees_and_limits->{GatewayType::BACS} = new FeesAndLimits;
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
}
|
||||
|
||||
if ($cg && $cg->fees_and_limits->{GatewayType::BACS}->is_enabled) {
|
||||
return $cg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//todo refactor this - it is only searching for existing tokens
|
||||
public function getBankTransferGateway() :?CompanyGateway
|
||||
|
@ -144,6 +144,7 @@ class Gateway extends StaticModel
|
||||
GatewayType::DIRECT_DEBIT => ['refund' => false, 'token_billing' => false, 'webhooks' => ['payment_intent.processing','payment_intent.succeeded','payment_intent.partially_funded']],
|
||||
GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false],
|
||||
GatewayType::APPLE_PAY => ['refund' => false, 'token_billing' => false],
|
||||
GatewayType::BACS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||
GatewayType::SOFORT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
GatewayType::KLARNA => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
GatewayType::SEPA => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
@ -190,6 +191,7 @@ class Gateway extends StaticModel
|
||||
GatewayType::EPS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
GatewayType::BANCONTACT => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
GatewayType::BECS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
GatewayType::BACS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
GatewayType::IDEAL => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
GatewayType::ACSS => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded', 'payment_intent.succeeded']],
|
||||
GatewayType::FPX => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable', 'charge.succeeded']],
|
||||
|
@ -80,6 +80,8 @@ class GatewayType extends StaticModel
|
||||
|
||||
const KLARNA = 23;
|
||||
|
||||
const BACS = 24;
|
||||
|
||||
public function gateway()
|
||||
{
|
||||
return $this->belongsTo(Gateway::class);
|
||||
@ -127,6 +129,8 @@ class GatewayType extends StaticModel
|
||||
return ctrans('texts.eps');
|
||||
case self::BECS:
|
||||
return ctrans('texts.becs');
|
||||
case self::BACS:
|
||||
return ctrans('texts.bacs');
|
||||
case self::ACSS:
|
||||
return ctrans('texts.acss');
|
||||
case self::DIRECT_DEBIT:
|
||||
|
@ -73,6 +73,7 @@ class PaymentType extends StaticModel
|
||||
const FPX = 46;
|
||||
const KLARNA = 47;
|
||||
const Interac_E_Transfer = 48;
|
||||
const BACS = 49;
|
||||
|
||||
public array $type_names = [
|
||||
self::CREDIT => 'payment_type_Credit',
|
||||
|
191
app/PaymentDrivers/Stripe/BACS.php
Normal file
191
app/PaymentDrivers/Stripe/BACS.php
Normal file
@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\Stripe;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
use App\PaymentDrivers\Stripe\Jobs\UpdateCustomer;
|
||||
use Stripe\Checkout\Session;
|
||||
use Stripe\PaymentIntent;
|
||||
use Stripe\PaymentMethod;
|
||||
use App\Utils\Number;
|
||||
|
||||
class BACS
|
||||
{
|
||||
public $stripe;
|
||||
|
||||
public function __construct(StripePaymentDriver $stripe)
|
||||
{
|
||||
$this->stripe = $stripe;
|
||||
}
|
||||
|
||||
public function authorizeView(array $data)
|
||||
{
|
||||
$customer = $this->stripe->findOrCreateCustomer();
|
||||
$data['session'] = Session::create([
|
||||
'payment_method_types' => ['bacs_debit'],
|
||||
'mode' => 'setup',
|
||||
'customer' => $customer->id,
|
||||
'success_url' => str_replace("%7B", "{", str_replace("%7D", "}", $this->buildAuthorizeUrl())),
|
||||
'cancel_url' => route('client.payment_methods.index'),
|
||||
]);
|
||||
return render('gateways.stripe.bacs.authorize', $data);
|
||||
}
|
||||
private function buildAuthorizeUrl(): string
|
||||
{
|
||||
return route('client.payment_methods.confirm', [
|
||||
'method' => GatewayType::BACS,
|
||||
'session_id' => "{CHECKOUT_SESSION_ID}",
|
||||
]);
|
||||
}
|
||||
|
||||
public function authorizeResponse($request)
|
||||
{
|
||||
$this->stripe->init();
|
||||
if ($request->session_id) {
|
||||
$session = $this->stripe->stripe->checkout->sessions->retrieve($request->session_id, ['expand' => ['setup_intent']]);
|
||||
|
||||
$customer = $this->stripe->findOrCreateCustomer();
|
||||
$this->stripe->attach($session->setup_intent->payment_method, $customer);
|
||||
$payment_method = $this->stripe->getStripePaymentMethod($session->setup_intent->payment_method);
|
||||
$this->storePaymentMethod($payment_method, $customer);
|
||||
}
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
$data['gateway'] = $this->stripe;
|
||||
$data['amount'] = $data['total']['amount_with_fee'];
|
||||
$data['payment_hash'] = $this->stripe->payment_hash->hash;
|
||||
|
||||
return render('gateways.stripe.bacs.pay', $data);
|
||||
}
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
|
||||
{
|
||||
$this->stripe->init();
|
||||
$invoice_numbers = collect($this->stripe->payment_hash->invoices())->pluck('invoice_number')->implode(',');
|
||||
$description = ctrans('texts.stripe_payment_text', ['invoicenumber' => $invoice_numbers, 'amount' => Number::formatMoney($request->amount, $this->stripe->client), 'client' => $this->stripe->client->present()->name()]);
|
||||
$payment_intent_data = [
|
||||
'amount' => $this->stripe->convertToStripeAmount($request->amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
|
||||
'currency' => $this->stripe->client->getCurrencyCode(),
|
||||
'customer' => $this->stripe->findOrCreateCustomer(),
|
||||
'description' => $description,
|
||||
'payment_method_types' => ['bacs_debit'],
|
||||
'metadata' => [
|
||||
'payment_hash' => $this->stripe->payment_hash->hash,
|
||||
'gateway_type_id' => GatewayType::BACS,
|
||||
],
|
||||
'payment_method' => $request->token,
|
||||
'confirm' => true,
|
||||
];
|
||||
$state = [
|
||||
'payment_hash' => $this->stripe->payment_hash->hash,
|
||||
'payment_intent' => $this->stripe->createPaymentIntent($payment_intent_data),
|
||||
];
|
||||
$state = array_merge($state, $request->all());
|
||||
|
||||
$state['customer'] = $state['payment_intent']->customer;
|
||||
|
||||
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $state);
|
||||
$this->stripe->payment_hash->save();
|
||||
|
||||
if ($state['payment_intent']->status == 'processing') {
|
||||
$this->stripe->logSuccessfulGatewayResponse(['response' => $state['payment_intent'], 'data' => $this->stripe->payment_hash], SystemLog::TYPE_STRIPE);
|
||||
|
||||
return $this->processSuccessfulPayment($state['payment_intent']);
|
||||
}
|
||||
|
||||
return $this->processUnsuccessfulPayment("An unknown error occured.");
|
||||
}
|
||||
|
||||
public function processSuccessfulPayment($payment_intent)
|
||||
{
|
||||
UpdateCustomer::dispatch($this->stripe->company_gateway->company->company_key, $this->stripe->company_gateway->id, $this->stripe->client->id);
|
||||
|
||||
$data = [
|
||||
'payment_method' => $payment_intent['id'],
|
||||
'payment_type' => PaymentType::BACS,
|
||||
'amount' => $this->stripe->convertFromStripeAmount($payment_intent->amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()),
|
||||
'transaction_reference' => $payment_intent['id'],
|
||||
'gateway_type_id' => GatewayType::BACS,
|
||||
];
|
||||
|
||||
$payment = $this->stripe->createPayment($data, Payment::STATUS_PENDING);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment_intent, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_STRIPE,
|
||||
$this->stripe->client,
|
||||
$this->stripe->client->company,
|
||||
);
|
||||
|
||||
|
||||
return redirect()->route('client.payments.show', ['payment' => $this->stripe->encodePrimaryKey($payment->id)]);
|
||||
}
|
||||
|
||||
public function processUnsuccessfulPayment($server_response)
|
||||
{
|
||||
$this->stripe->sendFailureMail($server_response);
|
||||
|
||||
$message = [
|
||||
'server_response' => $server_response,
|
||||
'data' => $this->stripe->payment_hash->data,
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_STRIPE,
|
||||
$this->stripe->client,
|
||||
$this->stripe->client->company,
|
||||
);
|
||||
|
||||
throw new PaymentFailed('Failed to process the payment.', 500);
|
||||
}
|
||||
|
||||
private function storePaymentMethod($method, $customer)
|
||||
{
|
||||
try {
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->brand = (string) $method->bacs_debit->sort_code;
|
||||
$payment_meta->last4 = (string) $method->bacs_debit->last4;
|
||||
$payment_meta->state = 'unauthorized';
|
||||
$payment_meta->type = GatewayType::BACS;
|
||||
|
||||
$data = [
|
||||
'payment_meta' => $payment_meta,
|
||||
'token' => $method->id,
|
||||
'payment_method_id' => GatewayType::BACS,
|
||||
];
|
||||
$clientgateway = ClientGatewayToken::query()
|
||||
->where('token', $method->id)
|
||||
->first();
|
||||
if (!$clientgateway){
|
||||
$this->stripe->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return $this->stripe->processInternallyFailedPayment($this->stripe, $e);
|
||||
}
|
||||
}
|
||||
}
|
@ -79,6 +79,9 @@ class Charge
|
||||
if ($cgt->gateway_type_id == GatewayType::SEPA) {
|
||||
$data['payment_method_types'] = ['sepa_debit'];
|
||||
}
|
||||
if ($cgt->gateway_type_id == GatewayType::BACS) {
|
||||
$data['payment_method_types'] = ['bacs_debit'];
|
||||
}
|
||||
|
||||
/* Should improve token billing with client not present */
|
||||
if (!auth()->guard('contact')->check()) {
|
||||
@ -135,8 +138,15 @@ class Charge
|
||||
if ($cgt->gateway_type_id == GatewayType::SEPA) {
|
||||
$payment_method_type = PaymentType::SEPA;
|
||||
$status = Payment::STATUS_PENDING;
|
||||
} else {
|
||||
if (isset($response->latest_charge)) {
|
||||
|
||||
} elseif ($cgt->gateway_type_id == GatewayType::BACS){
|
||||
$payment_method_type = PaymentType::BACS;
|
||||
$status = Payment::STATUS_PENDING;
|
||||
}
|
||||
else {
|
||||
|
||||
if(isset($response->latest_charge)) {
|
||||
|
||||
$charge = \Stripe\Charge::retrieve($response->latest_charge, $this->stripe->stripe_connect_auth);
|
||||
$payment_method_type = $charge->payment_method_details->card->brand;
|
||||
} elseif (isset($response->charges->data[0]->payment_method_details->card->brand)) {
|
||||
@ -147,9 +157,11 @@ class Charge
|
||||
|
||||
$status = Payment::STATUS_COMPLETED;
|
||||
}
|
||||
|
||||
if (!in_array($response?->status, ['succeeded', 'processing'])) {
|
||||
$this->stripe->processInternallyFailedPayment($this->stripe, new \Exception('Auto billing failed.', 400));
|
||||
|
||||
|
||||
if(!in_array($response?->status, ['succeeded', 'processing'])){
|
||||
$this->stripe->processInternallyFailedPayment($this->stripe, new \Exception('Auto billing failed.',400));
|
||||
|
||||
}
|
||||
|
||||
$data = [
|
||||
@ -195,6 +207,8 @@ class Charge
|
||||
break;
|
||||
case PaymentType::SEPA:
|
||||
return PaymentType::SEPA;
|
||||
case PaymentType::BACS:
|
||||
return PaymentType::BACS;
|
||||
default:
|
||||
return PaymentType::CREDIT_CARD_OTHER;
|
||||
break;
|
||||
|
@ -89,6 +89,7 @@ class PaymentIntentWebhook implements ShouldQueue
|
||||
|
||||
$charge_id = false;
|
||||
|
||||
|
||||
if (isset($this->stripe_request['object']['charges']) && optional($this->stripe_request['object']['charges']['data'][0])['id']) {
|
||||
$charge_id = $this->stripe_request['object']['charges']['data'][0]['id'];
|
||||
} // API VERSION 2018
|
||||
@ -119,8 +120,9 @@ class PaymentIntentWebhook implements ShouldQueue
|
||||
->where('transaction_reference', $charge['id'])
|
||||
->first();
|
||||
|
||||
//return early
|
||||
if ($payment && $payment->status_id == Payment::STATUS_COMPLETED) {
|
||||
//return early
|
||||
if($payment && $payment->status_id == Payment::STATUS_COMPLETED){
|
||||
|
||||
nlog(" payment found and status correct - returning ");
|
||||
return;
|
||||
} elseif ($payment) {
|
||||
@ -186,7 +188,11 @@ class PaymentIntentWebhook implements ShouldQueue
|
||||
}
|
||||
|
||||
$this->updateAchPayment($payment_hash, $client, $meta);
|
||||
} elseif(isset($pi['payment_method_types']) && in_array('bacs_debit', $pi['payment_method_types'])){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function updateAchPayment($payment_hash, $client, $meta)
|
||||
@ -206,7 +212,7 @@ class PaymentIntentWebhook implements ShouldQueue
|
||||
'transaction_reference' => $meta['transaction_reference'],
|
||||
'gateway_type_id' => GatewayType::BANK_TRANSFER,
|
||||
];
|
||||
|
||||
|
||||
$payment = $driver->createPayment($data, Payment::STATUS_COMPLETED);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
@ -254,13 +260,14 @@ class PaymentIntentWebhook implements ShouldQueue
|
||||
}
|
||||
|
||||
$driver->storeGatewayToken($data, $additional_data);
|
||||
|
||||
} catch(\Exception $e) {
|
||||
|
||||
nlog("failed to import payment methods");
|
||||
nlog($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function updateCreditCardPayment($payment_hash, $client, $meta)
|
||||
{
|
||||
$company_gateway = CompanyGateway::find($this->company_gateway_id);
|
||||
@ -278,7 +285,7 @@ class PaymentIntentWebhook implements ShouldQueue
|
||||
'transaction_reference' => $meta['transaction_reference'],
|
||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||
];
|
||||
|
||||
|
||||
$payment = $driver->createPayment($data, Payment::STATUS_COMPLETED);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
@ -290,4 +297,5 @@ class PaymentIntentWebhook implements ShouldQueue
|
||||
$client->company,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,6 +41,9 @@ class StripeWebhook implements ShouldQueue
|
||||
'charge.failed',
|
||||
'payment_intent.succeeded',
|
||||
'payment_intent.payment_failed',
|
||||
'mandate.updated',
|
||||
'checkout.session.completed',
|
||||
'payment_method.automatically_updated'
|
||||
];
|
||||
|
||||
public function __construct(string $company_key, int $company_gateway_id)
|
||||
|
@ -26,6 +26,7 @@ use App\Models\GatewayType;
|
||||
use App\Models\PaymentHash;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\Client;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Models\ClientGatewayToken;
|
||||
@ -33,6 +34,9 @@ use App\PaymentDrivers\Stripe\ACH;
|
||||
use App\PaymentDrivers\Stripe\EPS;
|
||||
use App\PaymentDrivers\Stripe\FPX;
|
||||
use App\PaymentDrivers\Stripe\ACSS;
|
||||
use App\PaymentDrivers\Stripe\Alipay;
|
||||
use App\PaymentDrivers\Stripe\ApplePay;
|
||||
use App\PaymentDrivers\Stripe\BACS;
|
||||
use App\PaymentDrivers\Stripe\BECS;
|
||||
use App\PaymentDrivers\Stripe\SEPA;
|
||||
use App\PaymentDrivers\Stripe\iDeal;
|
||||
@ -59,6 +63,7 @@ use App\PaymentDrivers\Stripe\Jobs\PaymentIntentFailureWebhook;
|
||||
use App\PaymentDrivers\Stripe\Jobs\PaymentIntentProcessingWebhook;
|
||||
use App\PaymentDrivers\Stripe\Jobs\PaymentIntentPartiallyFundedWebhook;
|
||||
|
||||
|
||||
class StripePaymentDriver extends BaseDriver
|
||||
{
|
||||
use MakesHash, Utilities;
|
||||
@ -96,6 +101,7 @@ class StripePaymentDriver extends BaseDriver
|
||||
GatewayType::ACSS => ACSS::class,
|
||||
GatewayType::FPX => FPX::class,
|
||||
GatewayType::KLARNA => Klarna::class,
|
||||
GatewayType::BACS => BACS::class,
|
||||
GatewayType::DIRECT_DEBIT => BankTransfer::class,
|
||||
];
|
||||
|
||||
@ -234,6 +240,14 @@ class StripePaymentDriver extends BaseDriver
|
||||
&& in_array($this->client->country->iso_3166_3, ['CAN', 'USA'])) {
|
||||
$types[] = GatewayType::ACSS;
|
||||
}
|
||||
if ($this->client
|
||||
&& $this->client->currency()
|
||||
&& in_array($this->client->currency()->code, ['GBP'])
|
||||
&& isset($this->client->country)
|
||||
&& in_array($this->client->company->country()->getID(), ['826'])
|
||||
&& in_array($this->client->country->iso_3166_3, ['GBR'])) {
|
||||
$types[] = GatewayType::BACS;
|
||||
}
|
||||
if ($this->client
|
||||
&& $this->client->currency()
|
||||
&& in_array($this->client->currency()->code, ['EUR', 'DKK', 'GBP', 'NOK', 'SEK', 'AUD', 'NZD', 'CAD', 'PLN', 'CHF'])
|
||||
@ -245,7 +259,7 @@ class StripePaymentDriver extends BaseDriver
|
||||
&& $this->client->currency()
|
||||
&& in_array($this->client->currency()->code, ['EUR', 'DKK', 'GBP', 'NOK', 'SEK', 'AUD', 'NZD', 'CAD', 'PLN', 'CHF', 'USD'])
|
||||
&& isset($this->client->country)
|
||||
&& in_array($this->client->company->country()->getID(), ['840'])
|
||||
&& in_array($this->client->company->country()->id, ['840'])
|
||||
&& in_array($this->client->country->iso_3166_3, ['AUT','BEL','DNK','FIN','FRA','DEU','IRL','ITA','NLD','NOR','ESP','SWE','GBR','USA'])) {
|
||||
$types[] = GatewayType::KLARNA;
|
||||
}
|
||||
@ -310,6 +324,8 @@ class StripePaymentDriver extends BaseDriver
|
||||
return 'gateways.stripe.bancontact';
|
||||
case GatewayType::BECS:
|
||||
return 'gateways.stripe.becs';
|
||||
case GatewayType::BACS:
|
||||
return 'gateways.stripe.bacs';
|
||||
case GatewayType::ACSS:
|
||||
return 'gateways.stripe.acss';
|
||||
case GatewayType::FPX:
|
||||
@ -663,8 +679,6 @@ class StripePaymentDriver extends BaseDriver
|
||||
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request)
|
||||
{
|
||||
// if($request->type === 'payment_intent.requires_action')
|
||||
// nlog($request->all());
|
||||
|
||||
if ($request->type === 'customer.source.updated') {
|
||||
$ach = new ACH($this);
|
||||
@ -752,6 +766,63 @@ class StripePaymentDriver extends BaseDriver
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($request->type === "payment_method.automatically_updated"){
|
||||
// Will notify customer on updated information
|
||||
return response()->json([], 200);
|
||||
} elseif ($request->type === "checkout.session.completed"){
|
||||
// Store payment token for Stripe BACS
|
||||
$this->init();
|
||||
$setup_intent = $this->stripe->setupIntents->retrieve($request->data['object']['setup_intent'], []);
|
||||
$clientpayment_token = ClientGatewayToken::where('gateway_customer_reference', $request->data['object']['customer'])->first();
|
||||
if ($clientpayment_token){
|
||||
$this->client = Client::where('id', $clientpayment_token->client_id)->first();
|
||||
$customer = $this->findOrCreateCustomer();
|
||||
$this->attach($setup_intent->payment_method, $customer);
|
||||
$payment_method = $this->getStripePaymentMethod($setup_intent->payment_method);
|
||||
$payment_meta = new \stdClass;
|
||||
$payment_meta->brand = (string) $payment_method->bacs_debit->sort_code;
|
||||
$payment_meta->last4 = (string) $payment_method->bacs_debit->last4;
|
||||
$payment_meta->state = 'unauthorized';
|
||||
$payment_meta->type = GatewayType::BACS;
|
||||
|
||||
$data = [
|
||||
'payment_meta' => $payment_meta,
|
||||
'token' => $payment_method->id,
|
||||
'payment_method_id' => GatewayType::BACS,
|
||||
];
|
||||
$clientgateway = ClientGatewayToken::query()
|
||||
->where('token', $payment_method)
|
||||
->first();
|
||||
if (!$clientgateway){
|
||||
$this->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]);
|
||||
}
|
||||
}
|
||||
return response()->json([], 200);
|
||||
} elseif ($request->type === "mandate.updated"){
|
||||
// Check if payment method BACS is still valid
|
||||
if ($request->data['object']['status'] === "active"){
|
||||
// Check if payment method exists
|
||||
$payment_method = (string) $request->data['object']['payment_method'];
|
||||
$clientgateway = ClientGatewayToken::query()
|
||||
->where('token', $payment_method)
|
||||
->first();
|
||||
if ($clientgateway){
|
||||
$clientgateway->meta->state = 'authorized';
|
||||
$clientgateway->update();
|
||||
};
|
||||
return response()->json([], 200);
|
||||
}
|
||||
elseif ($request->data['object']['status'] === "inactive" && $request->data['object']['payment_method']){
|
||||
// Delete payment method
|
||||
$clientgateway = ClientGatewayToken::query()
|
||||
->where('token', $request->data['object']['payment_method'])
|
||||
->first();
|
||||
$clientgateway->delete();
|
||||
return response()->json([], 200);
|
||||
}
|
||||
elseif ($request->data['object']['status'] === "pending"){
|
||||
return response()->json([], 200);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([], 200);
|
||||
|
39
database/migrations/2022_16_12_54687_add_stripe_bacs.php
Normal file
39
database/migrations/2022_16_12_54687_add_stripe_bacs.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\PaymentType;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$pt = PaymentType::find(49);
|
||||
|
||||
if(!$pt)
|
||||
{
|
||||
$type = new PaymentType();
|
||||
$type->id = 49;
|
||||
$type->name = 'BACS';
|
||||
$type->gateway_type_id = GatewayType::BACS;
|
||||
$type->save();
|
||||
}
|
||||
|
||||
$gt = GatewayType::find(24);
|
||||
|
||||
if(!$gt)
|
||||
{
|
||||
$type = new GatewayType();
|
||||
$type->id = 24;
|
||||
$type->alias = 'bacs';
|
||||
$type->name = 'BACS';
|
||||
$type->save();
|
||||
}
|
||||
}
|
||||
};
|
@ -4299,6 +4299,9 @@ $LANG = array(
|
||||
'klarna' => 'Klarna',
|
||||
'eps' => 'EPS',
|
||||
'becs' => 'BECS Direct Debit',
|
||||
'bacs' => 'BACS Direct Debit',
|
||||
'payment_type_BACS' => 'BACS Direct Debit',
|
||||
'missing_payment_method' => 'Please add a payment method first, before trying to pay.',
|
||||
'becs_mandate' => 'By providing your bank account details, you agree to this <a class="underline" href="https://stripe.com/au-becs-dd-service-agreement/legal">Direct Debit Request and the Direct Debit Request service agreement</a>, and authorise Stripe Payments Australia Pty Ltd ACN 160 180 343 Direct Debit User ID number 507156 (“Stripe”) to debit your account through the Bulk Electronic Clearing System (BECS) on behalf of :company (the “Merchant”) for any amounts separately communicated to you by the Merchant. You certify that you are either an account holder or an authorised signatory on the account listed above.',
|
||||
'you_need_to_accept_the_terms_before_proceeding' => 'You need to accept the terms before proceeding.',
|
||||
'direct_debit' => 'Direct Debit',
|
||||
@ -4907,7 +4910,7 @@ $LANG = array(
|
||||
'export_company' => 'Create company backup',
|
||||
'backup' => 'Backup',
|
||||
'notification_purchase_order_created_body' => 'The following purchase_order :purchase_order was created for vendor :vendor for :amount.',
|
||||
'notification_purchase_order_created_subject' => 'Purchase Order :purchase_order was created for :vendor',
|
||||
'notification_purchase_order_created_subject' => 'Purchase Order :purchase_order was created for :vendor',
|
||||
'notification_purchase_order_sent_subject' => 'Purchase Order :purchase_order was sent to :vendor',
|
||||
'notification_purchase_order_sent' => 'The following vendor :vendor was emailed Purchase Order :purchase_order for :amount.',
|
||||
'subscription_blocked' => 'This product is a restricted item, please contact the vendor for further information.',
|
||||
|
2
public/js/clients/payments/stripe-bacs.js
vendored
Normal file
2
public/js/clients/payments/stripe-bacs.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! For license information please see stripe-bacs.js.LICENSE.txt */
|
||||
(()=>{var e,t,n,o,r,a;function i(e,t){for(var n=0;n<t.length;n++){var o=t[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,o.key,o)}}function u(e,t,n){return t&&i(e.prototype,t),n&&i(e,n),Object.defineProperty(e,"prototype",{writable:!1}),e}function c(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var d=u((function e(t,n){var o=this;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),c(this,"setupStripe",(function(){return o.stripeConnect?o.stripe=Stripe(o.key,{stripeAccount:o.stripeConnect}):o.stripe=Stripe(o.key),o})),c(this,"payment_data",void 0),c(this,"handle",(function(){o.onlyAuthorization?document.getElementById("authorize-bacs").addEventListener("click",(function(e){document.getElementById("authorize-bacs").disabled=!0,document.querySelector("#authorize-bacs > svg").classList.remove("hidden"),document.querySelector("#authorize-bacs > span").classList.add("hidden"),location.href=document.querySelector("meta[name=stripe-redirect-url]").content})):(o.payNowButton=document.getElementById("pay-now"),document.getElementById("pay-now").addEventListener("click",(function(e){o.payNowButton.disabled=!0,o.payNowButton.querySelector("svg").classList.remove("hidden"),o.payNowButton.querySelector("span").classList.add("hidden"),document.getElementById("server-response").submit()})),o.payment_data=Array.from(document.getElementsByClassName("toggle-payment-with-token")),o.payment_data.length>0?o.payment_data.forEach((function(e){return e.addEventListener("click",(function(e){document.querySelector("input[name=token]").value=e.target.dataset.token}))})):(o.errors.textContent=document.querySelector("meta[name=translation-payment-method-required]").content,o.errors.hidden=!1,o.payNowButton.disabled=!0,o.payNowButton.querySelector("span").classList.remove("hidden"),o.payNowButton.querySelector("svg").classList.add("hidden")))})),this.key=t,this.errors=document.getElementById("errors"),this.stripeConnect=n,this.onlyAuthorization=m})),s=null!==(e=null===(t=document.querySelector('meta[name="stripe-publishable-key"]'))||void 0===t?void 0:t.content)&&void 0!==e?e:"",l=null!==(n=null===(o=document.querySelector('meta[name="stripe-account-id"]'))||void 0===o?void 0:o.content)&&void 0!==n?n:"",m=null!==(r=null===(a=document.querySelector('meta[name="only-authorization"]'))||void 0===a?void 0:a.content)&&void 0!==r?r:"";new d(s,l).setupStripe().handle()})();
|
9
public/js/clients/payments/stripe-bacs.js.LICENSE.txt
Normal file
9
public/js/clients/payments/stripe-bacs.js.LICENSE.txt
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
@ -1,49 +1,50 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=7b6124b74168ccb1cc7da22f7a2bc9ed",
|
||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=b6723e0b8ea33f1f50617fa5f289a9d3",
|
||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=faf4828cc6b3b73b69c53d3046661884",
|
||||
"/js/clients/payments/forte-credit-card-payment.js": "/js/clients/payments/forte-credit-card-payment.js?id=f42dd0caddb3603e71db061924c4b172",
|
||||
"/js/clients/payments/forte-ach-payment.js": "/js/clients/payments/forte-ach-payment.js?id=b8173c7c0dee76bf9ae6312a963ae0e4",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=207f218c44553470287f35f33a7eb154",
|
||||
"/js/clients/payments/stripe-klarna.js": "/js/clients/payments/stripe-klarna.js?id=7268f9282c6bb3b04d19d11a7b0c1681",
|
||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=404b7ee18e420de0e73f5402b7e39122",
|
||||
"/js/clients/purchase_orders/action-selectors.js": "/js/clients/purchase_orders/action-selectors.js?id=2f0c4e3bab30a98e33ac768255113174",
|
||||
"/js/clients/purchase_orders/accept.js": "/js/clients/purchase_orders/accept.js?id=9bb483a89a887f753e49c0b635d6276a",
|
||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=752e2bb6390f1a422e31868cf2a2bf67",
|
||||
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=4fc5dec1bc4fc21b9e32b1b490c3e7ae",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=0a4361f9c468fa087ff543f1793adc7d",
|
||||
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=7cb96275b3eb4901054564c654fb60e3",
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=3a4c5cfac7dd4c9218be55945c3c8e85",
|
||||
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=00615ec62b99e3245769d4603e6053ce",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=6e7c8ab039a239727317ae8622de10db",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=8cab3339ef48418e1fb2e7a9259d51ca",
|
||||
"/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=682de6347049b32c9488f39c78a68ace",
|
||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=d3c404bb646f1aeaf2382a8c57ab8e1a",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=e1c0599d6f7dc163b549a6df0b3490b4",
|
||||
"/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js?id=8b036822abaa4ceb379008fc14208dc2",
|
||||
"/js/clients/payments/braintree-paypal.js": "/js/clients/payments/braintree-paypal.js?id=de0b1d0c6da7ff509bef3aee8d09e7f8",
|
||||
"/js/clients/payments/wepay-credit-card.js": "/js/clients/payments/wepay-credit-card.js?id=92ef8632637d335cd0e4bc29a05b7df8",
|
||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=af85b3f6d53c55b5d0e3a80ef58ce0de",
|
||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=3869bc6d80acc83f81d9afe8efaae728",
|
||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=7cd5a1d95d33ada211ce185ad6e4bb33",
|
||||
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=27274d334aed0824ce4654fa22132f7f",
|
||||
"/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=f85ebb6a77002afd350086d1274b6af5",
|
||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=238e7001420a22b001856193689a1e70",
|
||||
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=13e043123f1e58409394458a70461d63",
|
||||
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=494f58d2fd8984792833ba7d3055de08",
|
||||
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=77d4e397d193196e482af80737bff64a",
|
||||
"/js/clients/payment_methods/authorize-checkout-card.js": "/js/clients/payment_methods/authorize-checkout-card.js?id=659c4287fb8ef1c458071c206c4d965d",
|
||||
"/js/clients/payments/stripe-giropay.js": "/js/clients/payments/stripe-giropay.js?id=852a9abf5f3a29f5d7d2f989cbeab374",
|
||||
"/js/clients/payments/stripe-acss.js": "/js/clients/payments/stripe-acss.js?id=447c587a5eeb0c1de3091c8358db7ad7",
|
||||
"/js/clients/payments/stripe-bancontact.js": "/js/clients/payments/stripe-bancontact.js?id=f694d3f9f01e4550cb5a3eb6cb43c12d",
|
||||
"/js/clients/payments/stripe-becs.js": "/js/clients/payments/stripe-becs.js?id=97ea3555a8504662eda5fce9c9115e5a",
|
||||
"/js/clients/payments/stripe-eps.js": "/js/clients/payments/stripe-eps.js?id=146d48d03f5fc4b1cf122189119e2877",
|
||||
"/js/clients/payments/stripe-ideal.js": "/js/clients/payments/stripe-ideal.js?id=34cf4ee3f189427fb69d0df8f5a4b766",
|
||||
"/js/clients/payments/stripe-przelewy24.js": "/js/clients/payments/stripe-przelewy24.js?id=cfdcc5bf20d6bfa09700708dfdd943e2",
|
||||
"/js/clients/payments/stripe-browserpay.js": "/js/clients/payments/stripe-browserpay.js?id=7015e43eb5f9f9f2f45f54b41b5780a0",
|
||||
"/js/clients/payments/stripe-fpx.js": "/js/clients/payments/stripe-fpx.js?id=243c2929386b10c6a0c49ca3bcabfb2d",
|
||||
"/css/app.css": "/css/app.css?id=d3b1387842383d1983c767978d20ec86",
|
||||
"/js/app.js": "/js/app.js?id=19300612c6880925e8043b61e8d49632",
|
||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=9fb77e87fe0f85a367050e08f79ec9df",
|
||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=803182f668c39d631ca5c55437876da4",
|
||||
"/js/clients/payments/forte-credit-card-payment.js": "/js/clients/payments/forte-credit-card-payment.js?id=6e9f466c5504d3753f9b4ffc6f947095",
|
||||
"/js/clients/payments/forte-ach-payment.js": "/js/clients/payments/forte-ach-payment.js?id=1d10fcc52a1f15858e5da216f1df45ec",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=7bed15f51bca764378d9a3aa605b8664",
|
||||
"/js/clients/payments/stripe-klarna.js": "/js/clients/payments/stripe-klarna.js?id=5770e0d82d3843c68903744530f5ae73",
|
||||
"/js/clients/payments/stripe-bacs.js": "/js/clients/payments/stripe-bacs.js?id=5739aad61ac7bbb20f2149d203849ff7",
|
||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=d4f86ddee4e8a1d6e9719010aa0fe62b",
|
||||
"/js/clients/purchase_orders/action-selectors.js": "/js/clients/purchase_orders/action-selectors.js?id=160b8161599fc2429b449b0970d3ba6c",
|
||||
"/js/clients/purchase_orders/accept.js": "/js/clients/purchase_orders/accept.js?id=ddd4aa4069ea79411eeec367b7d5986d",
|
||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=28221de8f1cb37f845ba4ec59bcd8867",
|
||||
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=1c5493a4c53a5b862d07ee1818179ea9",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=0274ab4f8d2b411f2a2fe5142301e7af",
|
||||
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=4bd34a0b160f6f29b3096d870ac4d308",
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=6fb63bae43d077b5061f4dadfe8dffc8",
|
||||
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=61a346e1977d3a1fec3634b234baa25c",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=809de47258a681f0ffebe787dd6a9a93",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=27560b012f166f8b9417ced2188aab70",
|
||||
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=8ce33c3deae058ad314fb8357e5be63b",
|
||||
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=be5307abc990bb44f2f92628103b1d98",
|
||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=c2caa29f753ad1f3a12ca45acddacd72",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=2b2fe55f926789abc52f19111006e1ec",
|
||||
"/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js?id=8e3b1c4c78c976ff0c43cb739c26b1f3",
|
||||
"/js/clients/payments/braintree-paypal.js": "/js/clients/payments/braintree-paypal.js?id=5764a8d406c1eda848d073f10d178626",
|
||||
"/js/clients/payments/wepay-credit-card.js": "/js/clients/payments/wepay-credit-card.js?id=dbba20d70fbebb326ddbc46115af9771",
|
||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=b8706d7de6127f184ad19b2a810880be",
|
||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=e0b1231a7bf6252672836222285c0f52",
|
||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=bbab588ed009a93345bec520cbe66869",
|
||||
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=31d068e55757636f34834bc2494250df",
|
||||
"/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=6d8c7fd66d911b20cdc4248e33db1b3a",
|
||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=b180fd6378d3723d3e9133e0b1943ac6",
|
||||
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=7971b212e8a849fe36bfe915f81023bd",
|
||||
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=c36ab5621413ef1de7c864bc8eb7439e",
|
||||
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=b258636d8bae366e9d8f54274f437181",
|
||||
"/js/clients/payment_methods/authorize-checkout-card.js": "/js/clients/payment_methods/authorize-checkout-card.js?id=e43f862d70d8710761f0856e528ec3d1",
|
||||
"/js/clients/payments/stripe-giropay.js": "/js/clients/payments/stripe-giropay.js?id=72ad4ad19297f211c2e6d0fa1fa1f76d",
|
||||
"/js/clients/payments/stripe-acss.js": "/js/clients/payments/stripe-acss.js?id=90b1805b1ca0264474b38054a2664c5b",
|
||||
"/js/clients/payments/stripe-bancontact.js": "/js/clients/payments/stripe-bancontact.js?id=03e5d7ee187e76b0b7c16bfa91804a8a",
|
||||
"/js/clients/payments/stripe-becs.js": "/js/clients/payments/stripe-becs.js?id=de2bd0ef2859e19e4f98ea9d6d11cb54",
|
||||
"/js/clients/payments/stripe-eps.js": "/js/clients/payments/stripe-eps.js?id=213d9ad34a79144a0d3345cb6a262e95",
|
||||
"/js/clients/payments/stripe-ideal.js": "/js/clients/payments/stripe-ideal.js?id=0a6b434e3849db26c35a143e0347e914",
|
||||
"/js/clients/payments/stripe-przelewy24.js": "/js/clients/payments/stripe-przelewy24.js?id=3d53d2f7d0291d9f92cf7414dd2d351c",
|
||||
"/js/clients/payments/stripe-browserpay.js": "/js/clients/payments/stripe-browserpay.js?id=db71055862995fd6ae21becfc587a3de",
|
||||
"/js/clients/payments/stripe-fpx.js": "/js/clients/payments/stripe-fpx.js?id=914a6846ad1e5584635e7430fef76875",
|
||||
"/css/app.css": "/css/app.css?id=aeba2a01bf369ac522071ab602096c66",
|
||||
"/css/card-js.min.css": "/css/card-js.min.css?id=62afeb675235451543ada60afcedcb7c",
|
||||
"/vendor/clipboard.min.js": "/vendor/clipboard.min.js?id=15f52a1ee547f2bdd46e56747332ca2d"
|
||||
}
|
||||
|
87
resources/js/clients/payments/stripe-bacs.js
vendored
Normal file
87
resources/js/clients/payments/stripe-bacs.js
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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 ProcessBACS {
|
||||
constructor(key, stripeConnect) {
|
||||
this.key = key;
|
||||
this.errors = document.getElementById('errors');
|
||||
this.stripeConnect = stripeConnect;
|
||||
this.onlyAuthorization = onlyAuthorization;
|
||||
}
|
||||
|
||||
setupStripe = () => {
|
||||
|
||||
if (this.stripeConnect){
|
||||
// this.stripe.stripeAccount = this.stripeConnect;
|
||||
|
||||
this.stripe = Stripe(this.key, {
|
||||
stripeAccount: this.stripeConnect,
|
||||
});
|
||||
|
||||
}
|
||||
else {
|
||||
this.stripe = Stripe(this.key);
|
||||
}
|
||||
|
||||
|
||||
return this;
|
||||
};
|
||||
payment_data;
|
||||
|
||||
handle = () => {
|
||||
|
||||
if (this.onlyAuthorization) {
|
||||
document.getElementById('authorize-bacs').addEventListener('click', (e) => {
|
||||
document.getElementById('authorize-bacs').disabled = true;
|
||||
document.querySelector('#authorize-bacs > svg').classList.remove('hidden');
|
||||
document.querySelector('#authorize-bacs > span').classList.add('hidden');
|
||||
location.href=document.querySelector('meta[name=stripe-redirect-url]').content;
|
||||
});}
|
||||
else{
|
||||
this.payNowButton = document.getElementById('pay-now');
|
||||
document.getElementById('pay-now').addEventListener('click', (e) => {
|
||||
this.payNowButton.disabled = true;
|
||||
this.payNowButton.querySelector('svg').classList.remove('hidden');
|
||||
this.payNowButton.querySelector('span').classList.add('hidden');
|
||||
document.getElementById('server-response').submit();
|
||||
});
|
||||
|
||||
this.payment_data = Array.from(document.getElementsByClassName('toggle-payment-with-token'));
|
||||
if (this.payment_data.length > 0){
|
||||
this.payment_data.forEach((element) =>
|
||||
element.addEventListener('click', (element) => {
|
||||
document.querySelector('input[name=token]').value =
|
||||
element.target.dataset.token;
|
||||
})
|
||||
);}
|
||||
else{
|
||||
this.errors.textContent = document.querySelector(
|
||||
'meta[name=translation-payment-method-required]'
|
||||
).content;
|
||||
this.errors.hidden = false;
|
||||
this.payNowButton.disabled = true;
|
||||
this.payNowButton.querySelector('span').classList.remove('hidden');
|
||||
this.payNowButton.querySelector('svg').classList.add('hidden');
|
||||
}}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const publishableKey = document.querySelector(
|
||||
'meta[name="stripe-publishable-key"]'
|
||||
)?.content ?? '';
|
||||
|
||||
const stripeConnect =
|
||||
document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
|
||||
const onlyAuthorization =
|
||||
document.querySelector('meta[name="only-authorization"]')?.content ?? '';
|
||||
|
||||
new ProcessBACS(publishableKey, stripeConnect).setupStripe().handle();
|
18
resources/js/clients/payments/stripe-sepa.js
vendored
18
resources/js/clients/payments/stripe-sepa.js
vendored
@ -5,7 +5,7 @@
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
class ProcessSEPA {
|
||||
@ -215,6 +215,22 @@ class ProcessSEPA {
|
||||
document.querySelector('#pay-now > svg').classList.add('hidden');
|
||||
document.querySelector('#pay-now > span').classList.remove('hidden');
|
||||
}
|
||||
handleSuccess(result) {
|
||||
document.querySelector(
|
||||
'input[name="gateway_response"]'
|
||||
).value = JSON.stringify(result.paymentIntent);
|
||||
|
||||
let tokenBillingCheckbox = document.querySelector(
|
||||
'input[name="token-billing-checkbox"]:checked'
|
||||
);
|
||||
|
||||
if (tokenBillingCheckbox) {
|
||||
document.querySelector('input[name="store_card"]').value =
|
||||
tokenBillingCheckbox.value;
|
||||
}
|
||||
|
||||
document.getElementById('server-response').submit();
|
||||
}
|
||||
}
|
||||
|
||||
const publishableKey =
|
||||
|
@ -25,6 +25,11 @@
|
||||
{{ ctrans('texts.bank_account') }}
|
||||
</a>
|
||||
@endif
|
||||
@if($client->getBACSGateway())
|
||||
<a data-cy="add-bacs-link" href="{{ route('client.payment_methods.create', ['method' => App\Models\GatewayType::BACS]) }}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition ease-in-out duration-150">
|
||||
{{ ctrans('texts.bacs') }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
@ -0,0 +1,38 @@
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'BACS', 'card_title' => 'BACS'])
|
||||
|
||||
@section('gateway_head')
|
||||
|
||||
@if($gateway->getConfigField('account_id'))
|
||||
<meta name="stripe-account-id" content="{{ $gateway->getConfigField('account_id') }}">
|
||||
<meta name="stripe-publishable-key" content="{{ config('ninja.ninja_stripe_publishable_key') }}">
|
||||
@else
|
||||
<meta name="stripe-publishable-key" content="{{ $gateway->getPublishableKey() }}">
|
||||
@endif
|
||||
<meta name="stripe-redirect-url" content="{{ $session->url }}">
|
||||
<meta name="only-authorization" content="true">
|
||||
|
||||
@endsection
|
||||
|
||||
@section('gateway_content')
|
||||
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::BACS]) }}" method="post" id="server_response">
|
||||
@csrf
|
||||
<input type="hidden" name="company_gateway_id" value="{{ $gateway->gateway_id }}">
|
||||
<input type="hidden" name="payment_method_id" value="1">
|
||||
<input type="hidden" name="gateway_response" id="gateway_response">
|
||||
<input type="hidden" name="is_default" id="is_default">
|
||||
</form>
|
||||
|
||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
|
||||
{{ ctrans('texts.bacs') }}
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.gateways.includes.pay_now', ['id' => 'authorize-bacs'])
|
||||
{{ ctrans('texts.add_payment_method') }}
|
||||
@endcomponent
|
||||
@endsection
|
||||
|
||||
@section('gateway_footer')
|
||||
<script src="https://js.stripe.com/v3/"></script>
|
||||
<script src="{{ asset('js/clients/payments/stripe-bacs.js') }}"></script>
|
||||
@endsection
|
@ -0,0 +1,50 @@
|
||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'BACS', 'card_title' => 'BACS'])
|
||||
|
||||
@section('gateway_head')
|
||||
@if($gateway->company_gateway->getConfigField('account_id'))
|
||||
<meta name="stripe-account-id" content="{{ $gateway->company_gateway->getConfigField('account_id') }}">
|
||||
<meta name="stripe-publishable-key" content="{{ config('ninja.ninja_stripe_publishable_key') }}">
|
||||
@else
|
||||
<meta name="stripe-publishable-key" content="{{ $gateway->company_gateway->getPublishableKey() }}">
|
||||
@endif
|
||||
<meta name="only-authorization" content="">
|
||||
<meta name="translation-payment-method-required" content="{{ ctrans('texts.missing_payment_method') }}">
|
||||
@endsection
|
||||
|
||||
@section('gateway_content')
|
||||
<form action="{{ route('client.payments.response') }}" method="post" id="server-response">
|
||||
@csrf
|
||||
<input type="hidden" name="company_gateway_id" value="{{ $gateway->getCompanyGatewayId() }}">
|
||||
<input type="hidden" name="payment_method_id" value="{{ $payment_method_id }}">
|
||||
<input type="hidden" name="token">
|
||||
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
|
||||
<input type="hidden" name="amount" value={{ $amount }}>
|
||||
</form>
|
||||
|
||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||
|
||||
@include('portal.ninja2020.gateways.includes.payment_details')
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')])
|
||||
{{ ctrans('texts.bacs') }} ({{ ctrans('texts.bank_transfer') }})
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
||||
@if (count($tokens) > 0)
|
||||
@foreach ($tokens as $token)
|
||||
<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>
|
||||
</label>
|
||||
@endforeach
|
||||
@endisset
|
||||
|
||||
@endcomponent
|
||||
@include('portal.ninja2020.gateways.includes.pay_now')
|
||||
@endsection
|
||||
|
||||
@push('footer')
|
||||
<script src="https://js.stripe.com/v3/"></script>
|
||||
<script src="{{ asset('js/clients/payments/stripe-bacs.js') }}"></script>
|
||||
@endpush
|
4
webpack.mix.js
vendored
4
webpack.mix.js
vendored
@ -26,6 +26,10 @@ mix.js("resources/js/app.js", "public/js")
|
||||
"resources/js/clients/payments/stripe-klarna.js",
|
||||
"public/js/clients/payments/stripe-klarna.js"
|
||||
)
|
||||
.js(
|
||||
"resources/js/clients/payments/stripe-bacs.js",
|
||||
"public/js/clients/payments/stripe-bacs.js"
|
||||
)
|
||||
.js(
|
||||
"resources/js/clients/invoices/action-selectors.js",
|
||||
"public/js/clients/invoices/action-selectors.js"
|
||||
|
Loading…
Reference in New Issue
Block a user