diff --git a/app/controllers/api/payments_controller.rb b/app/controllers/api/payments_controller.rb index bbaf75985..e7ed4a40e 100644 --- a/app/controllers/api/payments_controller.rb +++ b/app/controllers/api/payments_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# API Controller for handling payments process in the front-end +# Abstract API Controller to be extended by each gateway, for handling the payments processes in the front-end class API::PaymentsController < API::ApiController before_action :authenticate_user! diff --git a/app/controllers/api/stripe_controller.rb b/app/controllers/api/stripe_controller.rb index de9937700..839992810 100644 --- a/app/controllers/api/stripe_controller.rb +++ b/app/controllers/api/stripe_controller.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# API Controller for handling payments process in the front-end +# API Controller for handling the payments process in the front-end, using the Stripe gateway class API::StripeController < API::PaymentsController ## diff --git a/app/frontend/src/javascript/api/custom-asset.ts b/app/frontend/src/javascript/api/custom-asset.ts index ecde60ab4..254241090 100644 --- a/app/frontend/src/javascript/api/custom-asset.ts +++ b/app/frontend/src/javascript/api/custom-asset.ts @@ -1,4 +1,4 @@ -import apiClient from './api-client'; +import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; import { CustomAsset, CustomAssetName } from '../models/custom-asset'; import wrapPromise, { IWrapPromise } from '../lib/wrap-promise'; diff --git a/app/frontend/src/javascript/api/external/stripe.ts b/app/frontend/src/javascript/api/external/stripe.ts index c37a970de..48a58c14d 100644 --- a/app/frontend/src/javascript/api/external/stripe.ts +++ b/app/frontend/src/javascript/api/external/stripe.ts @@ -1,4 +1,4 @@ -import stripeClient from './stripe-client'; +import stripeClient from '../clients/stripe-client'; import { AxiosResponse } from 'axios'; export default class StripeAPI { diff --git a/app/frontend/src/javascript/api/payment-schedule.ts b/app/frontend/src/javascript/api/payment-schedule.ts index 97b3990ed..882d9548a 100644 --- a/app/frontend/src/javascript/api/payment-schedule.ts +++ b/app/frontend/src/javascript/api/payment-schedule.ts @@ -1,4 +1,4 @@ -import apiClient from './api-client'; +import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; import { CancelScheduleResponse, diff --git a/app/frontend/src/javascript/api/payzen.ts b/app/frontend/src/javascript/api/payzen.ts index ed1a39feb..4ff7009de 100644 --- a/app/frontend/src/javascript/api/payzen.ts +++ b/app/frontend/src/javascript/api/payzen.ts @@ -1,4 +1,4 @@ -import apiClient from './api-client'; +import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; import { CartItems } from '../models/payment'; import { User } from '../models/user'; diff --git a/app/frontend/src/javascript/api/price.ts b/app/frontend/src/javascript/api/price.ts index c0e1b0f91..3acfa72e8 100644 --- a/app/frontend/src/javascript/api/price.ts +++ b/app/frontend/src/javascript/api/price.ts @@ -1,4 +1,4 @@ -import apiClient from './api-client'; +import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; import { CartItems } from '../models/payment'; import { ComputePriceResult } from '../models/price'; diff --git a/app/frontend/src/javascript/api/setting.ts b/app/frontend/src/javascript/api/setting.ts index 7de47c264..d5a199a5d 100644 --- a/app/frontend/src/javascript/api/setting.ts +++ b/app/frontend/src/javascript/api/setting.ts @@ -1,4 +1,4 @@ -import apiClient from './api-client'; +import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; import { Setting, SettingBulkResult, SettingError, SettingName } from '../models/setting'; import wrapPromise, { IWrapPromise } from '../lib/wrap-promise'; diff --git a/app/frontend/src/javascript/api/stripe.ts b/app/frontend/src/javascript/api/stripe.ts index eff57cfd7..9a0fbcd41 100644 --- a/app/frontend/src/javascript/api/stripe.ts +++ b/app/frontend/src/javascript/api/stripe.ts @@ -1,8 +1,8 @@ -import apiClient from './api-client'; +import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; import { CartItems, IntentConfirmation, PaymentConfirmation, UpdateCardResponse } from '../models/payment'; -export default class PaymentAPI { +export default class StripeAPI { static async confirm (stp_payment_method_id: string, cart_items: CartItems): Promise { const res: AxiosResponse = await apiClient.post(`/api/payments/confirm_payment`, { payment_method_id: stp_payment_method_id, diff --git a/app/frontend/src/javascript/api/wallet.ts b/app/frontend/src/javascript/api/wallet.ts index 590085611..8b818a42d 100644 --- a/app/frontend/src/javascript/api/wallet.ts +++ b/app/frontend/src/javascript/api/wallet.ts @@ -1,4 +1,4 @@ -import apiClient from './api-client'; +import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; import wrapPromise, { IWrapPromise } from '../lib/wrap-promise'; import { Wallet } from '../models/wallet'; diff --git a/app/frontend/src/javascript/components/payment/stripe/stripe-card-update.tsx b/app/frontend/src/javascript/components/payment/stripe/stripe-card-update.tsx index b52036d22..5aa9a8b5b 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-card-update.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-card-update.tsx @@ -3,7 +3,7 @@ import { CardElement, useElements, useStripe } from '@stripe/react-stripe-js'; import { SetupIntent } from "@stripe/stripe-js"; import { PaymentConfirmation } from '../../../models/payment'; import { User } from '../../../models/user'; -import PaymentAPI from '../../../api/payment'; +import StripeAPI from '../../../api/stripe'; interface StripeCardUpdateProps { onSubmit: () => void, @@ -47,7 +47,7 @@ export const StripeCardUpdate: React.FC = ({ onSubmit, on } else { try { // we start by associating the payment method with the user - const { client_secret } = await PaymentAPI.setupIntent(customerId); + const { client_secret } = await StripeAPI.setupIntent(customerId); const { error } = await stripe.confirmCardSetup(client_secret, { payment_method: paymentMethod.id, mandate_data: { @@ -64,7 +64,7 @@ export const StripeCardUpdate: React.FC = ({ onSubmit, on onError(error.message); } else { // then we update the default payment method - const res = await PaymentAPI.updateCard(customerId, paymentMethod.id); + const res = await StripeAPI.updateCard(customerId, paymentMethod.id); onSuccess(res); } } catch (err) { diff --git a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx index ffc78e5ea..5af01c81f 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-form.tsx @@ -4,7 +4,7 @@ import { SetupIntent } from "@stripe/stripe-js"; import { useTranslation } from 'react-i18next'; import { CartItems, PaymentConfirmation } from '../../../models/payment'; import { User } from '../../../models/user'; -import PaymentAPI from '../../../api/payment'; +import StripeAPI from '../../../api/stripe'; interface StripeFormProps { onSubmit: () => void, @@ -53,11 +53,11 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, onE try { if (!paymentSchedule) { // process the normal payment pipeline, including SCA validation - const res = await PaymentAPI.confirm(paymentMethod.id, cartItems); + const res = await StripeAPI.confirm(paymentMethod.id, cartItems); await handleServerConfirmation(res); } else { // we start by associating the payment method with the user - const { client_secret } = await PaymentAPI.setupIntent(customer.id); + const { client_secret } = await StripeAPI.setupIntent(customer.id); const { setupIntent, error } = await stripe.confirmCardSetup(client_secret, { payment_method: paymentMethod.id, mandate_data: { @@ -74,7 +74,7 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, onE onError(error.message); } else { // then we confirm the payment schedule - const res = await PaymentAPI.confirmPaymentSchedule(setupIntent.id, cartItems); + const res = await StripeAPI.confirmPaymentSchedule(setupIntent.id, cartItems); onSuccess(res); } } @@ -108,7 +108,7 @@ export const StripeForm: React.FC = ({ onSubmit, onSuccess, onE // The card action has been handled // The PaymentIntent can be confirmed again on the server try { - const confirmation = await PaymentAPI.confirm(result.paymentIntent.id, cartItems); + const confirmation = await StripeAPI.confirm(result.paymentIntent.id, cartItems); await handleServerConfirmation(confirmation); } catch (e) { onError(e); diff --git a/app/frontend/src/javascript/components/payment/stripe/stripe-keys-form.tsx b/app/frontend/src/javascript/components/payment/stripe/stripe-keys-form.tsx index 9cd434dff..22b3a0389 100644 --- a/app/frontend/src/javascript/components/payment/stripe/stripe-keys-form.tsx +++ b/app/frontend/src/javascript/components/payment/stripe/stripe-keys-form.tsx @@ -4,7 +4,7 @@ import { HtmlTranslate } from '../../base/html-translate'; import { FabInput } from '../../base/fab-input'; import { Loader } from '../../base/loader'; import { SettingName } from '../../../models/setting'; -import StripeAPI from '../../../api/stripe'; +import StripeAPI from '../../../api/external/stripe'; import SettingAPI from '../../../api/setting'; diff --git a/app/frontend/src/javascript/services/payment.js b/app/frontend/src/javascript/services/payment.js index 69c80d865..70ba1f51b 100644 --- a/app/frontend/src/javascript/services/payment.js +++ b/app/frontend/src/javascript/services/payment.js @@ -5,12 +5,12 @@ Application.Services.factory('Payment', ['$resource', function ($resource) { {}, { confirm: { method: 'POST', - url: '/api/payments/confirm_payment', + url: '/api/stripe/confirm_payment', isArray: false }, onlinePaymentStatus: { method: 'GET', - url: '/api/payments/online_payment_status' + url: '/api/stripe/online_payment_status' } } ); diff --git a/config/routes.rb b/config/routes.rb index 09ef94b29..7b0f3c907 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -171,22 +171,23 @@ Rails.application.routes.draw do # Fab-manager's version post 'version' => 'version#show' - # payments handling - post 'payments/confirm_payment' => 'payments/confirm_payment' - get 'payments/online_payment_status' => 'payments/online_payment_status' - get 'payments/setup_intent/:user_id' => 'payments#setup_intent' - post 'payments/confirm_payment_schedule' => 'payments#confirm_payment_schedule' - post 'payments/update_card' => 'payments#update_card' + # card payments handling + ## Stripe gateway + post 'stripe/confirm_payment' => 'stripe/confirm_payment' + get 'stripe/online_payment_status' => 'stripe/online_payment_status' + get 'stripe/setup_intent/:user_id' => 'stripe#setup_intent' + post 'stripe/confirm_payment_schedule' => 'stripe#confirm_payment_schedule' + post 'stripe/update_card' => 'stripe#update_card' + + ## PayZen gateway + post 'payzen/sdk_test' => 'payzen#sdk_test' + post 'payzen/create_payment' => 'payzen#create_payment' # FabAnalytics get 'analytics/data' => 'analytics#data' # test MIME type post 'files/mime_type' => 'files#mime' - - # PayZen special endpoint - post 'payzen/sdk_test' => 'payzen#sdk_test' - post 'payzen/create_payment' => 'payzen#create_payment' end # rss diff --git a/test/integration/events/as_user_test.rb b/test/integration/events/as_user_test.rb index a89a026a2..6ad6095be 100644 --- a/test/integration/events/as_user_test.rb +++ b/test/integration/events/as_user_test.rb @@ -26,7 +26,7 @@ module Events # Reserve the 'radio' event VCR.use_cassette('reserve_event_with_many_prices_and_payment_means') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { diff --git a/test/integration/reservations/create_test.rb b/test/integration/reservations/create_test.rb index 3ef638bf2..e761276d4 100644 --- a/test/integration/reservations/create_test.rb +++ b/test/integration/reservations/create_test.rb @@ -21,7 +21,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest subscriptions_count = Subscription.count VCR.use_cassette('reservations_create_for_machine_without_subscription_success') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -91,7 +91,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest notifications_count = Notification.count VCR.use_cassette('reservations_create_for_machine_without_subscription_error') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method(error: :card_declined), cart_items: { @@ -139,7 +139,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest invoice_items_count = InvoiceItem.count VCR.use_cassette('reservations_create_for_training_without_subscription_success') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -208,7 +208,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest users_credit_count = UsersCredit.count VCR.use_cassette('reservations_create_for_machine_with_subscription_success') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -363,7 +363,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest wallet_transactions_count = WalletTransaction.count VCR.use_cassette('reservations_create_for_machine_and_pay_wallet_success') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -447,7 +447,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest wallet_transactions_count = WalletTransaction.count VCR.use_cassette('reservations_create_for_training_and_plan_by_pay_wallet_success') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -525,7 +525,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest users_credit_count = UsersCredit.count VCR.use_cassette('reservations_machine_and_plan_using_coupon_success') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -616,7 +616,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest notifications_count = Notification.count VCR.use_cassette('reservations_training_with_expired_coupon_error') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -667,7 +667,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest plan = Plan.find_by(group_id: @user_without_subscription.group.id, type: 'Plan', base_name: 'Abonnement mensualisable') VCR.use_cassette('reservations_training_subscription_with_payment_schedule') do - get "/api/payments/setup_intent/#{@user_without_subscription.id}" + get "/api/stripe/setup_intent/#{@user_without_subscription.id}" # Check response format & status assert_equal 200, response.status, response.body @@ -692,7 +692,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest assert_equal 'off_session', stripe_res.usage - post '/api/payments/confirm_payment_schedule', + post '/api/stripe/confirm_payment_schedule', params: { setup_intent_id: setup_intent[:id], cart_items: { @@ -761,7 +761,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest plan = Plan.find_by(group_id: user.group.id, type: 'Plan', base_name: 'Abonnement mensualisable') VCR.use_cassette('reservations_machine_subscription_with_payment_schedule_coupon_wallet') do - get "/api/payments/setup_intent/#{user.id}" + get "/api/stripe/setup_intent/#{user.id}" # Check response format & status assert_equal 200, response.status, response.body @@ -786,7 +786,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest assert_equal 'off_session', stripe_res.usage - post '/api/payments/confirm_payment_schedule', + post '/api/stripe/confirm_payment_schedule', params: { setup_intent_id: setup_intent[:id], cart_items: { diff --git a/test/integration/subscriptions/create_as_admin_test.rb b/test/integration/subscriptions/create_as_admin_test.rb index 2d996fe8a..8a3b96ddc 100644 --- a/test/integration/subscriptions/create_as_admin_test.rb +++ b/test/integration/subscriptions/create_as_admin_test.rb @@ -65,7 +65,7 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest payment_schedule_items_count = PaymentScheduleItem.count VCR.use_cassette('subscriptions_admin_create_with_payment_schedule') do - get "/api/payments/setup_intent/#{user.id}" + get "/api/stripe/setup_intent/#{user.id}" # Check response format & status assert_equal 200, response.status, response.body @@ -90,7 +90,7 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest assert_equal 'off_session', stripe_res.usage - post '/api/payments/confirm_payment_schedule', + post '/api/stripe/confirm_payment_schedule', params: { setup_intent_id: setup_intent[:id], cart_items: { diff --git a/test/integration/subscriptions/create_as_user_test.rb b/test/integration/subscriptions/create_as_user_test.rb index 155aa8a59..733e15c74 100644 --- a/test/integration/subscriptions/create_as_user_test.rb +++ b/test/integration/subscriptions/create_as_user_test.rb @@ -12,7 +12,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest plan = Plan.find_by(group_id: @user.group.id, type: 'Plan', base_name: 'Mensuel') VCR.use_cassette('subscriptions_user_create_success') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -72,7 +72,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest plan = Plan.where.not(group_id: @user.group.id).first VCR.use_cassette('subscriptions_user_create_failed') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -100,7 +100,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest plan = Plan.find_by(group_id: @vlonchamp.group.id, type: 'Plan', base_name: 'Mensuel tarif réduit') VCR.use_cassette('subscriptions_user_create_success_with_wallet') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -175,7 +175,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest payment_schedule_items_count = PaymentScheduleItem.count VCR.use_cassette('subscriptions_user_create_with_payment_schedule') do - get "/api/payments/setup_intent/#{@user.id}" + get "/api/stripe/setup_intent/#{@user.id}" # Check response format & status assert_equal 200, response.status, response.body @@ -200,7 +200,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest assert_equal 'off_session', stripe_res.usage - post '/api/payments/confirm_payment_schedule', + post '/api/stripe/confirm_payment_schedule', params: { setup_intent_id: setup_intent[:id], cart_items: { diff --git a/test/integration/subscriptions/renew_as_user_test.rb b/test/integration/subscriptions/renew_as_user_test.rb index 3d142ddc1..d0726d39d 100644 --- a/test/integration/subscriptions/renew_as_user_test.rb +++ b/test/integration/subscriptions/renew_as_user_test.rb @@ -13,7 +13,7 @@ class Subscriptions::RenewAsUserTest < ActionDispatch::IntegrationTest stripe_subscription = nil VCR.use_cassette('subscriptions_user_renew_success', erb: true) do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method, cart_items: { @@ -77,7 +77,7 @@ class Subscriptions::RenewAsUserTest < ActionDispatch::IntegrationTest previous_expiration = @user.subscription.expired_at.to_i VCR.use_cassette('subscriptions_user_renew_failed') do - post '/api/payments/confirm_payment', + post '/api/stripe/confirm_payment', params: { payment_method_id: stripe_payment_method(error: :card_declined), cart_items: {