mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 13:12:50 +01:00
Merge pull request #6827 from beganovich/v5-726
Stripe: SEPA improvements
This commit is contained in:
commit
f038073b4a
@ -11,15 +11,15 @@
|
||||
|
||||
namespace App\PaymentDrivers\Stripe;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
|
||||
class SEPA
|
||||
{
|
||||
@ -29,6 +29,8 @@ class SEPA
|
||||
public function __construct(StripePaymentDriver $stripe)
|
||||
{
|
||||
$this->stripe = $stripe;
|
||||
|
||||
$this->stripe->init();
|
||||
}
|
||||
|
||||
public function authorizeView($data)
|
||||
@ -36,7 +38,8 @@ class SEPA
|
||||
return render('gateways.stripe.sepa.authorize', $data);
|
||||
}
|
||||
|
||||
public function paymentView(array $data) {
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
$data['gateway'] = $this->stripe;
|
||||
$data['payment_method_id'] = GatewayType::SEPA;
|
||||
$data['stripe_amount'] = $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency());
|
||||
@ -52,11 +55,19 @@ class SEPA
|
||||
'setup_future_usage' => 'off_session',
|
||||
'customer' => $this->stripe->findOrCreateCustomer(),
|
||||
'description' => $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')),
|
||||
|
||||
]);
|
||||
|
||||
$data['pi_client_secret'] = $intent->client_secret;
|
||||
|
||||
if (count($data['tokens']) > 0) {
|
||||
$setup_intent = $this->stripe->stripe->setupIntents->create([
|
||||
'payment_method_types' => ['sepa_debit'],
|
||||
'customer' => $this->stripe->findOrCreateCustomer()->id,
|
||||
]);
|
||||
|
||||
$data['si_client_secret'] = $setup_intent->client_secret;
|
||||
}
|
||||
|
||||
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['stripe_amount' => $data['stripe_amount']]);
|
||||
$this->stripe->payment_hash->save();
|
||||
|
||||
@ -65,28 +76,24 @@ class SEPA
|
||||
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
{
|
||||
|
||||
$gateway_response = json_decode($request->gateway_response);
|
||||
|
||||
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $request->all());
|
||||
$this->stripe->payment_hash->save();
|
||||
|
||||
if (property_exists($gateway_response, 'status') && $gateway_response->status == 'processing') {
|
||||
|
||||
$this->stripe->init();
|
||||
$this->storePaymentMethod($gateway_response);
|
||||
if (property_exists($gateway_response, 'status') && ($gateway_response->status == 'processing' || $gateway_response->status === 'succeeded')) {
|
||||
if ($request->store_card) {
|
||||
$this->storePaymentMethod($gateway_response);
|
||||
}
|
||||
|
||||
return $this->processSuccessfulPayment($gateway_response->id);
|
||||
}
|
||||
|
||||
return $this->processUnsuccessfulPayment();
|
||||
|
||||
}
|
||||
|
||||
public function processSuccessfulPayment(string $payment_intent)
|
||||
{
|
||||
$this->stripe->init();
|
||||
|
||||
$data = [
|
||||
'payment_method' => $payment_intent,
|
||||
'payment_type' => PaymentType::SEPA,
|
||||
@ -95,7 +102,7 @@ class SEPA
|
||||
'gateway_type_id' => GatewayType::SEPA,
|
||||
];
|
||||
|
||||
$this->stripe->createPayment($data, Payment::STATUS_PENDING);
|
||||
$payment = $this->stripe->createPayment($data, Payment::STATUS_PENDING);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $this->stripe->payment_hash->data, 'data' => $data],
|
||||
@ -106,7 +113,7 @@ class SEPA
|
||||
$this->stripe->client->company,
|
||||
);
|
||||
|
||||
return redirect()->route('client.payments.index');
|
||||
return redirect()->route('client.payments.show', $payment->hashed_id);
|
||||
}
|
||||
|
||||
public function processUnsuccessfulPayment()
|
||||
@ -141,7 +148,6 @@ class SEPA
|
||||
private function storePaymentMethod($intent)
|
||||
{
|
||||
try {
|
||||
|
||||
$method = $this->stripe->getStripePaymentMethod($intent->payment_method);
|
||||
|
||||
$payment_meta = new \stdClass;
|
||||
|
2
public/js/clients/payments/stripe-sepa.js
vendored
2
public/js/clients/payments/stripe-sepa.js
vendored
File diff suppressed because one or more lines are too long
@ -20,7 +20,7 @@
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=81c2623fc1e5769b51c7",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=665ddf663500767f1a17",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=a30464874dee84678344",
|
||||
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=e7dc964c85085314b12c",
|
||||
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=3f2fa0857dc804a85dcb",
|
||||
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=231571942310348aa616",
|
||||
"/js/clients/payments/wepay-credit-card.js": "/js/clients/payments/wepay-credit-card.js?id=f51400e03c5fdb6cdabe",
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=1b8f9325aa6e8595e7fa",
|
||||
|
214
resources/js/clients/payments/stripe-sepa.js
vendored
214
resources/js/clients/payments/stripe-sepa.js
vendored
@ -18,93 +18,174 @@ class ProcessSEPA {
|
||||
setupStripe = () => {
|
||||
this.stripe = Stripe(this.key);
|
||||
|
||||
if(this.stripeConnect)
|
||||
this.stripe.stripeAccount = stripeConnect;
|
||||
if (this.stripeConnect) this.stripe.stripeAccount = stripeConnect;
|
||||
const elements = this.stripe.elements();
|
||||
var style = {
|
||||
base: {
|
||||
color: "#32325d",
|
||||
color: '#32325d',
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif',
|
||||
fontSmoothing: "antialiased",
|
||||
fontSize: "16px",
|
||||
"::placeholder": {
|
||||
color: "#aab7c4"
|
||||
fontSmoothing: 'antialiased',
|
||||
fontSize: '16px',
|
||||
'::placeholder': {
|
||||
color: '#aab7c4',
|
||||
},
|
||||
':-webkit-autofill': {
|
||||
color: '#32325d',
|
||||
},
|
||||
":-webkit-autofill": {
|
||||
color: "#32325d"
|
||||
}
|
||||
},
|
||||
invalid: {
|
||||
color: "#fa755a",
|
||||
iconColor: "#fa755a",
|
||||
":-webkit-autofill": {
|
||||
color: "#fa755a"
|
||||
}
|
||||
}
|
||||
color: '#fa755a',
|
||||
iconColor: '#fa755a',
|
||||
':-webkit-autofill': {
|
||||
color: '#fa755a',
|
||||
},
|
||||
},
|
||||
};
|
||||
var options = {
|
||||
style: style,
|
||||
supportedCountries: ["SEPA"],
|
||||
supportedCountries: ['SEPA'],
|
||||
// If you know the country of the customer, you can optionally pass it to
|
||||
// the Element as placeholderCountry. The example IBAN that is being used
|
||||
// as placeholder reflects the IBAN format of that country.
|
||||
placeholderCountry: document.querySelector('meta[name="country"]').content
|
||||
placeholderCountry: document.querySelector('meta[name="country"]')
|
||||
.content,
|
||||
};
|
||||
this.iban = elements.create("iban", options);
|
||||
this.iban.mount("#sepa-iban");
|
||||
this.iban = elements.create('iban', options);
|
||||
this.iban.mount('#sepa-iban');
|
||||
return this;
|
||||
};
|
||||
|
||||
handle = () => {
|
||||
document.getElementById('pay-now').addEventListener('click', (e) => {
|
||||
|
||||
let errors = document.getElementById('errors');
|
||||
|
||||
if (document.getElementById('sepa-name').value === "") {
|
||||
document.getElementById('sepa-name').focus();
|
||||
errors.textContent = "Name required.";
|
||||
errors.hidden = false;
|
||||
return;
|
||||
}
|
||||
Array.from(
|
||||
document.getElementsByClassName('toggle-payment-with-token')
|
||||
).forEach((element) =>
|
||||
element.addEventListener('click', (element) => {
|
||||
document
|
||||
.getElementById('stripe--payment-container')
|
||||
.classList.add('hidden');
|
||||
document.getElementById('save-card--container').style.display =
|
||||
'none';
|
||||
document.querySelector('input[name=token]').value =
|
||||
element.target.dataset.token;
|
||||
})
|
||||
);
|
||||
|
||||
if (document.getElementById('sepa-email-address').value === "") {
|
||||
document.getElementById('sepa-email-address').focus();
|
||||
errors.textContent = "Email required.";
|
||||
errors.hidden = false;
|
||||
return ;
|
||||
}
|
||||
document
|
||||
.getElementById('toggle-payment-with-new-bank-account')
|
||||
.addEventListener('click', (element) => {
|
||||
document
|
||||
.getElementById('stripe--payment-container')
|
||||
.classList.remove('hidden');
|
||||
document.getElementById('save-card--container').style.display =
|
||||
'grid';
|
||||
document.querySelector('input[name=token]').value = '';
|
||||
});
|
||||
|
||||
document.getElementById('pay-now').addEventListener('click', (e) => {
|
||||
if (
|
||||
document.querySelector('input[name=token]').value.length !== 0
|
||||
) {
|
||||
document.querySelector('#errors').hidden = true;
|
||||
|
||||
if (!document.getElementById('sepa-mandate-acceptance').checked) {
|
||||
errors.textContent = "Accept Terms";
|
||||
errors.hidden = false;
|
||||
console.log("Terms");
|
||||
return ;
|
||||
}
|
||||
document.getElementById('pay-now').disabled = true;
|
||||
document
|
||||
.querySelector('#pay-now > svg')
|
||||
.classList.remove('hidden');
|
||||
document
|
||||
.querySelector('#pay-now > span')
|
||||
.classList.add('hidden');
|
||||
|
||||
this.stripe
|
||||
.confirmSepaDebitSetup(
|
||||
document.querySelector('meta[name=si-client-secret')
|
||||
.content,
|
||||
{
|
||||
payment_method: document.querySelector(
|
||||
'input[name=token]'
|
||||
).value,
|
||||
}
|
||||
)
|
||||
.then((result) => {
|
||||
if (result.error) {
|
||||
console.error(error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
document.querySelector(
|
||||
'input[name="gateway_response"]'
|
||||
).value = JSON.stringify(result.setupIntent);
|
||||
|
||||
return document
|
||||
.querySelector('#server-response')
|
||||
.submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
errors.textContent = error;
|
||||
errors.hidden = false;
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.getElementById('sepa-name').value === '') {
|
||||
document.getElementById('sepa-name').focus();
|
||||
errors.textContent = document.querySelector(
|
||||
'meta[name=translation-name-required]'
|
||||
).content;
|
||||
errors.hidden = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.getElementById('sepa-email-address').value === '') {
|
||||
document.getElementById('sepa-email-address').focus();
|
||||
errors.textContent = document.querySelector(
|
||||
'meta[name=translation-email-required]'
|
||||
).content;
|
||||
errors.hidden = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!document.getElementById('sepa-mandate-acceptance').checked) {
|
||||
errors.textContent = document.querySelector(
|
||||
'meta[name=translation-terms-required]'
|
||||
).content;
|
||||
errors.hidden = false;
|
||||
console.log('Terms');
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('pay-now').disabled = true;
|
||||
document.querySelector('#pay-now > svg').classList.remove('hidden');
|
||||
document.querySelector('#pay-now > span').classList.add('hidden');
|
||||
|
||||
this.stripe.confirmSepaDebitPayment(
|
||||
document.querySelector('meta[name=pi-client-secret').content,
|
||||
{
|
||||
payment_method: {
|
||||
sepa_debit: this.iban,
|
||||
billing_details: {
|
||||
name: document.getElementById("sepa-name").value,
|
||||
email: document.getElementById("sepa-email-address").value,
|
||||
this.stripe
|
||||
.confirmSepaDebitPayment(
|
||||
document.querySelector('meta[name=pi-client-secret')
|
||||
.content,
|
||||
{
|
||||
payment_method: {
|
||||
sepa_debit: this.iban,
|
||||
billing_details: {
|
||||
name: document.getElementById('sepa-name')
|
||||
.value,
|
||||
email: document.getElementById(
|
||||
'sepa-email-address'
|
||||
).value,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
).then((result) => {
|
||||
if (result.error) {
|
||||
return this.handleFailure(result.error.message);
|
||||
}
|
||||
}
|
||||
)
|
||||
.then((result) => {
|
||||
if (result.error) {
|
||||
return this.handleFailure(result.error.message);
|
||||
}
|
||||
|
||||
return this.handleSuccess(result);
|
||||
});
|
||||
return this.handleSuccess(result);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@ -113,6 +194,15 @@ class ProcessSEPA {
|
||||
'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();
|
||||
}
|
||||
|
||||
@ -123,15 +213,15 @@ class ProcessSEPA {
|
||||
errors.textContent = message;
|
||||
errors.hidden = false;
|
||||
|
||||
document.getElementById('pay-now').disabled = false;
|
||||
document.querySelector('#pay-now > svg').classList.add('hidden');
|
||||
document.querySelector('#pay-now > span').classList.remove('hidden');
|
||||
document.getElementById('pay-now').disabled = false;
|
||||
document.querySelector('#pay-now > svg').classList.add('hidden');
|
||||
document.querySelector('#pay-now > span').classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
const publishableKey = document.querySelector(
|
||||
'meta[name="stripe-publishable-key"]'
|
||||
)?.content ?? '';
|
||||
const publishableKey =
|
||||
document.querySelector('meta[name="stripe-publishable-key"]')?.content ??
|
||||
'';
|
||||
|
||||
const stripeConnect =
|
||||
document.querySelector('meta[name="stripe-account-id"]')?.content ?? '';
|
||||
|
@ -4327,6 +4327,7 @@ $LANG = array(
|
||||
'giropay' => 'GiroPay',
|
||||
'giropay_law' => 'By entering your Customer information (such as name, sort code and account number) you (the Customer) agree that this information is given voluntarily.',
|
||||
'eps' => 'EPS',
|
||||
'you_need_to_accept_the_terms_before_proceeding' => 'You need to accept the terms before proceeding.',
|
||||
);
|
||||
|
||||
return $LANG;
|
||||
|
@ -7,9 +7,24 @@
|
||||
<meta name="country" content="{{ $country }}">
|
||||
<meta name="customer" content="{{ $customer }}">
|
||||
<meta name="pi-client-secret" content="{{ $pi_client_secret }}">
|
||||
<meta name="si-client-secret" content="{{ $si_client_secret ?? '' }}">
|
||||
|
||||
<meta name="translation-name-required" content="{{ ctrans('texts.missing_account_holder_name') }}">
|
||||
<meta name="translation-email-required" content="{{ ctrans('texts.provide_email') }}">
|
||||
<meta name="translation-terms-required" content="{{ ctrans('texts.you_need_to_accept_the_terms_before_proceeding') }}">
|
||||
@endsection
|
||||
|
||||
@section('gateway_content')
|
||||
<form action="{{ route('client.payments.response') }}" method="post" id="server-response">
|
||||
@csrf
|
||||
<input type="hidden" name="gateway_response">
|
||||
<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="payment_hash" value="{{ $payment_hash }}">
|
||||
<input type="hidden" name="store_card">
|
||||
<input type="hidden" name="token">
|
||||
</form>
|
||||
|
||||
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||
|
||||
@include('portal.ninja2020.gateways.includes.payment_details')
|
||||
@ -18,7 +33,48 @@
|
||||
{{ ctrans('texts.sepa') }} ({{ ctrans('texts.bank_transfer') }})
|
||||
@endcomponent
|
||||
|
||||
@include('portal.ninja2020.gateways.stripe.sepa.sepa_debit')
|
||||
@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">**** {{ optional($token->meta)->last4 }}</span>
|
||||
</label>
|
||||
@endforeach
|
||||
@endisset
|
||||
|
||||
<label>
|
||||
<input type="radio" id="toggle-payment-with-new-bank-account" class="form-radio cursor-pointer" name="payment-type"
|
||||
checked />
|
||||
<span class="ml-1 cursor-pointer">{{ __('texts.new_bank_account') }}</span>
|
||||
</label>
|
||||
@endcomponent
|
||||
|
||||
@component('portal.ninja2020.components.general.card-element-single')
|
||||
<div id="stripe--payment-container">
|
||||
<label for="sepa-name">
|
||||
<input class="input w-full" id="sepa-name" type="text"
|
||||
placeholder="{{ ctrans('texts.bank_account_holder') }}">
|
||||
</label>
|
||||
<label for="sepa-email" class="mt-4">
|
||||
<input class="input w-full" id="sepa-email-address" type="email"
|
||||
placeholder="{{ ctrans('texts.email') }}">
|
||||
</label>
|
||||
<label>
|
||||
<div class="border p-3 rounded mt-2">
|
||||
<div id="sepa-iban"></div>
|
||||
</div>
|
||||
</label>
|
||||
<div id="mandate-acceptance" class="mt-4">
|
||||
<input type="checkbox" id="sepa-mandate-acceptance" class="input mr-4">
|
||||
<label for="sepa-mandate-acceptance" class="cursor-pointer">
|
||||
{{ ctrans('texts.sepa_mandat', ['company' => $contact->company->present()->name()]) }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
@endcomponent
|
||||
|
||||
@include('portal.ninja2020.gateways.includes.save_card')
|
||||
@include('portal.ninja2020.gateways.includes.pay_now')
|
||||
@endsection
|
||||
|
@ -1,29 +0,0 @@
|
||||
<div id="stripe--payment-container">
|
||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.name')])
|
||||
|
||||
<form action="{{ route('client.payments.response') }}" method="post" id="server-response">
|
||||
@csrf
|
||||
<input type="hidden" name="gateway_response">
|
||||
<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="payment_hash" value="{{ $payment_hash }}">
|
||||
<input type="hidden" name="store_card">
|
||||
|
||||
<label for="sepa-name">
|
||||
<input class="input w-full" id="sepa-name" type="text" placeholder="{{ ctrans('texts.bank_account_holder') }}">
|
||||
</label>
|
||||
<label for="sepa-email" >
|
||||
<input class="input w-full" id="sepa-email-address" type="email" placeholder="{{ ctrans('texts.email') }}">
|
||||
</label>
|
||||
<label>
|
||||
<div class="border p-4 rounded">
|
||||
<div id="sepa-iban"></div>
|
||||
</div>
|
||||
</label>
|
||||
<div id="mandate-acceptance">
|
||||
<input type="checkbox" id="sepa-mandate-acceptance" class="input mr-4">
|
||||
<label for="sepa-mandate-acceptance">{{ctrans('texts.sepa_mandat', ['company' => auth('contact')->user()->company->present()->name()])}}</label>
|
||||
</div>
|
||||
</form>
|
||||
@endcomponent
|
||||
</div>
|
127
tests/Browser/ClientPortal/Gateways/Stripe/SEPATest.php
Normal file
127
tests/Browser/ClientPortal/Gateways/Stripe/SEPATest.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://opensource.org/licenses/AAL
|
||||
*/
|
||||
|
||||
namespace Tests\Browser\ClientPortal\Gateways\Stripe;
|
||||
|
||||
use App\DataMapper\FeesAndLimits;
|
||||
use App\Models\Client;
|
||||
use App\Models\CompanyGateway;
|
||||
use App\Models\GatewayType;
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Pages\ClientPortal\Login;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class SEPATest extends DuskTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
foreach (static::$browsers as $browser) {
|
||||
$browser->driver->manage()->deleteAllCookies();
|
||||
}
|
||||
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser
|
||||
->visit(new Login())
|
||||
->auth();
|
||||
});
|
||||
|
||||
$this->disableCompanyGateways();
|
||||
|
||||
// Enable Stripe.
|
||||
CompanyGateway::where('gateway_key', 'd14dd26a37cecc30fdd65700bfb55b23')->restore();
|
||||
|
||||
// Enable SEPA.
|
||||
$cg = CompanyGateway::where('gateway_key', 'd14dd26a37cecc30fdd65700bfb55b23')->firstOrFail();
|
||||
$fees_and_limits = $cg->fees_and_limits;
|
||||
$fees_and_limits->{GatewayType::SEPA} = new FeesAndLimits();
|
||||
$cg->fees_and_limits = $fees_and_limits;
|
||||
$cg->save();
|
||||
|
||||
// SEPA required DE to be billing country.
|
||||
$client = Client::first();
|
||||
$client->country_id = 276;
|
||||
|
||||
$settings = $client->settings;
|
||||
$settings->currency_id = "3";
|
||||
|
||||
$client->settings = $settings;
|
||||
$client->save();
|
||||
}
|
||||
|
||||
public function testPayingWithNewSEPABankAccount(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser
|
||||
->visitRoute('client.invoices.index')
|
||||
->click('@pay-now')
|
||||
->click('@pay-now-dropdown')
|
||||
->clickLink('SEPA Direct Debit')
|
||||
->type('#sepa-name', 'John Doe')
|
||||
->type('#sepa-email-address', 'test@invoiceninja.com')
|
||||
->withinFrame('iframe', function (Browser $browser) {
|
||||
$browser->type('iban', 'DE89370400440532013000');
|
||||
})
|
||||
->check('#sepa-mandate-acceptance', true)
|
||||
->click('#pay-now')
|
||||
->waitForText('Details of the payment', 60);
|
||||
});
|
||||
}
|
||||
|
||||
public function testPayingWithNewSEPABankAccountAndSaveForFuture(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser
|
||||
->visitRoute('client.invoices.index')
|
||||
->click('@pay-now')
|
||||
->click('@pay-now-dropdown')
|
||||
->clickLink('SEPA Direct Debit')
|
||||
->type('#sepa-name', 'John Doe')
|
||||
->type('#sepa-email-address', 'test@invoiceninja.com')
|
||||
->withinFrame('iframe', function (Browser $browser) {
|
||||
$browser->type('iban', 'DE89370400440532013000');
|
||||
})
|
||||
->check('#sepa-mandate-acceptance', true)
|
||||
->radio('#proxy_is_default', true)
|
||||
->click('#pay-now')
|
||||
->waitForText('Details of the payment', 60);
|
||||
});
|
||||
}
|
||||
|
||||
public function testPayWithSavedBankAccount()
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser
|
||||
->visitRoute('client.invoices.index')
|
||||
->click('@pay-now')
|
||||
->click('@pay-now-dropdown')
|
||||
->clickLink('SEPA Direct Debit')
|
||||
->click('.toggle-payment-with-token')
|
||||
->click('#pay-now')
|
||||
->waitForText('Details of the payment', 60);
|
||||
});
|
||||
}
|
||||
|
||||
public function testRemoveBankAccount()
|
||||
{
|
||||
$this->browse(function (Browser $browser) {
|
||||
$browser
|
||||
->visitRoute('client.payment_methods.index')
|
||||
->clickLink('View')
|
||||
->press('Remove Payment Method')
|
||||
->waitForText('Confirmation')
|
||||
->click('@confirm-payment-removal')
|
||||
->assertSee('Payment method has been successfully removed.');
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user