-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: list transactions and show payment method
- Loading branch information
1 parent
a7e8157
commit b053923
Showing
8 changed files
with
253 additions
and
91 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { patch, get } from './cleeng.service'; | ||
|
||
import { addQueryParams } from '#src/utils/formatting'; | ||
import type { GetPaymentDetails, GetSubscriptions, GetTransactions, UpdateSubscription } from '#types/subscription'; | ||
|
||
export async function getActiveSubscription({ sandbox, customerId, jwt }: { sandbox: boolean; customerId: string; jwt: string }) { | ||
const response = await getSubscriptions({ customerId }, sandbox, jwt); | ||
|
||
if (response.errors.length > 0) return null; | ||
|
||
return response.responseData.items.find((item) => item.status === 'active' || item.status === 'cancelled') || null; | ||
} | ||
|
||
export async function getAllTransactions({ sandbox, customerId, jwt }: { sandbox: boolean; customerId: string; jwt: string }) { | ||
const response = await getTransactions({ customerId }, sandbox, jwt); | ||
|
||
if (response.errors.length > 0) return null; | ||
|
||
return response.responseData.items; | ||
} | ||
|
||
export async function getActivePayment({ sandbox, customerId, jwt }: { sandbox: boolean; customerId: string; jwt: string }) { | ||
const response = await getPaymentDetails({ customerId }, sandbox, jwt); | ||
|
||
if (response.errors.length > 0) return null; | ||
|
||
return response.responseData.paymentDetails.find((paymentDetails) => paymentDetails.active) || null; | ||
} | ||
|
||
export const getSubscriptions: GetSubscriptions = async (payload, sandbox, jwt) => { | ||
return get(sandbox, `/customers/${payload.customerId}/subscriptions`, jwt); | ||
}; | ||
|
||
export const updateSubscription: UpdateSubscription = async (payload, sandbox, jwt) => { | ||
return patch(sandbox, `/customers/${payload.customerId}/subscriptions`, JSON.stringify(payload), jwt); | ||
}; | ||
|
||
export const getPaymentDetails: GetPaymentDetails = async (payload, sandbox, jwt) => { | ||
return get(sandbox, `/customers/${payload.customerId}/payment_details`, jwt); | ||
}; | ||
|
||
export const getTransactions: GetTransactions = async ({ customerId, limit, offset }, sandbox, jwt) => { | ||
return get(sandbox, addQueryParams(`/customers/${customerId}/transactions`, { limit, offset }), jwt); | ||
}; |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import InPlayer, { Card, SubscriptionDetails as InplayerSubscription } from '@inplayer-org/inplayer.js'; | ||
|
||
import type { PaymentDetail, Subscription, Transaction } from '#types/subscription'; | ||
import type { Config } from '#types/Config'; | ||
import type { InPlayerPurchaseDetails } from '#types/inplayer'; | ||
|
||
interface SubscriptionDetails extends InplayerSubscription { | ||
item_id?: number; | ||
item_title?: string; | ||
subscription_id?: string; | ||
subscription_price?: number; | ||
action_type?: 'recurrent' | 'canceled' | 'free-trial' | 'ended' | 'incomplete_expired'; | ||
next_rebill_date?: number; | ||
charged_amount?: number; | ||
payment_method_name?: string; | ||
access_type?: { | ||
period: string; | ||
}; | ||
} | ||
|
||
export async function getActiveSubscription({ config }: { config: Config }) { | ||
try { | ||
const assetId = config.integrations.inplayer?.assetId || 0; | ||
const { data: hasAccess } = await InPlayer.Asset.checkAccessForAsset(assetId); | ||
|
||
if (hasAccess) { | ||
const { data } = await InPlayer.Subscription.getSubscriptions(); | ||
const activeSubscription = data.collection.find((subscription: SubscriptionDetails) => subscription.item_id === assetId); | ||
if (activeSubscription) { | ||
return processActiveSubscription(activeSubscription); | ||
} | ||
} | ||
return null; | ||
} catch { | ||
throw new Error('Unable to fetch customer subscriptions.'); | ||
} | ||
} | ||
|
||
export async function getAllTransactions() { | ||
try { | ||
const { data } = await InPlayer.Payment.getPurchaseHistory('active', 0, 30); | ||
// @ts-ignore | ||
// TODO fix PurchaseHistoryCollection type in InPlayer SDK | ||
return data?.collection?.map((transaction: InPlayerPurchaseDetails) => processTransaction(transaction)); | ||
} catch { | ||
throw new Error('Failed to get transactions'); | ||
} | ||
} | ||
|
||
export async function getActivePayment() { | ||
try { | ||
const { data } = await InPlayer.Payment.getDefaultCreditCard(); | ||
const cards: PaymentDetail[] = []; | ||
for (const currency in data?.cards) { | ||
// @ts-ignore | ||
// TODO fix Card type in InPlayer SDK | ||
cards.push(processCardDetails(data.cards?.[currency])); | ||
} | ||
|
||
return cards.find((paymentDetails) => paymentDetails.active) || null; | ||
} catch { | ||
throw new Error('Failed to get payment details'); | ||
} | ||
} | ||
|
||
export const getSubscriptions = async () => { | ||
return { | ||
errors: [], | ||
responseData: { items: [] }, | ||
}; | ||
}; | ||
|
||
const processCardDetails = (card: Card & { card_type: string; account_id: number }): PaymentDetail => { | ||
const { number, exp_month, exp_year, card_name, card_type, account_id } = card; | ||
const zeroFillExpMonth = `0${exp_month}`.substring(-2); | ||
return { | ||
customerId: account_id.toString(), | ||
paymentMethodSpecificParams: { | ||
holderName: card_name, | ||
variant: card_type, | ||
lastCardFourDigits: number, | ||
cardExpirationDate: `${zeroFillExpMonth}/${exp_year}`, | ||
}, | ||
active: true, | ||
} as PaymentDetail; | ||
}; | ||
|
||
// TODO: fix PurchaseDetails type in InPlayer SDK | ||
const processTransaction = (transaction: InPlayerPurchaseDetails): Transaction => { | ||
return { | ||
transactionId: transaction.parent_resource_id, | ||
transactionDate: transaction.created_at, | ||
offerId: transaction.purchased_access_fee_id?.toString(), | ||
offerType: transaction.type || '', | ||
offerTitle: transaction?.purchased_access_fee_description || '', | ||
offerPeriod: '', | ||
transactionPriceExclTax: transaction.purchased_amount?.toString(), | ||
transactionCurrency: transaction.purchased_currency, | ||
discountedOfferPrice: transaction.purchased_amount?.toString(), | ||
offerCurrency: transaction.purchased_currency, | ||
offerPriceExclTax: transaction.purchased_amount?.toString(), | ||
applicableTax: '0', | ||
transactionPriceInclTax: transaction.purchased_amount?.toString(), | ||
customerId: transaction.customer_id?.toString(), | ||
customerEmail: transaction.consumer_email, | ||
customerLocale: '', | ||
customerCountry: 'en', | ||
customerIpCountry: '', | ||
customerCurrency: '', | ||
paymentMethod: transaction.payment_method, | ||
}; | ||
}; | ||
|
||
const processActiveSubscription = (subscription: SubscriptionDetails) => { | ||
let status = ''; | ||
switch (subscription.action_type) { | ||
case 'free-trial' || 'recurrent': | ||
status = 'active'; | ||
break; | ||
case 'canceled': | ||
status = 'cancelled'; | ||
break; | ||
case 'incomplete_expired' || 'ended': | ||
status = 'expired'; | ||
break; | ||
default: | ||
status = 'terminated'; | ||
} | ||
|
||
return { | ||
subscriptionId: subscription.subscription_id, | ||
offerId: subscription.item_id?.toString(), | ||
status, | ||
expiresAt: subscription.next_rebill_date, | ||
nextPaymentAt: subscription.next_rebill_date, | ||
nextPaymentPrice: subscription.subscription_price, | ||
nextPaymentCurrency: subscription.currency, | ||
paymentGateway: 'stripe', | ||
paymentMethod: subscription.payment_method_name, | ||
offerTitle: subscription.item_title, | ||
period: subscription.access_type?.period, | ||
totalPrice: subscription.charged_amount, | ||
} as Subscription; | ||
}; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.