mirror of
https://github.com/valitydev/checkout.git
synced 2024-11-06 02:25:18 +00:00
OPS-481: Invoice randomize amount (#313)
This commit is contained in:
parent
43a667f6a5
commit
0adbe879d6
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "إكمال الدفع",
|
||||
"form.p2p.complete.loading": "يرجى الانتظار",
|
||||
"form.p2p.destination.amount": "المبلغ:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "لقد قمنا بتغيير مبلغ التحويل. يساعد ذلك في زيادة احتمال نجاح الدفع.",
|
||||
"form.p2p.alert.li": ["حول المبلغ الدقيق", "قم بالتحويل كامل المبلغ في تحويلة واحدة"],
|
||||
"form.p2p.alert.p": "وإلا، لن يتم اعتماد الدفع.",
|
||||
"form.p2p.gateway.selector.heading": "اختر طريقة أو بنك",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "Köçürmə tamamlandı",
|
||||
"form.p2p.complete.loading": "Lütfən, gözləyin",
|
||||
"form.p2p.destination.amount": "Köçürmə məbləği:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "Biz köçürmə məbləğini dəyişdik. Bu, ödənişin uğurlu olma ehtimalını artırır.",
|
||||
"form.p2p.alert.li": ["Ərizədə göstərilən dəqiq məbləği köçürün", "Bütün məbləği bir köçürmədə ödəyin"],
|
||||
"form.p2p.alert.p": "Əks halda ödəniş hesaba alınmayacaq.",
|
||||
"form.p2p.gateway.selector.heading": "Bir metod və ya bank seçin",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "ট্রান্সফার সম্পন্ন",
|
||||
"form.p2p.complete.loading": "অনুগ্রহ করে অপেক্ষা করুন",
|
||||
"form.p2p.destination.amount": "পরিমাণ:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "আমরা স্থানান্তরের পরিমাণ পরিবর্তন করেছি। এটি সফল পেমেন্টের সম্ভাবনা বাড়াতে সাহায্য করে।",
|
||||
"form.p2p.alert.li": ["অর্ডারে উল্লিখিত সঠিক পরিমাণ ট্রান্সফার করুন।", "পুরো পরিমাণ একবারে পরিশোধ করুন।"],
|
||||
"form.p2p.alert.p": "অন্যথায়, পেমেন্ট গৃহীত হবে না।",
|
||||
"form.p2p.gateway.selector.heading": "একটি পদ্ধতি বা ব্যাংক চয়ন করুন",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "Complete payment",
|
||||
"form.p2p.complete.loading": "Please, wait",
|
||||
"form.p2p.destination.amount": "Amount:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "We have adjusted the transfer amount. This helps increase the chance of a successful payment.",
|
||||
"form.p2p.alert.li": ["Transfer the exact amount", "Transfer the entire amount in one transaction"],
|
||||
"form.p2p.alert.p": "Otherwise, the payment will not be credited.",
|
||||
"form.p2p.gateway.selector.heading": "Choose a method or bank",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "支払い完了",
|
||||
"form.p2p.complete.loading": "読み込み中...",
|
||||
"form.p2p.destination.amount": "金額:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "送金額を変更しました。これにより、支払いが成功する可能性が高まります。",
|
||||
"form.p2p.alert.li": ["正確な金額を振り込んでください", "全額を一回の取引で振り込んでください"],
|
||||
"form.p2p.alert.p": "そうしない場合、支払いは認められません。",
|
||||
"form.p2p.gateway.selector.heading": "方法または銀行を選択してください",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "이체 완료",
|
||||
"form.p2p.complete.loading": "기다려 주십시오",
|
||||
"form.p2p.destination.amount": "금액:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "송금 금액을 조정했습니다. 이는 성공적인 결제 가능성을 높이는 데 도움이 됩니다.",
|
||||
"form.p2p.alert.li": ["요청한 정확한 금액을 이체하십시오.", "전체 금액을 한 번에 이체하십시오."],
|
||||
"form.p2p.alert.p": "그렇지 않으면 결제가 인정되지 않습니다.",
|
||||
"form.p2p.gateway.selector.heading": "방법 또는 은행 선택",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "Transferência concluída",
|
||||
"form.p2p.complete.loading": "Por favor, aguarde",
|
||||
"form.p2p.destination.amount": "Quantia:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "Alteramos o valor da transferência. Isso ajuda a aumentar a probabilidade de um pagamento bem-sucedido.",
|
||||
"form.p2p.alert.li": [
|
||||
"Transfira a quantia exata especificada no pedido.",
|
||||
"Pague a quantia total em uma única transferência."
|
||||
|
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "Перевод выполнен",
|
||||
"form.p2p.complete.loading": "Пожалуйста, подождите",
|
||||
"form.p2p.destination.amount": "Сумма:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "Мы изменили сумму перевода. Это помогает повысить вероятность успешного платежа.",
|
||||
"form.p2p.alert.li": ["Переводите точную сумму, указанную в заявке.", "Оплачивайте всю сумму одним переводом."],
|
||||
"form.p2p.alert.p": "В противном случае платеж не будет зачислен.",
|
||||
"form.p2p.gateway.selector.heading": "Выберите метод или банк",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"form.p2p.complete.button": "Transfer tamamlandı",
|
||||
"form.p2p.complete.loading": "Lütfen bekleyin",
|
||||
"form.p2p.destination.amount": "Miktar:",
|
||||
"form.p2p.destination.randomizeAmountDescription": "Transfer tutarını değiştirdik. Bu, başarılı bir ödeme olasılığını artırır.",
|
||||
"form.p2p.alert.li": ["Talep edilen kesin miktarı transfer edin.", "Tüm miktarı tek bir transferde ödeyin."],
|
||||
"form.p2p.alert.p": "Aksi takdirde ödeme alınmayacaktır.",
|
||||
"form.p2p.gateway.selector.heading": "Bir yöntem veya banka seçin",
|
||||
|
@ -1,5 +1,10 @@
|
||||
import { ServiceProviderMetadata } from './serviceProviderMetadata';
|
||||
|
||||
export type InvoiceAmountRandomized = {
|
||||
original: number;
|
||||
randomized: number;
|
||||
};
|
||||
|
||||
export type ClientInfo = {
|
||||
fingerprint: string;
|
||||
ip?: string;
|
||||
@ -275,4 +280,5 @@ export type Invoice = {
|
||||
reason: string;
|
||||
cart: InvoiceLine[];
|
||||
externalID?: string;
|
||||
amountRandomized?: InvoiceAmountRandomized;
|
||||
};
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { isNil } from 'checkout/utils';
|
||||
|
||||
import { InvoiceAndToken } from '../backend/payments';
|
||||
import { InvoiceContext } from '../paymentModel';
|
||||
|
||||
export const invoiceToInvoiceContext = ({
|
||||
invoice: { id, externalID, dueDate, status },
|
||||
invoice: { id, externalID, dueDate, status, amountRandomized },
|
||||
invoiceAccessToken,
|
||||
}: InvoiceAndToken): InvoiceContext => ({
|
||||
type: 'InvoiceContext',
|
||||
@ -13,4 +15,5 @@ export const invoiceToInvoiceContext = ({
|
||||
externalID,
|
||||
dueDate,
|
||||
status,
|
||||
isAmountRandomized: !isNil(amountRandomized),
|
||||
});
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { isNil } from 'checkout/utils';
|
||||
|
||||
import { backendModelToPaymentAmount } from './backendModelToPaymentAmount';
|
||||
import { backendModelToPaymentMethods } from './backendModelToPaymentMethods';
|
||||
import { BackendModel, BackendModelInvoice, BackendModelInvoiceTemplate, getBackendModel } from './getBackendModel';
|
||||
@ -8,13 +10,14 @@ import { InitParams } from '../init';
|
||||
|
||||
const applyInvoice = (
|
||||
{ invoiceParams, type }: Partial<InvoiceContext>,
|
||||
{ invoice: { dueDate, externalID, status } }: BackendModelInvoice,
|
||||
{ invoice: { dueDate, externalID, status, amountRandomized } }: BackendModelInvoice,
|
||||
): InvoiceContext => ({
|
||||
type,
|
||||
invoiceParams,
|
||||
dueDate,
|
||||
externalID,
|
||||
status,
|
||||
isAmountRandomized: !isNil(amountRandomized),
|
||||
});
|
||||
|
||||
const applyInvoiceTemplate = (
|
||||
|
@ -83,6 +83,7 @@ export type InvoiceContext = {
|
||||
readonly dueDate: string;
|
||||
readonly status: InvoiceStatus;
|
||||
readonly externalID?: string;
|
||||
readonly isAmountRandomized: boolean;
|
||||
};
|
||||
|
||||
export type PaymentModelInvoice = InvoiceContext & CommonPaymentModel;
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { VStack } from '@chakra-ui/react';
|
||||
import { VStack, Alert, Text, Divider, AlertIcon } from '@chakra-ui/react';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { Destination } from 'checkout/backend/p2p';
|
||||
import { LocaleContext, PaymentModelContext, ViewModelContext } from 'checkout/contexts';
|
||||
import { LocaleContext, PaymentConditionsContext, PaymentModelContext, ViewModelContext } from 'checkout/contexts';
|
||||
import { InvoiceDetermined, PaymentCondition } from 'checkout/paymentCondition';
|
||||
|
||||
import { DestinationBankAccountInfo } from './DestinationBankAccountInfo';
|
||||
import { InfoItem } from './InfoItem';
|
||||
@ -10,6 +11,9 @@ import { formatCardPan, formatPhoneNumber } from './utils';
|
||||
import { SBPIcon } from '../icons/SBPIcon';
|
||||
import { getGatewayIcon, mapGatewayName } from '../utils';
|
||||
|
||||
const isInvoiceDetermined = (condition: PaymentCondition): condition is InvoiceDetermined =>
|
||||
condition.name === 'invoiceDetermined';
|
||||
|
||||
export type DestinationInfoProps = {
|
||||
destination: Destination;
|
||||
};
|
||||
@ -17,16 +21,29 @@ export type DestinationInfoProps = {
|
||||
export function DestinationInfo({ destination }: DestinationInfoProps) {
|
||||
const { l } = useContext(LocaleContext);
|
||||
const { viewAmount } = useContext(ViewModelContext);
|
||||
const { paymentModel } = useContext(PaymentModelContext);
|
||||
const { conditions } = useContext(PaymentConditionsContext);
|
||||
|
||||
const {
|
||||
paymentModel: {
|
||||
paymentAmount: { currency },
|
||||
},
|
||||
} = useContext(PaymentModelContext);
|
||||
invoiceContext: { isAmountRandomized },
|
||||
} = conditions.find<InvoiceDetermined>(isInvoiceDetermined);
|
||||
|
||||
const {
|
||||
paymentAmount: { currency },
|
||||
} = paymentModel;
|
||||
|
||||
return (
|
||||
<VStack align="stretch">
|
||||
<InfoItem label={l['form.p2p.destination.amount']} value={viewAmount} />
|
||||
<VStack align="stretch">
|
||||
{isAmountRandomized && (
|
||||
<Alert borderRadius="xl" p={3} status="warning">
|
||||
<AlertIcon />
|
||||
<Text fontSize="sm">{l['form.p2p.destination.randomizeAmountDescription']}</Text>
|
||||
</Alert>
|
||||
)}
|
||||
<InfoItem isDivider={false} label={l['form.p2p.destination.amount']} value={viewAmount} />
|
||||
<Divider />
|
||||
</VStack>
|
||||
{destination.destinationType === 'BankCard' && (
|
||||
<InfoItem
|
||||
formatter={formatCardPan}
|
||||
|
@ -1,13 +1,15 @@
|
||||
import { VStack, Text, Flex, Spacer, Divider, useClipboard, useToast, IconButton, createIcon } from '@chakra-ui/react';
|
||||
import { ReactElement, cloneElement, useContext, useEffect, useState } from 'react';
|
||||
import { ReactElement, cloneElement, useContext, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { LocaleContext } from 'checkout/contexts';
|
||||
import { isNil } from 'checkout/utils';
|
||||
|
||||
export type InfoItemProps = {
|
||||
label: string;
|
||||
value: string;
|
||||
icon?: ReactElement;
|
||||
isCopyable?: boolean;
|
||||
isDivider?: boolean;
|
||||
formatter?: (value: string) => Promise<string>;
|
||||
};
|
||||
|
||||
@ -19,12 +21,19 @@ export const CopyIcon = createIcon({
|
||||
),
|
||||
});
|
||||
|
||||
export function InfoItem({ label, value, isCopyable, formatter, icon }: InfoItemProps) {
|
||||
export function InfoItem({ label, value, isCopyable, formatter, icon, isDivider }: InfoItemProps) {
|
||||
const { l } = useContext(LocaleContext);
|
||||
const { onCopy, hasCopied } = useClipboard(value);
|
||||
const [displayValue, setDisplayValue] = useState(value);
|
||||
const toast = useToast();
|
||||
|
||||
const isDividerVisible = useMemo(() => {
|
||||
if (isNil(isDivider)) {
|
||||
return true;
|
||||
}
|
||||
return isDivider;
|
||||
}, [isDivider]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!formatter) return;
|
||||
formatter(value).then(setDisplayValue);
|
||||
@ -63,7 +72,7 @@ export function InfoItem({ label, value, isCopyable, formatter, icon }: InfoItem
|
||||
{isCopyable && <IconButton aria-label="Copy" icon={<CopyIcon />} size="xs" onClick={onCopy} />}
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Divider />
|
||||
{isDividerVisible && <Divider />}
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user