From 431ea28448266977080452ef63838fa3a94566c0 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 1 Jun 2021 12:20:02 +0200 Subject: [PATCH] WIP: payzen recurring payments --- app/controllers/api/payzen_controller.rb | 18 ++++++++++++++++++ app/frontend/src/javascript/api/payzen.ts | 9 +++++++-- .../components/payment/payzen/payzen-form.tsx | 18 ++++++++++++++++-- app/models/cart_item/subscription.rb | 2 +- config/routes.rb | 1 + lib/pay_zen/client.rb | 2 +- lib/pay_zen/service.rb | 2 +- lib/pay_zen/transaction.rb | 17 +++++++++++++++++ 8 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 lib/pay_zen/transaction.rb diff --git a/app/controllers/api/payzen_controller.rb b/app/controllers/api/payzen_controller.rb index 7cc33fb44..f9b3d62a3 100644 --- a/app/controllers/api/payzen_controller.rb +++ b/app/controllers/api/payzen_controller.rb @@ -4,6 +4,7 @@ class API::PayzenController < API::PaymentsController require 'pay_zen/charge' require 'pay_zen/order' + require 'pay_zen/transaction' require 'pay_zen/helper' def sdk_test @@ -58,6 +59,23 @@ class API::PayzenController < API::PaymentsController render json: e, status: :unprocessable_entity end + def confirm_payment_schedule + render(json: { error: 'Bad gateway or online payment is disabled' }, status: :bad_gateway) and return unless PayZen::Helper.enabled? + + client = PayZen::Transaction.new + transaction = client.get(params[:transaction_uuid]) + + cart = shopping_cart + + if transaction['answer']['status'] == 'PAID' + render on_payment_success(params[:order_id], cart) + else + render json: transaction['answer'], status: :unprocessable_entity + end + rescue StandardError => e + render json: e, status: :unprocessable_entity + end + private def on_payment_success(order_id, cart) diff --git a/app/frontend/src/javascript/api/payzen.ts b/app/frontend/src/javascript/api/payzen.ts index a055d66fc..e8bc33bfd 100644 --- a/app/frontend/src/javascript/api/payzen.ts +++ b/app/frontend/src/javascript/api/payzen.ts @@ -33,8 +33,13 @@ export default class PayzenAPI { return res?.data; } - static async confirm(orderId: string, cart: ShoppingCart): Promise { - const res: AxiosResponse = await apiClient.post('/api/payzen/confirm_payment', { cart_items: cart, order_id: orderId }); + static async confirm(orderId: string, cart: ShoppingCart): Promise { + const res: AxiosResponse = await apiClient.post('/api/payzen/confirm_payment', { cart_items: cart, order_id: orderId }); + return res?.data; + } + + static async confirmPaymentSchedule(orderId: string, transactionUuid: string, cart: ShoppingCart): Promise { + const res: AxiosResponse = await apiClient.post('/api/payzen/confirm_payment_schedule', { cart_items: cart, order_id: orderId, transaction_uuid: transactionUuid }); return res?.data; } } diff --git a/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx b/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx index a93c183e0..df0c87768 100644 --- a/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx +++ b/app/frontend/src/javascript/components/payment/payzen/payzen-form.tsx @@ -8,9 +8,11 @@ import { Loader } from '../../base/loader'; import { CreateTokenResponse, KryptonClient, - KryptonError, + KryptonError, PaymentTransaction, ProcessPaymentAnswer } from '../../../models/payzen'; +import { PaymentSchedule } from '../../../models/payment-schedule'; +import { Invoice } from '../../../models/invoice'; /** * A form component to collect the credit card details and to create the payment method on Stripe. @@ -63,7 +65,7 @@ export const PayzenForm: React.FC = ({ onSubmit, onSuccess, on const transaction = event.clientAnswer.transactions[0]; if (event.clientAnswer.orderStatus === 'PAID') { - PayzenAPI.confirm(event.clientAnswer.orderDetails.orderId, cart).then((confirmation) => { + confirmPayment(event, transaction).then((confirmation) => { PayZenKR.current.removeForms().then(() => { onSuccess(confirmation); }); @@ -77,6 +79,18 @@ export const PayzenForm: React.FC = ({ onSubmit, onSuccess, on return true; }; + /** + * Confirm the payment, depending on the current type of payment (single shot or recurring) + * @param event + */ + const confirmPayment = async (event: ProcessPaymentAnswer, transaction: PaymentTransaction): Promise => { + if (!paymentSchedule) { + return await PayzenAPI.confirm(event.clientAnswer.orderDetails.orderId, cart); + } else { + return await PayzenAPI.confirmPaymentSchedule(event.clientAnswer.orderDetails.orderId, transaction.uuid, cart); + } + } + /** * Callback triggered when the PayZen form was entirely loaded and displayed * @see https://docs.lyra.com/fr/rest/V4.0/javascript/features/reference.html#%C3%89v%C3%A9nements diff --git a/app/models/cart_item/subscription.rb b/app/models/cart_item/subscription.rb index 9016d1182..4b1a96f17 100644 --- a/app/models/cart_item/subscription.rb +++ b/app/models/cart_item/subscription.rb @@ -28,7 +28,7 @@ class CartItem::Subscription < CartItem::BaseItem end def to_object - Subscription.new( + ::Subscription.new( plan_id: @plan.id, statistic_profile_id: StatisticProfile.find_by(user: @customer).id ) diff --git a/config/routes.rb b/config/routes.rb index cb81910bb..e79ab602f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -183,6 +183,7 @@ Rails.application.routes.draw do post 'payzen/sdk_test' => 'payzen#sdk_test' post 'payzen/create_payment' => 'payzen#create_payment' post 'payzen/confirm_payment' => 'payzen#confirm_payment' + post 'payzen/confirm_payment_schedule' => 'payzen#confirm_payment_schedule' post 'payzen/check_hash' => 'payzen#check_hash' post 'payzen/create_token' => 'payzen#create_token' diff --git a/lib/pay_zen/client.rb b/lib/pay_zen/client.rb index 860abf4e0..810d0201e 100644 --- a/lib/pay_zen/client.rb +++ b/lib/pay_zen/client.rb @@ -30,7 +30,7 @@ class PayZen::Client raise ::PayzenError unless res.is_a?(Net::HTTPSuccess) json = JSON.parse(res.body) - raise ::PayzenError, json['answer']['errorMessage'] if json['status'] == 'ERROR' + raise ::PayzenError, json['answer'] if json['status'] == 'ERROR' json end diff --git a/lib/pay_zen/service.rb b/lib/pay_zen/service.rb index 62f577715..cbdc9c360 100644 --- a/lib/pay_zen/service.rb +++ b/lib/pay_zen/service.rb @@ -12,7 +12,7 @@ class PayZen::Service < Payment::Service def create_subscription(payment_schedule, order_id) first_item = payment_schedule.ordered_items.first - order = PayZen::Order.new.get(order_id: order_id, operation_type: 'VERIFICATION') + order = PayZen::Order.new.get(order_id, operation_type: 'VERIFICATION') client = PayZen::Charge.new params = { diff --git a/lib/pay_zen/transaction.rb b/lib/pay_zen/transaction.rb new file mode 100644 index 000000000..db9446a62 --- /dev/null +++ b/lib/pay_zen/transaction.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'pay_zen/client' + +# Transaction/* endpoints of the PayZen REST API +class PayZen::Transaction < PayZen::Client + def initialize(base_url: nil, username: nil, password: nil) + super(base_url: base_url, username: username, password: password) + end + + ## + # @see https://payzen.io/fr-FR/rest/V4.0/api/playground/Transaction/Get/ + ## + def get(uuid) + post('/Transaction/Get/', uuid: uuid) + end +end