Created
August 2, 2021 14:25
-
-
Save jeffdeville/c9aae0e9f8637cd522f325d01192cfd2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async createPayment({ | |
neatAccountId, | |
paymentToken, | |
amount, | |
paymentId, | |
rbit, | |
cardHolder, | |
providerSettings, | |
}: CreditCardPaymentRequest): Promise<WePayPayment> { | |
this.validateRbit(rbit) | |
this.assertValidAccountSettings(providerSettings) | |
this.assertValuesInCents(amount) | |
const token = paymentToken | |
const { address, phone, transactionDetails } = rbit | |
const credit_card = { | |
card_holder: { | |
address: { | |
country: address.country, | |
postal_code: address.postal_code, | |
}, | |
holder_name: cardHolder.holderName, | |
email: cardHolder.email, | |
}, | |
} as CreditCardPaymentMethodForPayments | |
const rbits = [ | |
this.buildAddressRiskBit(address), | |
this.buildPhoneRiskBit(phone), | |
this.buildTransactionDetailsBit(transactionDetails), | |
] | |
const cardType = await this.getPaymentType({ token, rbits, credit_card }) | |
const feeAmount = this.calculateFee(cardType, amount) | |
const paymentsRequest: PaymentsRequest = { | |
account_id: providerSettings?.wepay?.acctId as string, | |
amount, | |
currency: this.switchCurrency(address.country), | |
fee_amount: feeAmount, | |
reference_id: paymentId, | |
payment_method: { | |
token: { id: paymentToken }, | |
credit_card, | |
}, | |
custom_data: { | |
neatAccountId, | |
neatPaymentId: paymentId, | |
neatInvoiceId: transactionDetails.purchase_order_id, | |
}, | |
rbits, | |
} as unknown as PaymentsRequest | |
try { | |
const paymentsApi = new PaymentsApi() | |
const uniqueKey = uuidv4() | |
const request = async () => | |
paymentsApi.createapayment( | |
this.appId, | |
this.appToken, | |
this.apiVersion, | |
uniqueKey, | |
paymentsRequest, | |
) | |
const result = await this.sendRetryableRequest(request) | |
return result.data as unknown as WePayPayment | |
} catch (error) { | |
if (error.isAxiosError) { | |
const { error_message, details } = error.response.data | |
this.mapPaymentError(error_message, details) | |
} | |
throw error | |
} | |
} | |
async sendRetryableRequest<TResult>( | |
request: () => Promise<AxiosResponse<TResult>>, | |
attempt: number = 1, | |
): Promise<AxiosResponse<TResult>> { | |
try { | |
return await request() | |
} catch (error) { | |
if (!this.isRetryable(error) || attempt >= 3) throw error | |
// return await setTimeout(request, { 1: 5000, 2: 10000 }[attempt] as number) | |
await sleep({ 1: 5000, 2: 10000 }[attempt] as number) | |
return await this.sendRetryableRequest(request, attempt + 1) | |
} | |
} | |
isRetryable(error: AxiosError<any>): boolean { | |
if (typeof error === 'undefined') return false | |
if (!error?.isAxiosError) return false | |
if (typeof error.response === 'undefined') return false | |
const status = error?.response?.status | |
if (status >= 500 && status < 600) return true // all 500 errors are retryable | |
if (status == 429) return true // THROTTLE_EXCEEDED.APPLICATION_REQUEST_THROTTLE_EXCEEDED | |
if ( | |
(error.response?.data?.details || []).find( | |
(r: any) => r.reason_code === 'INVALID_PARAMS.CONCURRENT_UNIQUE_KEY_REQUEST_IS_PROCESSING', | |
) | |
) | |
return true | |
return false | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment