nestjs-braintree
Advanced tools
Comparing version 0.0.1 to 0.0.2
{ | ||
"name": "nestjs-braintree", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"description": "Nestjs braintree module", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
<p align="center"><img src="https://avatars1.githubusercontent.com/u/41109786?s=200&v=4"/></p> | ||
<p align="center"> | ||
<a href="https://travis-ci.org/nestjs-community/nestjs-braintree"><img src="https://travis-ci.org/nestjs-community/nestjs-braintree.svg?branch=master"/></a> | ||
<a href="https://www.npmjs.com/package/nestjs-braintree"><img src="https://img.shields.io/npm/v/nestjs-braintree.svg"/></a> | ||
<a href="https://github.com/nestjs-community/nestjs-braintree/blob/master/LICENSE"><img src="https://img.shields.io/github/license/nestjs-community/nestjs-braintree.svg"/></a> | ||
@@ -18,3 +19,3 @@ <a href='https://coveralls.io/github/nestjs-community/nestjs-braintree?branch=master'><img src='https://coveralls.io/repos/github/nestjs-community/nestjs-braintree/badge.svg?branch=master' alt='Coverage Status' /></a> | ||
```bash | ||
$ yarn add nestjs-braintree //not currently published | ||
$ yarn add nestjs-braintree | ||
``` | ||
@@ -89,2 +90,51 @@ | ||
## 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 {} | ||
``` | ||
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 | ||
@@ -141,5 +191,7 @@ | ||
async findByBraintreeId(id: string): Promise<Subscription|null> { | ||
return await this.repository.find({ | ||
where: braintreeId: id, | ||
async findByBraintreeId(braintreeId: string): Promise<Subscription|null> { | ||
return await this.subscriptionRepository.find({ | ||
where: { | ||
braintreeId, | ||
}, | ||
}); | ||
@@ -153,3 +205,3 @@ } | ||
@BraintreeSubscriptionCanceled() | ||
async canceled(webhook) { | ||
async canceled(webhook: BraintreeWebhook) { | ||
const subscription = await this.findByBraintreeId(webhook.subscription.id); | ||
@@ -179,34 +231,23 @@ if (!subscription) { | ||
## Transactions | ||
#### 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 | ||
Braintree is also 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: number) { | ||
//Will probably be similar to sale https://developers.braintreepayments.com/guides/transactions/node#settlement | ||
this.braintreeProvider.notImplementedYet(amount); | ||
} | ||
} | ||
```ts | ||
@Module({ | ||
imports: [ | ||
ConfigModule.load('root/to/config/*/**.{ts,js}'), | ||
BraintreeModule.forRoot({ | ||
BraintreeModule.forRootAsync({ | ||
useFactory: async (config: ConfigService) => config.get('braintree'), | ||
inject: [ConfigService], | ||
}), | ||
BraintreeWebhookModule.forRoot({ | ||
root: 'replace-braintree', | ||
handle: 'replace-webhook', | ||
}), | ||
], | ||
providers: [TransactionProvider], | ||
providers: [SubscriptionProvider], | ||
}) | ||
export default class AppModule {} | ||
``` | ||
The above will result in your route for your braintree webhooks being `{your_domain}/replace-braintree/replace-webhook` |
@@ -5,5 +5,5 @@ import * as braintree from 'braintree'; | ||
environment: braintree.Environment.Sandbox, | ||
merchantId: 'merchantId', | ||
publicKey: 'publicKey', | ||
privateKey: 'privateKey', | ||
merchantId: process.env.BRAINTREE_MERCHANT_ID, | ||
publicKey: process.env.BRAINTREE_PUBLIC_KEY, | ||
privateKey: process.env.BRAINTREE_PRIVATE_KEY, | ||
} |
@@ -53,5 +53,5 @@ import { Test, TestingModule } from '@nestjs/testing'; | ||
expect(options.environment).toBe(braintree.Environment.Sandbox); | ||
expect(options.merchantId).toBe('merchantId'); | ||
expect(options.publicKey).toBe('publicKey'); | ||
expect(options.privateKey).toBe('privateKey'); | ||
expect(typeof options.merchantId).toBe('string'); | ||
expect(typeof options.publicKey).toBe('string'); | ||
expect(typeof options.privateKey).toBe('string'); | ||
expect(provider).toBeInstanceOf(BraintreeProvider); | ||
@@ -58,0 +58,0 @@ }); |
import { Test, TestingModule } from '@nestjs/testing'; | ||
import * as path from 'path'; | ||
import { ConfigModule, ConfigService } from 'nestjs-config'; | ||
import { | ||
@@ -36,8 +34,7 @@ BraintreeModule, | ||
imports: [ | ||
ConfigModule.load( | ||
path.resolve(__dirname, '__stubs__', 'config', '*.ts'), | ||
), | ||
BraintreeModule.forRootAsync({ | ||
useFactory: async config => config.get('braintree'), | ||
inject: [ConfigService], | ||
BraintreeModule.forRoot({ | ||
environment: braintree.Environment.Sandbox, | ||
merchantId: 'merchantId', | ||
publicKey: 'publicKey', | ||
privateKey: 'privateKey', | ||
}), | ||
@@ -44,0 +41,0 @@ BraintreeWebhookModule, |
@@ -42,5 +42,7 @@ import { INestApplication } from "@nestjs/common"; | ||
), | ||
BraintreeModule.forRootAsync({ | ||
useFactory: async config => config.get('braintree'), | ||
inject: [ConfigService], | ||
BraintreeModule.forRoot({ | ||
environment: braintree.Environment.Sandbox, | ||
merchantId: 'merchantId', | ||
publicKey: 'publicKey', | ||
privateKey: 'privateKey', | ||
}), | ||
@@ -47,0 +49,0 @@ BraintreeWebhookModule, |
import {Injectable, Inject} from '@nestjs/common'; | ||
import { BraintreeOptions, BraintreeWebhookPayloadInterface, BraintreeWebhookNotificationInterface } from './interfaces'; | ||
import { | ||
BraintreeOptions, | ||
BraintreeWebhookPayloadInterface, | ||
BraintreeWebhookNotificationInterface, | ||
BraintreeTransactionInterface, | ||
BraintreeTransactionResultInterface, | ||
BraintreeSubscriptionInterface, | ||
BraintreeSubscriptionResultInterface, | ||
} from './interfaces'; | ||
import * as braintree from 'braintree'; | ||
@@ -19,5 +27,33 @@ import { BRAINTREE_OPTIONS_PROVIDER } from './braintree.constants'; | ||
//TODO add methods to handle creating a subscription | ||
//TODO add methods to handle transactions | ||
//TODO add methods for refunds | ||
async sale(transaction: BraintreeTransactionInterface): Promise<BraintreeTransactionResultInterface> { | ||
return await this.gateway.transaction.sale(transaction); | ||
} | ||
async refund(transactionId: string, amount?: string, orderId?: string): Promise<BraintreeTransactionResultInterface> { | ||
return await this.gateway.transaction.refund(transactionId, amount, orderId); | ||
} | ||
async find(transactionId: string): Promise<BraintreeTransactionResultInterface> { | ||
return await this.gateway.transaction.find(transactionId); | ||
} | ||
async createSubscription(subscription: BraintreeSubscriptionInterface): Promise<BraintreeSubscriptionResultInterface> { | ||
return await this.gateway.subscription.create(subscription); | ||
} | ||
async cancelSubscription(subscriptionId: string): Promise<BraintreeSubscriptionResultInterface> { | ||
return await this.gateway.subscription.cancel(subscriptionId); | ||
} | ||
async findSubscription(subscriptionId: string): Promise<BraintreeSubscriptionResultInterface> { | ||
return await this.gateway.subscription.find(subscriptionId); | ||
} | ||
async updateSubscription(subscriptionId: string, subscription: BraintreeSubscriptionInterface): Promise<BraintreeSubscriptionResultInterface> { | ||
return await this.gateway.subscription.update(subscriptionId, subscription); | ||
} | ||
// TODO implement confusing looking search plans | ||
// https://developers.braintreepayments.com/reference/request/subscription/search/node#search-results | ||
} |
@@ -1,19 +0,35 @@ | ||
import {Controller, Req, Logger, Post, HttpException} from '@nestjs/common'; | ||
import {Controller, Req, Logger, HttpException, RequestMethod} from '@nestjs/common'; | ||
import BraintreeProvider from './braintree.provider'; | ||
import BraintreeWebhookProvider from './braintree.webhook.provider'; | ||
import { BraintreeWebhookNotificationInterface } from './interfaces'; | ||
import { PATH_METADATA, METHOD_METADATA } from '@nestjs/common/constants'; | ||
//TODO make path configurable | ||
@Controller('braintree') | ||
@Controller() | ||
export default class BraintreeWebhookController { | ||
constructor(private readonly braintree: BraintreeProvider, private readonly webhookProvider: BraintreeWebhookProvider) {} | ||
constructor( | ||
private readonly braintree: BraintreeProvider, | ||
private readonly webhookProvider: BraintreeWebhookProvider, | ||
) {} | ||
@Post('webhook') | ||
public static forRoot(root: string = 'braintree', handle: string = 'webhook') { | ||
Reflect.defineMetadata(PATH_METADATA, root, BraintreeWebhookController); | ||
Reflect.defineMetadata( | ||
METHOD_METADATA, | ||
RequestMethod.POST, | ||
Object.getOwnPropertyDescriptor(BraintreeWebhookController.prototype, 'handle').value, | ||
); | ||
Reflect.defineMetadata( | ||
PATH_METADATA, | ||
handle, | ||
Object.getOwnPropertyDescriptor(BraintreeWebhookController.prototype, 'handle').value, | ||
); | ||
return BraintreeWebhookController; | ||
} | ||
async handle(@Req() request) { | ||
let webhook: BraintreeWebhookNotificationInterface; | ||
try { | ||
webhook = await this.braintree.parseWebhook({ | ||
bt_signature: request.body.bt_signature, | ||
webhook = await this.braintree.parseWebhook({ | ||
bt_signature: request.body.bt_signature, | ||
bt_payload: request.body.bt_payload, | ||
@@ -20,0 +36,0 @@ }); |
@@ -10,3 +10,4 @@ import {Module, OnModuleInit,} from '@nestjs/common'; | ||
import { MetadataScanner } from '@nestjs/core/metadata-scanner'; | ||
import { Injectable } from '@nestjs/common/interfaces'; | ||
import { Injectable, DynamicModule } from '@nestjs/common/interfaces'; | ||
import { BraintreeWebhookOptionsInterface } from './interfaces'; | ||
@@ -16,3 +17,3 @@ @Module({ | ||
providers: [BraintreeWebhookProvider], | ||
controllers: [BraintreeWebhookController], | ||
controllers: [BraintreeWebhookController.forRoot('braintree', 'webhook')], | ||
}) | ||
@@ -59,2 +60,11 @@ export default class BraintreeWebhookModule implements OnModuleInit { | ||
} | ||
public static forRoot(webhookOptions: BraintreeWebhookOptionsInterface): DynamicModule { | ||
return { | ||
module: BraintreeWebhookModule, | ||
imports: [BraintreeModule], | ||
providers: [BraintreeWebhookProvider], | ||
controllers: [BraintreeWebhookController.forRoot(webhookOptions.root, webhookOptions.handle)], | ||
}; | ||
} | ||
} |
@@ -32,3 +32,2 @@ import {Injectable, Provider, Logger, HttpException} from '@nestjs/common'; | ||
async handle(webhook: BraintreeWebhookNotificationInterface): Promise<void> { | ||
if (Object.keys(this.methods).includes(webhook.kind)) { | ||
@@ -35,0 +34,0 @@ this.methods[webhook.kind].forEach(async (methodProto: BraintreeWebhookMethodInterface) => { |
@@ -5,1 +5,3 @@ export * from './braintree.options.interface'; | ||
export * from './braintree.webhook.methods.interface'; | ||
export * from './braintree.webhook.options.interface'; | ||
export * from './braintree.transaction.interface'; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
60169
40
1364
249