mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-07 01:54:16 +01:00
handle successfull stripe payment
This commit is contained in:
parent
1e43dc9518
commit
96b1cfcbc7
@ -4,10 +4,11 @@ import { PaymentMethod } from "@stripe/stripe-js";
|
|||||||
import PaymentAPI from '../api/payment';
|
import PaymentAPI from '../api/payment';
|
||||||
import { CartItems, PaymentConfirmation } from '../models/payment';
|
import { CartItems, PaymentConfirmation } from '../models/payment';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Reservation } from '../models/reservation';
|
||||||
|
|
||||||
interface StripeFormProps {
|
interface StripeFormProps {
|
||||||
onSubmit: () => void,
|
onSubmit: () => void,
|
||||||
onSuccess: (paymentMethod: PaymentMethod) => void,
|
onSuccess: (result: PaymentMethod|PaymentConfirmation) => void,
|
||||||
onError: (message: string) => void,
|
onError: (message: string) => void,
|
||||||
className?: string,
|
className?: string,
|
||||||
processPayment?: boolean,
|
processPayment?: boolean,
|
||||||
@ -48,7 +49,7 @@ export const StripeForm: React.FC<StripeFormProps> = ({ onSubmit, onSuccess, onE
|
|||||||
if (processPayment) {
|
if (processPayment) {
|
||||||
// process the full payment pipeline, including SCA validation
|
// process the full payment pipeline, including SCA validation
|
||||||
const res = await PaymentAPI.confirm(paymentMethod.id, cartItems);
|
const res = await PaymentAPI.confirm(paymentMethod.id, cartItems);
|
||||||
await handleServerConfirmation(res, paymentMethod);
|
await handleServerConfirmation(res);
|
||||||
} else {
|
} else {
|
||||||
// we don't want to process the payment, only return the payment method
|
// we don't want to process the payment, only return the payment method
|
||||||
onSuccess(paymentMethod);
|
onSuccess(paymentMethod);
|
||||||
@ -58,8 +59,12 @@ export const StripeForm: React.FC<StripeFormProps> = ({ onSubmit, onSuccess, onE
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Process the server response about the Strong-customer authentication (SCA)
|
* Process the server response about the Strong-customer authentication (SCA)
|
||||||
|
* @param response can be a PaymentConfirmation, or a Reservation (if the reservation succeeded), or a Subscription (if the subscription succeeded)
|
||||||
|
* @see app/controllers/api/payments_controller.rb#on_reservation_success
|
||||||
|
* @see app/controllers/api/payments_controller.rb#on_subscription_success
|
||||||
|
* @see app/controllers/api/payments_controller.rb#generate_payment_response
|
||||||
*/
|
*/
|
||||||
const handleServerConfirmation = async (response: PaymentConfirmation, paymentMethod: PaymentMethod) => {
|
const handleServerConfirmation = async (response: PaymentConfirmation|any) => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
if (response.error.statusText) {
|
if (response.error.statusText) {
|
||||||
onError(response.error.statusText);
|
onError(response.error.statusText);
|
||||||
@ -76,13 +81,13 @@ export const StripeForm: React.FC<StripeFormProps> = ({ onSubmit, onSuccess, onE
|
|||||||
// The PaymentIntent can be confirmed again on the server
|
// The PaymentIntent can be confirmed again on the server
|
||||||
try {
|
try {
|
||||||
const confirmation = await PaymentAPI.confirm(result.paymentIntent.id, cartItems);
|
const confirmation = await PaymentAPI.confirm(result.paymentIntent.id, cartItems);
|
||||||
await handleServerConfirmation(confirmation, paymentMethod);
|
await handleServerConfirmation(confirmation);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
onError(e);
|
onError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
onSuccess(paymentMethod);
|
onSuccess(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import { StripeForm } from './stripe-form';
|
|||||||
import stripeLogo from '../../../images/powered_by_stripe.png';
|
import stripeLogo from '../../../images/powered_by_stripe.png';
|
||||||
import mastercardLogo from '../../../images/mastercard.png';
|
import mastercardLogo from '../../../images/mastercard.png';
|
||||||
import visaLogo from '../../../images/visa.png';
|
import visaLogo from '../../../images/visa.png';
|
||||||
import { CartItems } from '../models/payment';
|
import { CartItems, PaymentConfirmation } from '../models/payment';
|
||||||
import WalletAPI from '../api/wallet';
|
import WalletAPI from '../api/wallet';
|
||||||
import PriceAPI from '../api/price';
|
import PriceAPI from '../api/price';
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ declare var Fablab: IFablab;
|
|||||||
interface StripeModalProps {
|
interface StripeModalProps {
|
||||||
isOpen: boolean,
|
isOpen: boolean,
|
||||||
toggleModal: () => void,
|
toggleModal: () => void,
|
||||||
afterSuccess: (paymentMethod: PaymentMethod) => void,
|
afterSuccess: (result: PaymentMethod|PaymentConfirmation) => void,
|
||||||
cartItems: CartItems,
|
cartItems: CartItems,
|
||||||
currentUser: User,
|
currentUser: User,
|
||||||
schedule: PaymentSchedule,
|
schedule: PaymentSchedule,
|
||||||
@ -140,9 +140,9 @@ const StripeModal: React.FC<StripeModalProps> = ({ isOpen, toggleModal, afterSuc
|
|||||||
/**
|
/**
|
||||||
* After sending the form with success, process the resulting payment method
|
* After sending the form with success, process the resulting payment method
|
||||||
*/
|
*/
|
||||||
const handleFormSuccess = async (paymentMethod: PaymentMethod): Promise<void> => {
|
const handleFormSuccess = async (result: PaymentMethod|PaymentConfirmation): Promise<void> => {
|
||||||
setSubmitState(false);
|
setSubmitState(false);
|
||||||
afterSuccess(paymentMethod);
|
afterSuccess(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -735,19 +735,6 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
|
|||||||
* @param user {Object} user associated with the slot
|
* @param user {Object} user associated with the slot
|
||||||
*/
|
*/
|
||||||
const updateMachineSlot = function (slot, reservation, user) {
|
const updateMachineSlot = function (slot, reservation, user) {
|
||||||
/* TODO, FIXME
|
|
||||||
machines.js.erb:741 Uncaught (in promise) TypeError: Cannot read property 'slots' of undefined
|
|
||||||
at updateMachineSlot (machines.js.erb:741)
|
|
||||||
at machines.js.erb:664
|
|
||||||
at Object.forEach (angular.js:386)
|
|
||||||
at Scope.$scope.afterPayment (machines.js.erb:652)
|
|
||||||
at afterPayment (cart.js:884)
|
|
||||||
at $scope.afterStripeSuccess (cart.js:338)
|
|
||||||
at _callee$ (stripe-modal.tsx:145)
|
|
||||||
at tryCatch (runtime.js:63)
|
|
||||||
at Generator.invoke [as _invoke] (runtime.js:293)
|
|
||||||
at Generator.next (runtime.js:118)
|
|
||||||
*/
|
|
||||||
angular.forEach(reservation.slots, function (s) {
|
angular.forEach(reservation.slots, function (s) {
|
||||||
if (slot.start.isSame(s.start_at)) {
|
if (slot.start.isSame(s.start_at)) {
|
||||||
slot.slot_id = s.id;
|
slot.slot_id = s.id;
|
||||||
|
@ -70,13 +70,13 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
|||||||
// Payment schedule
|
// Payment schedule
|
||||||
$scope.schedule = {
|
$scope.schedule = {
|
||||||
requested_schedule: false, // does the user requests a payment schedule for his subscription
|
requested_schedule: false, // does the user requests a payment schedule for his subscription
|
||||||
payment_schedule: null // the effective computed payment schedule
|
payment_schedule: undefined // the effective computed payment schedule
|
||||||
};
|
};
|
||||||
|
|
||||||
// online payments (stripe)
|
// online payments (stripe)
|
||||||
$scope.stripe = {
|
$scope.stripe = {
|
||||||
showModal: false,
|
showModal: false,
|
||||||
cartItems: null
|
cartItems: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
// currently logged-in user
|
// currently logged-in user
|
||||||
@ -327,10 +327,11 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked atfer a successful Stripe payment
|
* Invoked atfer a successful Stripe payment
|
||||||
|
* @param result {*} may be a reservation or a subscription
|
||||||
*/
|
*/
|
||||||
$scope.afterStripeSuccess = () => {
|
$scope.afterStripeSuccess = (result) => {
|
||||||
$scope.toggleStripeModal();
|
$scope.toggleStripeModal();
|
||||||
afterPayment($scope.reservation);
|
afterPayment(result);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* PRIVATE SCOPE */
|
/* PRIVATE SCOPE */
|
||||||
@ -638,9 +639,9 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object
|
* Format the parameters expected by /api/prices/compute or /api/reservations and return the resulting object
|
||||||
* @param request {{reservation: object}|{subscription: object}} as returned by mkReservation()
|
* @param request {{reservation: *}|{subscription: *}} as returned by mkReservation()
|
||||||
* @param coupon {Object} Coupon as returned from the API
|
* @param coupon {{code: string}} Coupon as returned from the API
|
||||||
* @return {{reservation:Object, subscription: Object, coupon_code:string}}
|
* @return {CartItems}
|
||||||
*/
|
*/
|
||||||
const mkRequestParams = function (request, coupon) {
|
const mkRequestParams = function (request, coupon) {
|
||||||
return Object.assign({
|
return Object.assign({
|
||||||
@ -870,28 +871,28 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Actions to run after the payment was successful
|
* Actions to run after the payment was successful
|
||||||
* @param reservation {Object} may be a reservation or a subscription
|
* @param paymentResult {*} may be a reservation or a subscription
|
||||||
*/
|
*/
|
||||||
const afterPayment = function (reservation) {
|
const afterPayment = function (paymentResult) {
|
||||||
// we set the cart content as 'paid' to display a summary of the transaction
|
// we set the cart content as 'paid' to display a summary of the transaction
|
||||||
$scope.events.paid = $scope.events.reserved;
|
$scope.events.paid = $scope.events.reserved;
|
||||||
$scope.amountPaid = $scope.amountTotal;
|
$scope.amountPaid = $scope.amountTotal;
|
||||||
// we call the external callback if present
|
// we call the external callback if present
|
||||||
if (typeof $scope.afterPayment === 'function') { $scope.afterPayment(reservation); }
|
if (typeof $scope.afterPayment === 'function') { $scope.afterPayment(paymentResult); }
|
||||||
// we reset the coupon, and the cart content, and we unselect the slot
|
// we reset the coupon, and the cart content, and we unselect the slot
|
||||||
$scope.coupon.applied = null;
|
$scope.coupon.applied = undefined;
|
||||||
if ($scope.slot) {
|
if ($scope.slot) {
|
||||||
// reservation (+ subscription)
|
// reservation (+ subscription)
|
||||||
$scope.slot = null;
|
$scope.slot = undefined;
|
||||||
$scope.events.reserved = [];
|
$scope.events.reserved = [];
|
||||||
} else {
|
} else {
|
||||||
// subscription only
|
// subscription only
|
||||||
$scope.events = {};
|
$scope.events = {};
|
||||||
}
|
}
|
||||||
$scope.paidPlan = $scope.selectedPlan;
|
$scope.paidPlan = $scope.selectedPlan;
|
||||||
$scope.selectedPlan = null;
|
$scope.selectedPlan = undefined;
|
||||||
$scope.schedule.requested_schedule = false;
|
$scope.schedule.requested_schedule = false;
|
||||||
$scope.schedule.payment_schedule = null;
|
$scope.schedule.payment_schedule = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,7 @@ export interface PaymentConfirmation {
|
|||||||
success?: boolean,
|
success?: boolean,
|
||||||
error?: {
|
error?: {
|
||||||
statusText: string
|
statusText: string
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PaymentMethod {
|
export enum PaymentMethod {
|
||||||
@ -15,12 +15,12 @@ export enum PaymentMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CartItems {
|
export interface CartItems {
|
||||||
reservation: Reservation,
|
reservation?: Reservation,
|
||||||
subscription: {
|
subscription?: {
|
||||||
plan_id: number,
|
plan_id: number,
|
||||||
user_id: number,
|
user_id: number,
|
||||||
payment_schedule: boolean,
|
payment_schedule: boolean,
|
||||||
payment_method: PaymentMethod
|
payment_method: PaymentMethod
|
||||||
},
|
},
|
||||||
coupon_code: string
|
coupon_code?: string
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user