Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/nestjsx/nestjs-braintree
A module for braintree reoccurring payments and transactions :credit_card:
https://github.com/nestjsx/nestjs-braintree
braintree nestjs node payments subscriptions typescript webhooks
Last synced: about 1 month ago
JSON representation
A module for braintree reoccurring payments and transactions :credit_card:
- Host: GitHub
- URL: https://github.com/nestjsx/nestjs-braintree
- Owner: nestjsx
- License: mit
- Created: 2018-08-30T09:55:15.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2023-01-23T22:25:42.000Z (almost 2 years ago)
- Last Synced: 2024-10-29T22:37:19.452Z (about 1 month ago)
- Topics: braintree, nestjs, node, payments, subscriptions, typescript, webhooks
- Language: TypeScript
- Homepage:
- Size: 278 KB
- Stars: 76
- Watchers: 5
- Forks: 8
- Open Issues: 26
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-nestjs - Nestjs Braintree - 一个用于 webhooks 交易的模块。 (资源 / 集成)
README
Nestjs Braintree
A module for Braintree reoccurring payments and transactions built for the Nestjs framework.
Using the Braintree node SDK.
> NOTE! Currently building
## Install
```bash
$ yarn add nestjs-braintree
```## Use
### Basic use
```typescript
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
```typescript
import { Module } from '@nestjs/common';
import { BraintreeModule } from 'nestjs-braintree';@Module({
imports: [
BraintreeModule.forFeature(),
],
})
export default class SubModule {}
```### Use with nestjs-config
```typescript
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 {}//config/braintree.ts
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
```typescript
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 {}
```Available methods relating to transactions are
#### Sale
`braintreeProvider.sale(transaction: BraintreeTransactionInterface): Promise`#### Refund
`braintreeProvider.refund(transactionId: string, amount?: string, orderId?: string): Promise`#### Find
`braintreeProvider.find(transactionId: string): Promise`> 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.```typescript
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.```ts
@BraintreeWebhookHandler()
export class SubscriptionProvider {
constructor(@InjectRepository(Subscription) private readonly subscriptionRepository: Repository) {}async findByBraintreeId(braintreeId: string): Promise {
return await this.subscriptionRepository.find({
where: {
braintreeId,
},
});
}async update(subscription: Subscription): Promise {
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](https://developers.braintreepayments.com/reference/general/webhooks/overview).
#### 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```ts
@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`