Nestjs Braintree
A module for Braintree reoccurring payments and transactions built for the Nestjs framework.
Using the Braintree node SDK .
NOTE! Currently building
Install
$ yarn add nestjs-braintree
Use
Basic use
import { Module } from ' @nestjs/common ' ;
import { BraintreeModule } from ' nestjs-braintree ' ;
import * as braintree from ' braintree ' ;
@ Module ( {
imports : [
BraintreeModule . forRoot ( {
environment : braintree . Environment . Sandbox ,
merchantId : ' ' ,
publicKey : ' ' ,
privateKey : ' ' ,
} ) ,
] ,
} )
export default class AppModule { }
In a subModule
import { Module } from ' @nestjs/common ' ;
import { BraintreeModule } from ' nestjs-braintree ' ;
@ Module ( {
imports : [
BraintreeModule . forFeature ( ) ,
] ,
} )
export default class SubModule { }
Use with nestjs-config
import { Module } from ' @nestjs/common ' ;
import { BraintreeModule } from ' nestjs-braintree ' ;
import { ConfigModule , ConfigService } from ' nestjs-config ' ;
@ Module ( {
imports : [
ConfigModule . load ( ' root/to/config/*/**.{ts,js} ' ) ,
BraintreeModule . forRootAsync ( {
useFactory : async ( config : ConfigService ) => config . get ( ' braintree ' ) ,
inject : [ ConfigService ] ,
} ) ,
] ,
} )
export default class AppModule { }
import * as braintree from ' braintree ' ;
export default {
environment :
process . env . NODE_ENV == ' development '
? braintree . Environment . Sandbox
: braintree . Environment . Live ,
merchantId : process . env . BRAINTREE_MERCHANT_ID ,
publicKey : process . env . BRAINTREE_PUBLIC_KEY ,
privateKey : process . env . BRAINTREE_PRIVATE_KEY ,
} ;
Transactions
Braintree is capable of making one off transactions
import { Module } from ' @nestjs/common ' ;
import { BraintreeModule , InjectBraintreeProvider } from ' nestjs-braintree ' ;
import { ConfigModule , ConfigService } from ' nestjs-config ' ;
class TransactionProvider {
constructor (
@ InjectBraintreeProvider ( )
private readonly braintreeProvider : BraintreeProvider ,
) { }
takePayment ( amount : string , nonce : string ) {
this . braintreeProvider . sale ( {
payment_method_nonce : nonce ,
amount ,
} ) ;
}
}
@ Module ( {
imports : [
ConfigModule . load ( ' root/to/config/*/**.{ts,js} ' ) ,
BraintreeModule . forRoot ( {
useFactory : async ( config : ConfigService ) => config . get ( ' braintree ' ) ,
inject : [ ConfigService ] ,
} ) ,
] ,
providers : [ TransactionProvider ] ,
} )
export default class AppModule { }
Avaliable methods relating to transactions are
Sale
braintreeProvider.sale(transaction: BraintreeTransactionInterface): Promise<BraintreeTransactionResultInterface>
Refund
braintreeProvider.refund(transactionId: string, amount?: string, orderId?: string): Promise<BraintreeTransactionResultInterface>
Find
braintreeProvider.find(transactionId: string): Promise<BraintreeTransactionResultInterface>
The braintree SDK does offer additional methods. I will implement them soon hopefully
Webhooks
When using subscriptions with braintree, braintree will issue webhooks to your
endpoint which you can use the decorators to handle those actions.
import { Module } from ' @nestjs/common ' ;
import {
BraintreeModule ,
BraintreeWebhookModule ,
BraintreeSubscriptionCanceled ,
BraintreeSubscriptionExpired ,
BraintreeWebhookHandler ,
} from ' nestjs-braintree ' ;
import { ConfigModule , ConfigService } from ' nestjs-config ' ;
@ BraintreeWebhookHandler ( )
class SubscriptionProvider {
@ BraintreeSubscriptionCanceled ( )
canceled ( ) {
console . log ( ' subscription canceled ' ) ;
}
@ BraintreeSubscriptionExpired ( )
expired ( ) {
console . log ( ' subscription expired ' ) ;
}
}
@ Module ( {
imports : [
ConfigModule . load ( ' root/to/config/*/**.{ts,js} ' ) ,
BraintreeModule . forRootAsync ( {
useFactory : async ( config : ConfigService ) => config . get ( ' braintree ' ) ,
inject : [ ConfigService ] ,
} ) ,
BraintreeWebhookModule ,
] ,
providers : [ SubscriptionProvider ] ,
} )
export default class AppModule { }
Use Example
The idea of the Braintree Webhook Module is to make implementation of actions a lot easier. For example we can build a provider like this one to cancel canceled subscriptions.
@ BraintreeWebhookHandler ( )
export class SubscriptionProvider {
constructor ( @ InjectRepository ( Subscription ) private readonly subscriptionRepository : Repository < Subscription > ) { }
async findByBraintreeId ( braintreeId : string ) : Promise < Subscription | null > {
return await this . subscriptionRepository . find ( {
where : {
braintreeId ,
} ,
} ) ;
}
async update ( subscription : Subscription ) : Promise < boolean > {
return await this . subscriptionRepository . update ( subscription ) ;
}
@ BraintreeSubscriptionCanceled ( )
async canceled ( webhook : BraintreeWebhook ) {
const subscription = await this . findByBraintreeId ( webhook . subscription . id ) ;
if ( ! subscription ) {
return ;
}
subscription . active = false ;
await this . update ( subscription ) ;
}
}
Available webhooks
Shortname
Braintree webhook name/const/key
NestJS decorator
Subscription Canceled
subscription_canceled
@BraintreeSubscriptionCanceled()
Subscription Expired
subscription_expired
@BraintreeSubscriptionExpired()
Subscription Charged Successfully
subscription_charged_successfully
@BraintreeSubscriptionChargedSuccessfully()
Subscription Charged Unsuccessfully
subscription_charged_unsuccessfully
@BraintreeSubscriptionChargedUnsuccessfully()
Subscription Went Active
subscription_went_active
@BraintreeSubscriptionWentActive()
Subscription Went Past Due
subscription_went_past_due
@BraintreeSubscriptionWentPastDue()
Subscription Trial Ended
subscription_trial_ended
@BraintreeSubscriptionTrialEnded()
You can find out more about the webhooks here .
Custom routing for webhooks
You may want to divert from the default routing of {your_domain}/braintree/webhook
for whatever reason. You can do so using the forRoot
method on the BraintreeWebhookModule
like so
@ Module ( {
imports : [
ConfigModule . load ( ' root/to/config/*/**.{ts,js} ' ) ,
BraintreeModule . forRootAsync ( {
useFactory : async ( config : ConfigService ) => config . get ( ' braintree ' ) ,
inject : [ ConfigService ] ,
} ) ,
BraintreeWebhookModule . forRoot ( {
root : ' replace-braintree ' ,
handle : ' replace-webhook ' ,
} ) ,
] ,
providers : [ SubscriptionProvider ] ,
} )
export default class AppModule { }
The above will result in your route for your braintree webhooks being {your_domain}/replace-braintree/replace-webhook