diff --git a/packages/nodes-base/nodes/Paddle/CouponDescription.ts b/packages/nodes-base/nodes/Paddle/CouponDescription.ts index 063ae2eda0..553a0c0ffd 100644 --- a/packages/nodes-base/nodes/Paddle/CouponDescription.ts +++ b/packages/nodes-base/nodes/Paddle/CouponDescription.ts @@ -37,7 +37,6 @@ export const couponOperations = [ ] as INodeProperties[]; export const couponFields = [ - /* -------------------------------------------------------------------------- */ /* coupon:create */ /* -------------------------------------------------------------------------- */ @@ -55,7 +54,7 @@ export const couponFields = [ ] }, }, - default: '', + default: 'checkout', description: 'Either product (valid for specified products or subscription plans) or checkout (valid for any checkout).', options: [ { @@ -277,6 +276,26 @@ export const couponFields = [ ], }, /* -------------------------------------------------------------------------- */ +/* coupon:getAll */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Product ID', + name: 'productId', + type: 'number', + displayOptions: { + show: { + resource: [ + 'coupon', + ], + operation: [ + `getAll` + ] + }, + }, + default: '', + description: 'The specific product/subscription ID.', + }, +/* -------------------------------------------------------------------------- */ /* coupon:update */ /* -------------------------------------------------------------------------- */ { @@ -391,7 +410,6 @@ export const couponFields = [ }, ], }, - { displayName: 'Discount Amount', name: 'discountAmount', diff --git a/packages/nodes-base/nodes/Paddle/GenericFunctions.ts b/packages/nodes-base/nodes/Paddle/GenericFunctions.ts index 62f054414e..c56498935a 100644 --- a/packages/nodes-base/nodes/Paddle/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Paddle/GenericFunctions.ts @@ -16,26 +16,24 @@ import { export async function paddleApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, endpoint: string, method: string, body: any = {}, query?: IDataObject, uri?: string): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('paddleApi'); - const options = { + if (credentials === undefined) { + throw new Error('Could not retrieve credentials!'); + } + + const options : OptionsWithUri = { method, - qs: query || {}, - uri: uri || `${env}/v1${endpoint}`, + uri: `https://vendors.paddle.com/api${endpoint}` , body, json: true }; + body.vendor_id = credentials.vendorId; + body.vendor_auth_code = credentials.vendorAuthCode; + try { return await this.helpers.request!(options); } catch (error) { - - if (error.response.body) { - let errorMessage = error.response.body.message; - if (error.response.body.details) { - errorMessage += ` - Details: ${JSON.stringify(error.response.body.details)}`; - } - throw new Error(errorMessage); - } - - throw error; + console.log(error); + throw new Error(error); } } diff --git a/packages/nodes-base/nodes/Paddle/Paddle.node.ts b/packages/nodes-base/nodes/Paddle/Paddle.node.ts index b40102dec0..0a781e9bb4 100644 --- a/packages/nodes-base/nodes/Paddle/Paddle.node.ts +++ b/packages/nodes-base/nodes/Paddle/Paddle.node.ts @@ -1,15 +1,21 @@ -import { - IExecuteFunctions, -} from 'n8n-core'; - +import { IExecuteFunctions } from 'n8n-core'; import { IDataObject, - ILoadOptionsFunctions, + INodeExecutionData, - INodePropertyOptions, + INodeType, - INodeTypeDescription, + INodeTypeDescription } from 'n8n-workflow'; +import { couponFields, couponOperations } from './CouponDescription'; +import { paddleApiRequest } from './GenericFunctions'; +import { paymentFields, paymentOperations } from './PaymentDescription'; +import { planFields, planOperations } from './PlanDescription'; +import { productFields, productOperations } from './ProductDescription'; +import { userFields, userOperations } from './UserDescription'; + +import moment = require('moment'); +import { response } from 'express'; export class Paddle implements INodeType { description: INodeTypeDescription = { @@ -41,7 +47,6 @@ export class Paddle implements INodeType { { name: 'Coupon', value: 'coupon', - }, { name: 'Payments', @@ -68,6 +73,22 @@ export class Paddle implements INodeType { description: 'Resource to consume.', }, + // COUPON + couponFields, + couponOperations, + // PAYMENT + paymentFields, + paymentOperations, + // PLAN + planFields, + planOperations, + // PRODUCT + productFields, + productOperations, + // USER + userFields, + userOperations + ], }; @@ -76,10 +97,197 @@ export class Paddle implements INodeType { const returnData: IDataObject[] = []; const length = items.length as unknown as number; let responseData; - const qs: IDataObject = {}; + const body: IDataObject = {}; const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; for (let i = 0; i < length; i++) { + if (resource === 'coupon') { + if (operation === 'create') { + const productIds = this.getNodeParameter('productIds', i) as string; + const discountType = this.getNodeParameter('discountType', i) as string; + const discountAmount = this.getNodeParameter('discountAmount', i) as number; + const currency = this.getNodeParameter('currency', i) as string; + + body.product_ids = productIds; + body.discount_type = discountType; + body.discount_amount = discountAmount; + body.currency = currency; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (additionalFields.allowedUses) { + body.allowed_uses = additionalFields.allowedUses as number; + } + if (additionalFields.couponCode) { + body.coupon_code = additionalFields.couponCode as string; + } + if (additionalFields.couponPrefix) { + body.coupon_prefix = additionalFields.couponPrefix as string; + } + if (additionalFields.expires) { + body.expires = moment(additionalFields.expires as Date).format('YYYY/MM/DD') as string; + } + if (additionalFields.group) { + body.group = additionalFields.group as string; + } + if (additionalFields.recurring) { + if (additionalFields.recurring === true) { + body.recurring = 1; + } else { + body.recurring = 0; + } + } + if (additionalFields.numberOfCoupons) { + body.num_coupons = additionalFields.numberOfCoupons as number; + } + if (additionalFields.description) { + body.description = additionalFields.description as string; + } + + const endpoint = '/2.1/product/create_coupon'; + + responseData = paddleApiRequest.call(this, endpoint, 'POST', body); + } + + if (operation === 'getAll') { + const productIds = this.getNodeParameter('productId', i) as string; + const endpoint = '/2.0/product/list_coupons'; + + body.product_ids = productIds as string; + + responseData = paddleApiRequest.call(this, endpoint, 'POST', body); + } + + if (operation === 'update') { + const updateBy = this.getNodeParameter('updateBy', i) as string; + + if (updateBy === 'group') { + body.group = this.getNodeParameter('group', i) as string; + } else { + body.coupon_code = this.getNodeParameter('couponCode', i) as string; + } + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (additionalFields.allowedUses) { + body.allowed_uses = additionalFields.allowedUses as number; + } + if (additionalFields.currency) { + body.currency = additionalFields.currency as string; + } + if (additionalFields.newCouponCode) { + body.new_coupon_code = additionalFields.newCouponCode as string; + } + if (additionalFields.expires) { + body.expires = moment(additionalFields.expires as Date).format('YYYY/MM/DD') as string; + } + if (additionalFields.newGroup) { + body.new_group = additionalFields.newGroup as string; + } + if (additionalFields.recurring) { + if (additionalFields.recurring === true) { + body.recurring = 1; + } else { + body.recurring = 0; + } + } + if (additionalFields.productIds) { + body.product_ids = additionalFields.productIds as number; + } + if (additionalFields.discountAmount) { + body.discount_amount = additionalFields.discountAmount as number; + } + + const endpoint = '/2.1/product/update_coupon'; + + responseData = paddleApiRequest.call(this, endpoint, 'POST', body); + } + } + if (resource === 'payment') { + if (operation === 'getAll') { + const subscriptionId = this.getNodeParameter('subscription', i) as string; + const planId = this.getNodeParameter('planId', i) as string; + + body.subscription_id = subscriptionId; + body.plan_id = planId; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (additionalFields.state) { + body.state = additionalFields.state as string; + } + if (additionalFields.isPaid) { + if (additionalFields.isPaid === true) { + body.is_paid = 0; + } else { + body.is_paid = 1; + } + } + if (additionalFields.from) { + body.from = moment(additionalFields.from as Date).format('YYYY/MM/DD') as string; + } + if (additionalFields.to) { + body.to = moment(additionalFields.to as Date).format('YYYY/MM/DD') as string; + } + if (additionalFields.isOneOffCharge) { + body.is_one_off_charge = additionalFields.isOneOffCharge as boolean; + } + + const endpoint = '/2.0/subscription/payments'; + responseData = paddleApiRequest.call(this, endpoint, 'POST', body); + } + if (operation === 'reschedule') { + const paymentId = this.getNodeParameter('paymentId', i) as number; + const date = this.getNodeParameter('date', i) as Date; + + body.payment_id = paymentId; + body.date = body.to = moment(date as Date).format('YYYY/MM/DD') as string; + + const endpoint = '/2.0/subscription/payments_reschedule'; + + responseData = paddleApiRequest.call(this, endpoint, 'POST', body); + } + } + if (resource === 'plan') { + if (operation === 'getAll') { + const planId = this.getNodeParameter('planId', i) as string; + + body.plan = planId; + + const endpoint = '/2.0/subscription/plans'; + + responseData = paddleApiRequest.call(this, endpoint, 'POST', body); + } + } + if (resource === 'product') { + if (operation === 'getAll') { + const endpoint = '/2.0/product/get_products'; + + responseData = paddleApiRequest.call(this, endpoint, 'POST', body); + } + } + + if (resource === 'user') { + if (operation === 'getAll') { + const subscriptionId = this.getNodeParameter('subscriptionId', i) as string; + const planId = this.getNodeParameter('planId', i) as string; + const limit = this.getNodeParameter('limit', i) as number; + + body.subscription_id = subscriptionId; + body.plan_id = planId; + body.results_per_page = limit; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + + if (additionalFields.state) { + body.state = additionalFields.state as string; + } + + const endpoint = '/2.0/subscription/users'; + + responseData = paddleApiRequest.call(this, endpoint, 'POST', body); + } + } if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); diff --git a/packages/nodes-base/nodes/Paddle/PaddleTrigger.node.ts b/packages/nodes-base/nodes/Paddle/PaddleTrigger.node.ts index a2b5c6e484..f439a5beb6 100644 --- a/packages/nodes-base/nodes/Paddle/PaddleTrigger.node.ts +++ b/packages/nodes-base/nodes/Paddle/PaddleTrigger.node.ts @@ -11,6 +11,7 @@ import { ILoadOptionsFunctions, INodePropertyOptions, } from 'n8n-workflow'; +import { paddleApiRequest } from './GenericFunctions'; export class PaddleTrigger implements INodeType { description: INodeTypeDescription = { @@ -69,7 +70,7 @@ import { } const endpoint = `/notifications/webhooks/${webhookData.webhookId}`; try { - await payPalApiRequest.call(this, endpoint, 'GET'); + await paddleApiRequest.call(this, endpoint, 'GET'); } catch (err) { if (err.response && err.response.name === 'INVALID_RESOURCE_ID') { // Webhook does not exist @@ -93,7 +94,7 @@ import { }; const endpoint = '/notifications/webhooks'; try { - webhook = await payPalApiRequest.call(this, endpoint, 'POST', body); + webhook = await paddleApiRequest.call(this, endpoint, 'POST', body); } catch (e) { throw e; } @@ -111,7 +112,7 @@ import { if (webhookData.webhookId !== undefined) { const endpoint = `/notifications/webhooks/${webhookData.webhookId}`; try { - await payPalApiRequest.call(this, endpoint, 'DELETE', {}); + await paddleApiRequest.call(this, endpoint, 'DELETE', {}); } catch (e) { return false; } @@ -145,7 +146,7 @@ import { webhook_event: bodyData, }; try { - webhook = await payPalApiRequest.call(this, endpoint, 'POST', body); + webhook = await paddleApiRequest.call(this, endpoint, 'POST', body); } catch (e) { throw e; } diff --git a/packages/nodes-base/nodes/Paddle/PaymentDescription.ts b/packages/nodes-base/nodes/Paddle/PaymentDescription.ts index ef4faa55bc..77ff5ca432 100644 --- a/packages/nodes-base/nodes/Paddle/PaymentDescription.ts +++ b/packages/nodes-base/nodes/Paddle/PaymentDescription.ts @@ -32,7 +32,6 @@ export const paymentOperations = [ ] as INodeProperties[]; export const paymentFields = [ - /* -------------------------------------------------------------------------- */ /* payment:getAll */ /* -------------------------------------------------------------------------- */ @@ -72,28 +71,6 @@ export const paymentFields = [ }, description: 'Filter: The product/plan ID (single or comma-separated values).', }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - default: 1, - required: true, - typeOptions: { - minValue: 1, - maxValue: 200 - }, - displayOptions: { - show: { - resource: [ - 'user', - ], - operation: [ - 'getAll', - ], - }, - }, - description: 'Number of subscription records to return per page.', - }, { displayName: 'Additional Fields', name: 'additionalFields',