mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 21:22:58 +01:00
Merge pull request #4828 from beganovich/v5-0302-cypress-checkout
(v5) Fixes & tests for gateways
This commit is contained in:
commit
aec701040a
@ -82,15 +82,6 @@ class CreditCard
|
||||
{
|
||||
$this->checkout->init();
|
||||
|
||||
$cgt = ClientGatewayToken::query()
|
||||
->where('id', $this->decodePrimaryKey($request->input('token')))
|
||||
->where('company_id', auth('contact')->user()->client->company->id)
|
||||
->first();
|
||||
|
||||
if (!$cgt) {
|
||||
throw new PaymentFailed(ctrans('texts.payment_token_not_found'), 401);
|
||||
}
|
||||
|
||||
$state = [
|
||||
'server_response' => json_decode($request->gateway_response),
|
||||
'value' => $request->value,
|
||||
@ -103,12 +94,11 @@ class CreditCard
|
||||
|
||||
$state = array_merge($state, $request->all());
|
||||
$state['store_card'] = boolval($state['store_card']);
|
||||
$state['token'] = $cgt;
|
||||
|
||||
$this->checkout->payment_hash->data = array_merge((array)$this->checkout->payment_hash->data, $state);
|
||||
$this->checkout->payment_hash->save();
|
||||
|
||||
if ($request->has('token')) {
|
||||
if ($request->has('token') && !is_null($request->token) && !empty($request->token)) {
|
||||
return $this->attemptPaymentUsingToken($request);
|
||||
}
|
||||
|
||||
@ -117,7 +107,16 @@ class CreditCard
|
||||
|
||||
private function attemptPaymentUsingToken(PaymentResponseRequest $request)
|
||||
{
|
||||
$method = new IdSource($this->checkout->payment_hash->data->token->token);
|
||||
$cgt = ClientGatewayToken::query()
|
||||
->where('id', $this->decodePrimaryKey($request->input('token')))
|
||||
->where('company_id', auth('contact')->user()->client->company->id)
|
||||
->first();
|
||||
|
||||
if (!$cgt) {
|
||||
throw new PaymentFailed(ctrans('texts.payment_token_not_found'), 401);
|
||||
}
|
||||
|
||||
$method = new IdSource($cgt->token);
|
||||
|
||||
return $this->completePayment($method, $request);
|
||||
}
|
||||
@ -161,7 +160,7 @@ class CreditCard
|
||||
}
|
||||
|
||||
if ($response->status == 'Pending') {
|
||||
$this->checkout->confirmGatewayFee($request);
|
||||
$this->checkout->confirmGatewayFee();
|
||||
|
||||
return $this->processPendingPayment($response);
|
||||
}
|
||||
@ -171,7 +170,6 @@ class CreditCard
|
||||
|
||||
PaymentFailureMailer::dispatch($this->checkout->client, $response->response_summary, $this->checkout->client->company, $this->checkout->payment_hash->data->value);
|
||||
|
||||
|
||||
return $this->processUnsuccessfulPayment($response);
|
||||
}
|
||||
} catch (CheckoutHttpException $e) {
|
||||
|
@ -66,6 +66,7 @@ trait Utilities
|
||||
'payment_type' => PaymentType::parseCardType(strtolower($_payment->source['scheme'])),
|
||||
'amount' => $this->getParent()->payment_hash->data->raw_value,
|
||||
'transaction_reference' => $_payment->id,
|
||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||
];
|
||||
|
||||
$payment = $this->getParent()->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
|
||||
|
@ -86,6 +86,10 @@ class CreditCard
|
||||
$state = array_merge($state, $request->all());
|
||||
$state['store_card'] = boolval($state['store_card']);
|
||||
|
||||
if ($request->has('token') && !is_null($request->token)) {
|
||||
$state['store_card'] = false;
|
||||
}
|
||||
|
||||
$state['payment_intent'] = PaymentIntent::retrieve($state['server_response']->id);
|
||||
$state['customer'] = $state['payment_intent']->customer;
|
||||
|
||||
@ -116,7 +120,6 @@ class CreditCard
|
||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||
];
|
||||
|
||||
|
||||
$this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['amount' => $data['amount']]);
|
||||
$this->stripe->payment_hash->save();
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
{
|
||||
"video": false,
|
||||
"baseUrl": "http://localhost:8000/",
|
||||
"chromeWebSecurity": false
|
||||
"baseUrl": "https://localhost:8000/",
|
||||
"chromeWebSecurity": false,
|
||||
"env": {
|
||||
"runningEnvironment": "native"
|
||||
}
|
||||
}
|
||||
|
87
cypress/integration/client_portal/checkout_credit_card.spec.js
vendored
Normal file
87
cypress/integration/client_portal/checkout_credit_card.spec.js
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
context('Checkout.com: Credit card testing', () => {
|
||||
before(() => {
|
||||
cy.artisan('migrate:fresh --seed');
|
||||
cy.artisan('ninja:create-single-account checkout');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport('macbook-13');
|
||||
cy.clientLogin();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cy.visit('/client/logout');
|
||||
});
|
||||
|
||||
it('should not be able to add payment method', function () {
|
||||
cy.visit('/client/payment_methods');
|
||||
|
||||
cy.get('[data-cy=add-payment-method]').click();
|
||||
cy.get('[data-cy=add-credit-card-link]').click();
|
||||
|
||||
cy.get('[data-ref=gateway-container]')
|
||||
.contains('Checkout.com can be can saved as payment method for future use, once you complete your first transaction. Don\'t forget to check "Store credit card details" during payment process.');
|
||||
});
|
||||
|
||||
it('should pay with new card', function () {
|
||||
cy.visit('/client/invoices');
|
||||
|
||||
cy.get('[data-cy=pay-now]').first().click();
|
||||
cy.get('[data-cy=pay-now-dropdown]').click();
|
||||
cy.get('[data-cy=pay-with-0]').click();
|
||||
|
||||
cy.getWithinIframe('#checkout-frames-card-number').type('4658584090000001');
|
||||
cy.getWithinIframe('#checkout-frames-expiry-date').type('12/22');
|
||||
cy.getWithinIframe('#checkout-frames-cvv').type('257');
|
||||
|
||||
cy.get('#pay-button').click();
|
||||
|
||||
cy.url().should('contain', '/client/payments/VolejRejNm');
|
||||
});
|
||||
|
||||
it('should pay with new card & save credit card for future use', function () {
|
||||
cy.visit('/client/invoices');
|
||||
|
||||
cy.get('[data-cy=pay-now]').first().click();
|
||||
cy.get('[data-cy=pay-now-dropdown]').click();
|
||||
cy.get('[data-cy=pay-with-0]').click();
|
||||
|
||||
cy.get('[name=token-billing-checkbox]').first().check();
|
||||
|
||||
cy.getWithinIframe('#checkout-frames-card-number').type('4543474002249996');
|
||||
cy.getWithinIframe('#checkout-frames-expiry-date').type('12/22');
|
||||
cy.getWithinIframe('#checkout-frames-cvv').type('956');
|
||||
|
||||
cy.get('#pay-button').click();
|
||||
|
||||
cy.url().should('contain', '/client/payments/Wpmbk5ezJn');
|
||||
});
|
||||
|
||||
it('should pay with saved card (token)', function () {
|
||||
cy.visit('/client/invoices');
|
||||
|
||||
cy.get('[data-cy=pay-now]').first().click();
|
||||
cy.get('[data-cy=pay-now-dropdown]').click();
|
||||
cy.get('[data-cy=pay-with-0]').click();
|
||||
|
||||
cy.get('[name=payment-type]').first().check();
|
||||
|
||||
cy.get('#pay-now-with-token').click();
|
||||
|
||||
cy.url().should('contain', '/client/payments/Opnel5aKBz');
|
||||
});
|
||||
|
||||
it('should be able to remove payment method', function () {
|
||||
cy.visit('/client/payment_methods');
|
||||
|
||||
cy.get('[data-cy=view-payment-method]').click();
|
||||
|
||||
cy.get('#open-delete-popup').click();
|
||||
|
||||
cy.get('[data-cy=confirm-payment-removal]').click();
|
||||
|
||||
cy.url().should('contain', '/client/payment_methods');
|
||||
|
||||
cy.get('body').contains('Payment method has been successfully removed.');
|
||||
});
|
||||
});
|
@ -1,47 +1,98 @@
|
||||
describe('Stripe Credit Card Payments', () => {
|
||||
describe('Stripe: Credit card testing', () => {
|
||||
before(() => {
|
||||
cy.artisan('migrate:fresh --seed');
|
||||
cy.artisan('ninja:create-single-account stripe');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.viewport('macbook-13');
|
||||
cy.clientLogin();
|
||||
});
|
||||
|
||||
it('should be able to add credit card using Stripe', () => {
|
||||
afterEach(() => {
|
||||
cy.visit('/client/logout');
|
||||
});
|
||||
|
||||
it('should pay with new card', function () {
|
||||
cy.visit('/client/invoices');
|
||||
|
||||
cy.get('[data-cy=pay-now]').first().click();
|
||||
cy.get('[data-cy=pay-now-dropdown]').click();
|
||||
cy.get('[data-cy=pay-with-0]').click();
|
||||
|
||||
cy.get('#cardholder-name').type('Invoice Ninja Rocks');
|
||||
cy.getWithinIframe('[name=cardnumber]').type('4242424242424242');
|
||||
cy.getWithinIframe('[name=exp-date]').type('04/24');
|
||||
cy.getWithinIframe('[name=cvc]').type('242');
|
||||
cy.getWithinIframe('[name=postal]').type('42424');
|
||||
|
||||
cy.get('#pay-now').click();
|
||||
|
||||
cy.url().should('contain', '/client/payments/VolejRejNm');
|
||||
});
|
||||
|
||||
it('should pay with new card & save credit card for future use', function () {
|
||||
cy.visit('/client/invoices');
|
||||
|
||||
cy.get('[data-cy=pay-now]').first().click();
|
||||
cy.get('[data-cy=pay-now-dropdown]').click();
|
||||
cy.get('[data-cy=pay-with-0]').click();
|
||||
|
||||
cy.get('#cardholder-name').type('Invoice Ninja Rocks');
|
||||
cy.getWithinIframe('[name=cardnumber]').type('4242424242424242');
|
||||
cy.getWithinIframe('[name=exp-date]').type('04/24');
|
||||
cy.getWithinIframe('[name=cvc]').type('242');
|
||||
cy.getWithinIframe('[name=postal]').type('42424');
|
||||
|
||||
cy.get('[name=token-billing-checkbox]').first().check();
|
||||
|
||||
cy.get('#pay-now').click();
|
||||
|
||||
cy.url().should('contain', '/client/payments/Wpmbk5ezJn');
|
||||
});
|
||||
|
||||
it('should pay with saved card (token)', function () {
|
||||
cy.visit('/client/invoices');
|
||||
|
||||
cy.get('[data-cy=pay-now]').first().click();
|
||||
cy.get('[data-cy=pay-now-dropdown]').click();
|
||||
cy.get('[data-cy=pay-with-0]').click();
|
||||
|
||||
cy.get('[name=payment-type]').first().check();
|
||||
|
||||
cy.get('#pay-now').click();
|
||||
|
||||
cy.url().should('contain', '/client/payments/Opnel5aKBz');
|
||||
});
|
||||
|
||||
it('should be able to remove payment method', function () {
|
||||
cy.visit('/client/payment_methods');
|
||||
|
||||
cy.get('[data-cy=view-payment-method]').click();
|
||||
|
||||
cy.get('#open-delete-popup').click();
|
||||
|
||||
cy.get('[data-cy=confirm-payment-removal]').click();
|
||||
|
||||
cy.url().should('contain', '/client/payment_methods');
|
||||
|
||||
cy.get('body').contains('Payment method has been successfully removed.');
|
||||
});
|
||||
|
||||
it('should be able to add credit card (standalone)', function () {
|
||||
cy.visit('/client/payment_methods');
|
||||
|
||||
cy.get('[data-cy=add-payment-method]').click();
|
||||
cy.get('[data-cy=add-credit-card-link]').click();
|
||||
|
||||
cy.get('#cardholder-name').type('Invoice Ninja');
|
||||
cy.get('#cardholder-name').type('Invoice Ninja Rocks');
|
||||
cy.getWithinIframe('[name=cardnumber]').type('4242424242424242');
|
||||
cy.getWithinIframe('[name=exp-date]').type('04/24');
|
||||
cy.getWithinIframe('[name=cvc]').type('242');
|
||||
cy.getWithinIframe('[name=postal]').type('42424');
|
||||
|
||||
cy.getWithinIframe('[name="cardnumber"]').type('4242424242424242');
|
||||
cy.getWithinIframe('[name="exp-date"]').type('1230');
|
||||
cy.getWithinIframe('[name="cvc"]').type('100');
|
||||
cy.getWithinIframe('[name="postal"]').type('12345');
|
||||
cy.get('#authorize-card').click();
|
||||
|
||||
cy.get('#card-button').click();
|
||||
|
||||
cy.get('#errors').should('be.empty');
|
||||
|
||||
cy.location('pathname').should('eq', '/client/payment_methods');
|
||||
});
|
||||
|
||||
it('should be able to complete payment with added credit card', () => {
|
||||
cy.visit('/client/invoices');
|
||||
|
||||
cy.get('#unpaid-checkbox').click();
|
||||
|
||||
cy.get('[data-cy=pay-now')
|
||||
.first()
|
||||
.click();
|
||||
|
||||
cy.location('pathname').should('eq', '/client/invoices/payment');
|
||||
|
||||
cy.get('[data-cy=payment-methods-dropdown').click();
|
||||
|
||||
cy.get('[data-cy=payment-method')
|
||||
.first()
|
||||
.click();
|
||||
|
||||
cy.get('#pay-now-with-token').click();
|
||||
|
||||
cy.url().should('contain', '/client/payments');
|
||||
cy.url().should('contain', '/client/payment_methods');
|
||||
});
|
||||
});
|
||||
|
35
cypress/support/account.js
vendored
Normal file
35
cypress/support/account.js
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const baseUrl = Cypress.config().baseUrl.endsWith('/')
|
||||
? Cypress.config().baseUrl.slice(0, -1)
|
||||
: Cypress.config().baseUrl;
|
||||
|
||||
Cypress.Commands.add('createAdminAccount', () => {
|
||||
let body = {
|
||||
first_name: "Cypress",
|
||||
last_name: "Testing",
|
||||
email: "cypress_testing@example.com",
|
||||
password: "password",
|
||||
terms_of_service: true,
|
||||
privacy_policy: true,
|
||||
report_errors: true,
|
||||
};
|
||||
|
||||
let headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
};
|
||||
|
||||
return axios.post(`${baseUrl}/api/v1/signup?first_load=true`, body, headers)
|
||||
.then(response => {
|
||||
console.log('Data from the request', response.data.data[0]);
|
||||
return response.data.data[0];
|
||||
})
|
||||
.catch(e => {
|
||||
throw "Unable to create an account for admin.";
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('createClientAccount', () => {
|
||||
// ..
|
||||
});
|
6
cypress/support/artisan.js
vendored
Normal file
6
cypress/support/artisan.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
Cypress.Commands.add('artisan', (cmd) => {
|
||||
let environment = Cypress.env('runningEnvironment');
|
||||
let prefix = environment === 'docker' ? 'docker-compose run --rm artisan' : 'php artisan';
|
||||
|
||||
return cy.exec(`${prefix} ${cmd}`);
|
||||
});
|
4
cypress/support/index.js
vendored
4
cypress/support/index.js
vendored
@ -14,7 +14,9 @@
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
import './commands';
|
||||
import './artisan';
|
||||
import './account';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@
|
||||
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=98e406fa8e4db0e93427",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=c4012ad90f17d60432ad",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=6dbe9316b98deea55421",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=9418a9c5c137994c4bd8",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=c37c3892d35c50d82521",
|
||||
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=9b9fd56d655ad238f149",
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=1b8f9325aa6e8595e7fa",
|
||||
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=85bcae0a646882e56b12",
|
||||
|
@ -95,7 +95,7 @@ class StripeCreditCard {
|
||||
|
||||
if (tokenBillingCheckbox) {
|
||||
document.querySelector('input[name="store_card"]').value =
|
||||
tokenBillingCheckbox.checked;
|
||||
tokenBillingCheckbox.value;
|
||||
}
|
||||
|
||||
document.getElementById('server-response').submit();
|
||||
|
@ -1,4 +1,10 @@
|
||||
@if($gateway->company_gateway->token_billing !== 'always')
|
||||
@php
|
||||
$token_billing = $gateway instanceof \App\Models\CompanyGateway
|
||||
? $gateway->token_billing !== 'always'
|
||||
: $gateway->company_gateway->token_billing !== 'always';
|
||||
@endphp
|
||||
|
||||
@if($token_billing)
|
||||
<div class="sm:grid px-4 py-5 sm:grid-cols-3 sm:gap-4 sm:px-6" id="save-card--container">
|
||||
<dt class="text-sm leading-5 font-medium text-gray-500">
|
||||
{{ ctrans('texts.save_payment_method_details') }}
|
||||
|
@ -24,7 +24,7 @@
|
||||
<div x-data="{ open: false }" @keydown.window.escape="open = false" @click.away="open = false" class="relative inline-block text-left" data-cy="payment-methods-dropdown">
|
||||
<div>
|
||||
<div class="rounded-md shadow-sm">
|
||||
<button @click="open = !open" type="button" class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800">
|
||||
<button data-cy="pay-now-dropdown" @click="open = !open" type="button" class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium leading-5 text-gray-700 transition duration-150 ease-in-out bg-white border border-gray-300 rounded-md hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800">
|
||||
{{ ctrans('texts.pay_now') }}
|
||||
<svg class="w-5 h-5 ml-2 -mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
@ -35,13 +35,13 @@
|
||||
<div x-show="open" class="absolute right-0 w-56 mt-2 origin-top-right rounded-md shadow-lg">
|
||||
<div class="bg-white rounded-md shadow-xs">
|
||||
<div class="py-1">
|
||||
@foreach($payment_methods as $payment_method)
|
||||
@foreach($payment_methods as $index => $payment_method)
|
||||
@if($payment_method['label'] == 'Custom')
|
||||
<a href="#" @click="{ open = false }" data-company-gateway-id="{{ $payment_method['company_gateway_id'] }}" data-gateway-type-id="{{ $payment_method['gateway_type_id'] }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 dropdown-gateway-button hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cy="payment-method">
|
||||
<a href="#" @click="{ open = false }" data-cy="pay-with-custom" data-company-gateway-id="{{ $payment_method['company_gateway_id'] }}" data-gateway-type-id="{{ $payment_method['gateway_type_id'] }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 dropdown-gateway-button hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cy="payment-method">
|
||||
{{ \App\Models\CompanyGateway::find($payment_method['company_gateway_id'])->firstOrFail()->getConfigField('name') }}
|
||||
</a>
|
||||
@elseif($total > 0)
|
||||
<a href="#" @click="{ open = false }" data-company-gateway-id="{{ $payment_method['company_gateway_id'] }}" data-gateway-type-id="{{ $payment_method['gateway_type_id'] }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 dropdown-gateway-button hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cy="payment-method">
|
||||
<a href="#" @click="{ open = false }" data-cy="pay-with-{{ $index }}" data-company-gateway-id="{{ $payment_method['company_gateway_id'] }}" data-gateway-type-id="{{ $payment_method['gateway_type_id'] }}" class="block px-4 py-2 text-sm leading-5 text-gray-700 dropdown-gateway-button hover:bg-gray-100 hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900" data-cy="payment-method">
|
||||
{{ $payment_method['label'] }}
|
||||
</a>
|
||||
@endif
|
||||
|
Loading…
Reference in New Issue
Block a user