Skip to content

Commit

Permalink
feat(wabe-stripe): add getTotalRevenue
Browse files Browse the repository at this point in the history
  • Loading branch information
coratgerl committed Sep 11, 2024
1 parent 43cfd46 commit 3481bf4
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 12 deletions.
2 changes: 1 addition & 1 deletion packages/wabe-stripe/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wabe-stripe",
"version": "0.5.0",
"version": "0.5.1",
"description": "Stripe payment adapter for Wabe",
"homepage": "https://wabe.dev",
"author": {
Expand Down
89 changes: 83 additions & 6 deletions packages/wabe-stripe/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import { StripeAdapter } from '.'
import Stripe from 'stripe'
import { Currency, PaymentMode } from 'wabe'

const mockListCustomers = mock(() => {})
const mockCreateCustomer = mock(() => {})
const mockCreatePayment = mock(() => {})
const mockListSubscriptions = mock(() => {})
const mockCancelSubscription = mock(() => {})
const mockGetInvoices = mock(() => {})
const mockListCustomers = mock(() => { })
const mockCreateCustomer = mock(() => { })
const mockCreatePayment = mock(() => { })
const mockListSubscriptions = mock(() => { })
const mockCancelSubscription = mock(() => { })
const mockGetInvoices = mock(() => { })
const mockListTransactions = mock(() => { })

spyOn(Stripe.prototype, 'customers').mockReturnValue({
create: mockCreateCustomer,
Expand All @@ -30,6 +31,10 @@ spyOn(Stripe.prototype, 'invoices').mockReturnValue({
list: mockGetInvoices,
} as never)

spyOn(Stripe.prototype, 'balanceTransactions').mockReturnValue({
list: mockListTransactions,
} as never)

describe('wabe-stripe', () => {
beforeEach(() => {
mockListCustomers.mockClear()
Expand All @@ -38,6 +43,78 @@ describe('wabe-stripe', () => {
mockListSubscriptions.mockClear()
mockCancelSubscription.mockClear()
mockGetInvoices.mockClear()
mockListTransactions.mockClear()
})

it("should get the total gross revenue", async () => {
const adapter = new StripeAdapter('API_KEY')

mockListTransactions.mockResolvedValue({
data: [
{
id: 'txn_123',
amount: 100,
},
{
id: 'txn_124',
amount: 200,
},
{
id: 'txn_125',
amount: 300,
},
],
has_more: false,
} as never)

await adapter.getTotalRevenue({
charge: 'gross'
})

expect(mockListTransactions).toHaveBeenCalledTimes(1)
expect(mockListTransactions).toHaveBeenCalledWith({
limit: 100,
type: 'charge',
created: {
gte: undefined,
lt: undefined,
}
})
})

it("should get the total net revenue", async () => {
const adapter = new StripeAdapter('API_KEY')

mockListTransactions.mockResolvedValue({
data: [
{
id: 'txn_123',
amount: 100,
},
{
id: 'txn_124',
amount: 200,
},
{
id: 'txn_125',
amount: 300,
},
],
has_more: false,
} as never)

await adapter.getTotalRevenue({
charge: 'net'
})

expect(mockListTransactions).toHaveBeenCalledTimes(1)
expect(mockListTransactions).toHaveBeenCalledWith({
limit: 100,
created: {
gte: undefined,
lt: undefined,
}
})
})

it('should create a customer', async () => {
Expand Down
41 changes: 36 additions & 5 deletions packages/wabe-stripe/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import type {
CreatePaymentOptions,
Currency,
GetInvoicesOptions,
GetTotalRevenueOptions,
Invoice,
PaymentAdapter,
} from 'wabe'

export class StripeAdapter {

export class StripeAdapter implements PaymentAdapter {
private stripe: Stripe

constructor(apiKey: string) {
Expand Down Expand Up @@ -43,6 +46,8 @@ export class StripeAdapter {
payment_method: paymentMethod,
})

if (!customer.email) throw new Error('Error creating Stripe customer')

return customer.email
}

Expand Down Expand Up @@ -74,10 +79,10 @@ export class StripeAdapter {
unit_amount: unitAmount,
...(paymentMode === 'subscription'
? {
recurring: {
interval: recurringInterval || 'month',
},
}
recurring: {
interval: recurringInterval || 'month',
},
}
: {}),
},
quantity,
Expand Down Expand Up @@ -150,4 +155,30 @@ export class StripeAdapter {

return formatInvoices
}

async getTotalRevenue({ startRangeTimestamp, endRangeTimestamp, charge }: GetTotalRevenueOptions) {
const recursiveToGetGrossRevenue = async (totalRevenue = 0, idToStart?: string): Promise<number> => {
const transactions = await this.stripe.balanceTransactions.list({
limit: 100,
starting_after: idToStart,
created: {
gte: startRangeTimestamp,
lt: endRangeTimestamp
},
type: charge === 'net' ? undefined : 'charge'
})

const newTotalRevenue = transactions.data.reduce((acc, transaction) => {
return acc + transaction.amount
}, totalRevenue)

if (!transactions.has_more) return newTotalRevenue / 100

const lastElement = transactions.data[transactions.data.length - 1]

return recursiveToGetGrossRevenue(newTotalRevenue, lastElement.id)
}

return recursiveToGetGrossRevenue()
}
}
5 changes: 5 additions & 0 deletions packages/wabe/src/payment/PaymentController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
GetInvoicesOptions,
PaymentAdapter,
PaymentConfig,
GetTotalRevenueOptions,
} from './interface'

export class PaymentController implements PaymentAdapter {
Expand Down Expand Up @@ -37,4 +38,8 @@ export class PaymentController implements PaymentAdapter {
async getInvoices(options: GetInvoicesOptions) {
return this.adapter.getInvoices(options)
}

async getTotalRevenue(options: GetTotalRevenueOptions) {
return this.adapter.getTotalRevenue(options)
}
}
12 changes: 12 additions & 0 deletions packages/wabe/src/payment/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ export type GetInvoicesOptions = {
email: string
}

export type GetTotalRevenueOptions = {
startRangeTimestamp?: number
endRangeTimestamp?: number
charge: 'net' | 'gross'
}

export interface PaymentAdapter {
/**
* Create a customer
Expand All @@ -104,4 +110,10 @@ export interface PaymentAdapter {
* @returns The invoices of a customer
*/
getInvoices: (options: GetInvoicesOptions) => Promise<Invoice[]>
/**
* Get total revenue
* @param options OPTIONAL: The start and end range timestamps to get the total revenue
* @returns The total amount
*/
getTotalRevenue: (options: GetTotalRevenueOptions) => Promise<number>
}

0 comments on commit 3481bf4

Please sign in to comment.