mirror of
https://github.com/valitydev/checkout.git
synced 2024-11-06 10:35:20 +00:00
APM-79: Add self redirect for payment terminal (#82)
This commit is contained in:
parent
7b5383d0fd
commit
85efc4a2fd
@ -1,14 +1,15 @@
|
||||
import { Payer } from './payer';
|
||||
import { PaymentToolDetails } from '../payment-tool-details';
|
||||
import { ClientInfo } from '../client-info';
|
||||
import { ContactInfo } from '../contact-info';
|
||||
import { PayerType } from './payer-type';
|
||||
import { PaymentToolDetails } from '../payment-tool-details';
|
||||
|
||||
export class PaymentResourcePayer extends Payer {
|
||||
payerType: PayerType.PaymentResourcePayer;
|
||||
paymentToolToken: string;
|
||||
paymentSession: string;
|
||||
contactInfo: ContactInfo;
|
||||
sessionInfo?: {
|
||||
redirectUrl: string;
|
||||
};
|
||||
paymentToolDetails?: PaymentToolDetails;
|
||||
clientInfo?: ClientInfo;
|
||||
}
|
||||
|
@ -43,11 +43,15 @@ export const RedirectForm: React.FC = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
const prepared = prepareForm(origin, request, '_blank');
|
||||
const prepared = prepareForm(origin, request, '_self');
|
||||
containerRef.current.appendChild(prepared);
|
||||
setForm(prepared);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
form && form.submit();
|
||||
}, [form]);
|
||||
|
||||
const redirect = () => {
|
||||
form.submit();
|
||||
dispatch(finishInteraction());
|
||||
|
@ -19,13 +19,20 @@ export const toPaymentFlow = (c: InitConfig): PaymentFlow => {
|
||||
return c.paymentFlowHold ? hold : instant;
|
||||
};
|
||||
|
||||
const getSessionInfo = (redirectUrl: string) => ({
|
||||
sessionInfo: {
|
||||
redirectUrl
|
||||
}
|
||||
});
|
||||
|
||||
export function* createPayment(
|
||||
endpoint: string,
|
||||
token: string,
|
||||
invoiceID: string,
|
||||
formEmail: string,
|
||||
resource: PaymentResource,
|
||||
initConfig: InitConfig
|
||||
initConfig: InitConfig,
|
||||
redirectUrl?: string
|
||||
): Iterator<Effects> {
|
||||
const email = initConfig.email || formEmail;
|
||||
const { paymentToolToken, paymentSession } = resource;
|
||||
@ -37,7 +44,8 @@ export function* createPayment(
|
||||
paymentSession,
|
||||
contactInfo: {
|
||||
email
|
||||
}
|
||||
},
|
||||
...(redirectUrl && getSessionInfo(redirectUrl))
|
||||
},
|
||||
makeRecurrent: initConfig.recurring,
|
||||
metadata: initConfig.metadata
|
||||
|
@ -7,26 +7,47 @@ import { createPayment } from './create-payment';
|
||||
import { pollInvoiceEvents } from '../../poll-events';
|
||||
import { TypeKeys } from 'checkout/actions';
|
||||
import { SetAcceptedError } from 'checkout/actions/error-actions/set-accepted-error';
|
||||
import { serializeUrlParams } from '../../../../serialize-url-params';
|
||||
|
||||
type CreatePaymentResourceFn = (invoiceAccessToken: any) => Iterator<PaymentResource>;
|
||||
|
||||
const prepareRedirectUrl = (origin: string, invoiceID: string, invoiceAccessToken: string, configRedirectUrl: string) =>
|
||||
`${origin}/v1/checkout.html?${serializeUrlParams({
|
||||
invoiceID,
|
||||
invoiceAccessToken,
|
||||
configRedirectUrl
|
||||
})}`;
|
||||
|
||||
export function* makePayment(
|
||||
config: Config,
|
||||
model: ModelState,
|
||||
values: PayableFormValues,
|
||||
amountInfo: AmountInfoState,
|
||||
fn: CreatePaymentResourceFn,
|
||||
withPolling = true
|
||||
setRedirect = false
|
||||
) {
|
||||
const { initConfig, appConfig } = config;
|
||||
const { initConfig, appConfig, origin } = config;
|
||||
const { capiEndpoint } = appConfig;
|
||||
const {
|
||||
invoice: { id },
|
||||
invoiceAccessToken
|
||||
} = yield call(getPayableInvoice, initConfig, capiEndpoint, model, amountInfo, values.amount);
|
||||
const paymentResource = yield call(fn, invoiceAccessToken);
|
||||
let redirectUrl;
|
||||
if (setRedirect) {
|
||||
redirectUrl = prepareRedirectUrl(origin, id, invoiceAccessToken, initConfig.redirectUrl);
|
||||
}
|
||||
try {
|
||||
yield call(createPayment, capiEndpoint, invoiceAccessToken, id, values.email, paymentResource, initConfig);
|
||||
yield call(
|
||||
createPayment,
|
||||
capiEndpoint,
|
||||
invoiceAccessToken,
|
||||
id,
|
||||
values.email,
|
||||
paymentResource,
|
||||
initConfig,
|
||||
redirectUrl
|
||||
);
|
||||
} catch (e) {
|
||||
switch (e.code) {
|
||||
case LogicErrorCode.invalidInvoiceStatus:
|
||||
@ -37,7 +58,5 @@ export function* makePayment(
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (withPolling) {
|
||||
yield call(pollInvoiceEvents, capiEndpoint, invoiceAccessToken, id);
|
||||
}
|
||||
yield call(pollInvoiceEvents, capiEndpoint, invoiceAccessToken, id);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ const createPaymentResource = (endpoint: string, formValues: MobileCommerceFormV
|
||||
|
||||
export function* payWithMobileCommerce(c: Config, m: ModelState, a: AmountInfoState, v: MobileCommerceFormValues) {
|
||||
const fn = createPaymentResource(c.appConfig.capiEndpoint, v);
|
||||
yield call(makePayment, c, m, v, a, fn, false);
|
||||
yield call(makePayment, c, m, v, a, fn);
|
||||
yield put({
|
||||
type: TypeKeys.SET_MODAL_STATE,
|
||||
payload: new ModalForms([new MobileCommerceReceiptFormInfo()], true)
|
||||
|
@ -14,5 +14,5 @@ export function* payWithPaymentTerminal(
|
||||
v: PaymentTerminalFormValues
|
||||
): Iterator<CallEffect> {
|
||||
const fn = createPaymentResource(c.appConfig.capiEndpoint, v.provider, v.metadata);
|
||||
yield call(makePayment, c, m, v, a, fn);
|
||||
yield call(makePayment, c, m, v, a, fn, true);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
import { Transaction } from 'checkout/backend/model';
|
||||
import { listen } from 'cross-origin-communicator';
|
||||
import { detectLocale } from '../../../../../locale/detect-locale';
|
||||
import { serialize } from '../../../../../initializer/popup-initializer';
|
||||
import { serializeUrlParams } from '../../../../../serialize-url-params';
|
||||
|
||||
export async function getResultData(transaction: Transaction, serviceId: string, locale: string): Promise<ResultData> {
|
||||
const connectTransport = await listen(communicatorInstanceName, 5000);
|
||||
@ -20,7 +20,7 @@ export async function getResultData(transaction: Transaction, serviceId: string,
|
||||
href: transaction.href,
|
||||
serviceId,
|
||||
callbackURL: URL,
|
||||
cancelURL: `${URL}?${serialize({ type: Type.ERROR })}`,
|
||||
cancelURL: `${URL}?${serializeUrlParams({ type: Type.ERROR })}`,
|
||||
countryCode: detectLocale(locale),
|
||||
publicKeyMod: transaction.encInfo.mod,
|
||||
publicKeyExp: transaction.encInfo.exp,
|
||||
|
@ -3,32 +3,11 @@ import { initialize } from 'cross-origin-communicator';
|
||||
import { Initializer } from './initializer';
|
||||
import { CommunicatorEvents, communicatorInstanceName } from '../communicator-constants';
|
||||
import { OpenConfig } from '../app/config';
|
||||
|
||||
export const serialize = (params: { [name: string]: any }): string => {
|
||||
const urlParams: string[] = [];
|
||||
for (const prop in params) {
|
||||
if (params.hasOwnProperty(prop)) {
|
||||
let value = params[prop];
|
||||
if (typeof value === 'function' || value === undefined || value === null) {
|
||||
continue;
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
try {
|
||||
value = JSON.stringify(value);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
urlParams.push(`${prop}=${encodeURIComponent(value)}`);
|
||||
}
|
||||
}
|
||||
return urlParams.join('&');
|
||||
};
|
||||
import { serializeUrlParams } from '../serialize-url-params';
|
||||
|
||||
export class PopupInitializer extends Initializer {
|
||||
open(openConfig: OpenConfig = {}) {
|
||||
const url = `${this.origin}/v1/checkout.html?${serialize({ ...this.config, ...openConfig })}`;
|
||||
const url = `${this.origin}/v1/checkout.html?${serializeUrlParams({ ...this.config, ...openConfig })}`;
|
||||
const target = window.open(url);
|
||||
initialize(target, this.origin, communicatorInstanceName).then((transport) => {
|
||||
this.opened();
|
||||
|
21
src/serialize-url-params.ts
Normal file
21
src/serialize-url-params.ts
Normal file
@ -0,0 +1,21 @@
|
||||
export const serializeUrlParams = (params: { [name: string]: any }): string => {
|
||||
const urlParams: string[] = [];
|
||||
for (const prop in params) {
|
||||
if (params.hasOwnProperty(prop)) {
|
||||
let value = params[prop];
|
||||
if (typeof value === 'function' || value === undefined || value === null) {
|
||||
continue;
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
try {
|
||||
value = JSON.stringify(value);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
urlParams.push(`${prop}=${encodeURIComponent(value)}`);
|
||||
}
|
||||
}
|
||||
return urlParams.join('&');
|
||||
};
|
Loading…
Reference in New Issue
Block a user