From 4343bec2e0625b6870ccb10cde7ccbfdf003b9b1 Mon Sep 17 00:00:00 2001 From: Rupenieks Date: Tue, 1 Sep 2020 17:00:52 +0200 Subject: [PATCH] Revert "Merge branch 'save-changes-warning' of https://github.com/n8n-io/n8n into save-changes-warning" This reverts commit ebc7e76968668eba345828895ade59f1e9a6d53c, reversing changes made to 18c8c408e28cd29458cbb5e4f7a88e8142b7a935. --- .../nodes/Paddle/CouponDescription.ts | 394 +++++++++++++++--- .../nodes/Paddle/GenericFunctions.ts | 38 +- .../nodes/Paddle/OrderDescription.ts | 6 +- .../nodes-base/nodes/Paddle/Paddle.node.ts | 217 ++++++++-- .../nodes/Paddle/PaddleTrigger.node.ts | 165 -------- .../nodes/Paddle/PaymentDescription.ts | 92 ++-- .../nodes/Paddle/PlanDescription.ts | 49 ++- .../nodes/Paddle/ProductDescription.ts | 41 ++ .../nodes/Paddle/UserDescription.ts | 10 +- 9 files changed, 707 insertions(+), 305 deletions(-) delete mode 100644 packages/nodes-base/nodes/Paddle/PaddleTrigger.node.ts diff --git a/packages/nodes-base/nodes/Paddle/CouponDescription.ts b/packages/nodes-base/nodes/Paddle/CouponDescription.ts index 64e87cf9a..179ec825b 100644 --- a/packages/nodes-base/nodes/Paddle/CouponDescription.ts +++ b/packages/nodes-base/nodes/Paddle/CouponDescription.ts @@ -37,9 +37,9 @@ export const couponOperations = [ ] as INodeProperties[]; export const couponFields = [ -/* -------------------------------------------------------------------------- */ -/* coupon:create */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* coupon:create */ + /* -------------------------------------------------------------------------- */ { displayName: 'Coupon Type', name: 'couponType', @@ -71,9 +71,12 @@ export const couponFields = [ ] }, { - displayName: 'Product ID(s)', + displayName: 'Product IDs', name: 'productIds', - type: 'string', + type: 'multiOptions', + typeOptions: { + loadOptionsMethod: 'getProducts', + }, displayOptions: { show: { resource: [ @@ -184,6 +187,38 @@ export const couponFields = [ default: 'EUR', description: 'The currency must match the balance currency specified in your account.', options: [ + { + name: 'ARS', + value: 'ARS' + }, + { + name: 'AUD', + value: 'AUD' + }, + { + name: 'BRL', + value: 'BRL' + }, + { + name: 'CAD', + value: 'CAD' + }, + { + name: 'CHF', + value: 'CHF' + }, + { + name: 'CNY', + value: 'CNY' + }, + { + name: 'CZK', + value: 'CZK' + }, + { + name: 'DKK', + value: 'DKK' + }, { name: 'EUR', value: 'EUR' @@ -192,10 +227,70 @@ export const couponFields = [ name: 'GBP', value: 'GBP' }, + { + name: 'HKD', + value: 'HKD' + }, + { + name: 'HUF', + value: 'HUF' + }, + { + name: 'INR', + value: 'INR' + }, + { + name: 'JPY', + value: 'JPY' + }, + { + name: 'KRW', + value: 'KRW' + }, + { + name: 'MXN', + value: 'MXN' + }, + { + name: 'NOK', + value: 'NOK' + }, + { + name: 'NZD', + value: 'NZD' + }, + { + name: 'PLN', + value: 'PLN' + }, + { + name: 'RUB', + value: 'RUB' + }, + { + name: 'SEK', + value: 'SEK' + }, + { + name: 'SGD', + value: 'SGD' + }, + { + name: 'THB', + value: 'THB' + }, + { + name: 'TWD', + value: 'TWD' + }, { name: 'USD', value: 'USD' }, + { + name: 'ZAR', + value: 'ZAR' + }, ], displayOptions: { show: { @@ -295,6 +390,13 @@ export const couponFields = [ default: '', description: 'Prefix for generated codes. Not valid if coupon_code is specified.', }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'Description of the coupon. This will be displayed in the Seller Dashboard.', + }, { displayName: 'Expires', name: 'expires', @@ -313,13 +415,6 @@ export const couponFields = [ default: '', description: 'The name of the coupon group this coupon should be assigned to.', }, - { - displayName: 'Recurring', - name: 'recurring', - type: 'boolean', - default: false, - description: 'If the coupon is used on subscription products, this indicates whether the discount should apply to recurring payments after the initial purchase.', - }, { displayName: 'Number of Coupons', name: 'numberOfCoupons', @@ -328,21 +423,21 @@ export const couponFields = [ description: 'Number of coupons to generate. Not valid if coupon_code is specified.', }, { - displayName: 'Description', - name: 'description', - type: 'string', - default: '', - description: 'Description of the coupon. This will be displayed in the Seller Dashboard.', + displayName: 'Recurring', + name: 'recurring', + type: 'boolean', + default: false, + description: 'If the coupon is used on subscription products, this indicates whether the discount should apply to recurring payments after the initial purchase.', }, ], }, -/* -------------------------------------------------------------------------- */ -/* coupon:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* coupon:getAll */ + /* -------------------------------------------------------------------------- */ { displayName: 'Product ID', name: 'productId', - type: 'number', + type: 'string', displayOptions: { show: { resource: [ @@ -354,11 +449,53 @@ export const couponFields = [ }, }, default: '', + required: true, description: 'The specific product/subscription ID.', }, -/* -------------------------------------------------------------------------- */ -/* coupon:update */ -/* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'coupon', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'coupon', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 100, + description: 'How many results to return.', + }, + /* -------------------------------------------------------------------------- */ + /* coupon:update */ + /* -------------------------------------------------------------------------- */ { displayName: 'Update by', name: 'updateBy', @@ -453,7 +590,7 @@ export const couponFields = [ }, }, { - displayName: ' Additional Fields', + displayName: 'Additional Fields', name: 'additionalFieldsJson', type: 'json', typeOptions: { @@ -503,36 +640,191 @@ export const couponFields = [ description: 'Number of times a coupon can be used in a checkout. This will be set to 999,999 by default, if not specified.', }, { - displayName: 'Currency', - name: 'currency', - type: 'options', - default: 'EUR', - description: 'The currency must match the balance currency specified in your account.', + displayName: 'Discount', + name: 'discount', + type: 'fixedCollection', + default: 'discountProperties', options: [ { - name: 'EUR', - value: 'EUR' - }, - { - name: 'GBP', - value: 'GBP' - }, - { - name: 'USD', - value: 'USD' + displayName: 'Discount Properties', + name: 'discountProperties', + values: [ + { + displayName: 'Currency', + name: 'currency', + type: 'options', + default: 'EUR', + description: 'The currency must match the balance currency specified in your account.', + displayOptions: { + show: { + discountType: [ + 'flat', + ], + }, + }, + options: [ + { + name: 'ARS', + value: 'ARS' + }, + { + name: 'AUD', + value: 'AUD' + }, + { + name: 'BRL', + value: 'BRL' + }, + { + name: 'CAD', + value: 'CAD' + }, + { + name: 'CHF', + value: 'CHF' + }, + { + name: 'CNY', + value: 'CNY' + }, + { + name: 'CZK', + value: 'CZK' + }, + { + name: 'DKK', + value: 'DKK' + }, + { + name: 'EUR', + value: 'EUR' + }, + { + name: 'GBP', + value: 'GBP' + }, + { + name: 'HKD', + value: 'HKD' + }, + { + name: 'HUF', + value: 'HUF' + }, + { + name: 'INR', + value: 'INR' + }, + { + name: 'JPY', + value: 'JPY' + }, + { + name: 'KRW', + value: 'KRW' + }, + { + name: 'MXN', + value: 'MXN' + }, + { + name: 'NOK', + value: 'NOK' + }, + { + name: 'NZD', + value: 'NZD' + }, + { + name: 'PLN', + value: 'PLN' + }, + { + name: 'RUB', + value: 'RUB' + }, + { + name: 'SEK', + value: 'SEK' + }, + { + name: 'SGD', + value: 'SGD' + }, + { + name: 'THB', + value: 'THB' + }, + { + name: 'TWD', + value: 'TWD' + }, + { + name: 'USD', + value: 'USD' + }, + { + name: 'ZAR', + value: 'ZAR' + }, + ], + }, + { + displayName: 'Discount Amount Currency', + name: 'discountAmount', + type: 'number', + default: '', + description: 'Discount amount.', + displayOptions: { + show: { + discountType: [ + 'flat', + ], + }, + }, + typeOptions: { + minValue: 0 + }, + }, + { + displayName: 'Discount Amount Percentage', + name: 'discountAmount', + type: 'number', + default: '', + description: 'Discount amount.', + displayOptions: { + show: { + discountType: [ + 'percentage', + ], + }, + }, + typeOptions: { + minValue: 0, + maxValue: 100 + }, + }, + { + displayName: 'Discount Type', + name: 'discountType', + type: 'options', + default: 'flat', + description: 'Either flat or percentage.', + options: [ + { + name: 'Flat', + value: 'flat' + }, + { + name: 'Percentage', + value: 'percentage' + }, + ] + }, + ], }, ], }, - { - displayName: 'Discount Amount', - name: 'discountAmount', - type: 'number', - default: '', - description: 'Discount amount.', - typeOptions: { - minValue: 0 - }, - }, { displayName: 'Expires', name: 'expires', @@ -559,7 +851,7 @@ export const couponFields = [ description: 'New group name to move coupon to.', }, { - displayName: 'Product ID(s)', + displayName: 'Product IDs', name: 'productIds', type: 'string', default: '', diff --git a/packages/nodes-base/nodes/Paddle/GenericFunctions.ts b/packages/nodes-base/nodes/Paddle/GenericFunctions.ts index 8aa131884..243dc56ff 100644 --- a/packages/nodes-base/nodes/Paddle/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Paddle/GenericFunctions.ts @@ -1,4 +1,6 @@ -import { OptionsWithUri } from 'request'; +import { + OptionsWithUri, +} from 'request'; import { IExecuteFunctions, @@ -6,7 +8,6 @@ import { ILoadOptionsFunctions, IExecuteSingleFunctions, IWebhookFunctions, - BINARY_ENCODING } from 'n8n-core'; import { @@ -20,37 +21,50 @@ export async function paddleApiRequest(this: IHookFunctions | IExecuteFunctions throw new Error('Could not retrieve credentials!'); } - const options : OptionsWithUri = { + const options: OptionsWithUri = { method, headers: { 'content-type': 'application/json' }, - uri: `https://vendors.paddle.com/api${endpoint}` , + uri: `https://vendors.paddle.com/api${endpoint}`, body, json: true }; body['vendor_id'] = credentials.vendorId; body['vendor_auth_code'] = credentials.vendorAuthCode; - - console.log(options.body); - console.log(options); - try { const response = await this.helpers.request!(options); - console.log(response); if (!response.success) { throw new Error(`Code: ${response.error.code}. Message: ${response.error.message}`); } - return response.response; + return response; } catch (error) { - console.log(error); - throw new Error(error); + throw new Error(`ERROR: Code: ${error.code}. Message: ${error.message}`); } } +export async function paddleApiRequestAllItems(this: IHookFunctions | IExecuteFunctions, propertyName: string, endpoint: string, method: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any + + const returnData: IDataObject[] = []; + + let responseData; + + body.results_per_page = 200; + body.page = 1; + + do { + responseData = await paddleApiRequest.call(this, endpoint, method, body, query); + returnData.push.apply(returnData, responseData[propertyName]); + } while ( + responseData[propertyName].length !== 0 + ); + + return returnData; +} + export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any let result; try { diff --git a/packages/nodes-base/nodes/Paddle/OrderDescription.ts b/packages/nodes-base/nodes/Paddle/OrderDescription.ts index 367082a4b..d4afd8f7c 100644 --- a/packages/nodes-base/nodes/Paddle/OrderDescription.ts +++ b/packages/nodes-base/nodes/Paddle/OrderDescription.ts @@ -28,9 +28,9 @@ export const orderOperations = [ export const orderFields = [ -/* -------------------------------------------------------------------------- */ -/* order:get */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* order:get */ + /* -------------------------------------------------------------------------- */ { displayName: 'Checkout ID', name: 'checkoutId', diff --git a/packages/nodes-base/nodes/Paddle/Paddle.node.ts b/packages/nodes-base/nodes/Paddle/Paddle.node.ts index e5478aa11..94e1246f4 100644 --- a/packages/nodes-base/nodes/Paddle/Paddle.node.ts +++ b/packages/nodes-base/nodes/Paddle/Paddle.node.ts @@ -1,20 +1,53 @@ -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, validateJSON } from './GenericFunctions'; -import { paymentsFields, paymentsOperations } from './PaymentDescription'; -import { planFields, planOperations } from './PlanDescription'; -import { productFields, productOperations } from './ProductDescription'; -import { userFields, userOperations } from './UserDescription'; +import { + couponFields, + couponOperations, +} from './CouponDescription'; -import moment = require('moment'); -import { orderOperations, orderFields } from './OrderDescription'; +import { + paddleApiRequest, + paddleApiRequestAllItems, + validateJSON +} from './GenericFunctions'; + +import { + paymentFields, + paymentOperations, +} from './PaymentDescription'; + +import { + planFields, + planOperations, +} from './PlanDescription'; + +import { + productFields, + productOperations, +} from './ProductDescription'; + +import { + userFields, + userOperations, +} from './UserDescription'; + +// import { +// orderOperations, +// orderFields, +// } from './OrderDescription'; + +import * as moment from 'moment'; export class Paddle implements INodeType { description: INodeTypeDescription = { @@ -48,8 +81,8 @@ export class Paddle implements INodeType { value: 'coupon', }, { - name: 'Payments', - value: 'payments', + name: 'Payment', + value: 'payment', }, { name: 'Plan', @@ -59,10 +92,10 @@ export class Paddle implements INodeType { name: 'Product', value: 'product', }, - { - name: 'Order', - value: 'order', - }, + // { + // name: 'Order', + // value: 'order', + // }, { name: 'User', value: 'user', @@ -75,8 +108,8 @@ export class Paddle implements INodeType { ...couponOperations, ...couponFields, // PAYMENT - ...paymentsOperations, - ...paymentsFields, + ...paymentOperations, + ...paymentFields, // PLAN ...planOperations, ...planFields, @@ -84,14 +117,69 @@ export class Paddle implements INodeType { ...productOperations, ...productFields, // ORDER - ...orderOperations, - ...orderFields, + // ...orderOperations, + // ...orderFields, // USER ...userOperations, ...userFields ], }; + methods = { + loadOptions: { + /* -------------------------------------------------------------------------- */ + /* PAYMENT */ + /* -------------------------------------------------------------------------- */ + + // Get all payment so they can be selected in payment rescheduling + async getPayments(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const endpoint = '/2.0/subscription/payments'; + const paymentResponse = await paddleApiRequest.call(this, endpoint, 'POST', {}); + + // Alert user if there's no payments present to be loaded into payments property + if (paymentResponse.response === undefined || paymentResponse.response.length === 0) { + throw Error('No payments on account.'); + } + + for (const payment of paymentResponse.response) { + const id = payment.id; + returnData.push({ + name: id, + value: id, + }); + } + return returnData; + }, + + /* -------------------------------------------------------------------------- */ + /* PRODUCTS */ + /* -------------------------------------------------------------------------- */ + + // Get all Products so they can be selected in coupon creation when assigning products + async getProducts(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const endpoint = '/2.0/product/get_products'; + const products = await paddleApiRequest.call(this, endpoint, 'POST', {}); + + // Alert user if there's no products present to be loaded into payments property + if (products.length === 0) { + throw Error('No products on account.'); + } + + for (const product of products) { + const name = product.name; + const id = product.id; + returnData.push({ + name, + value: id, + }); + } + return returnData; + }, + } + }; + async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); const returnData: IDataObject[] = []; @@ -117,20 +205,21 @@ export class Paddle implements INodeType { } } else { - const discountType = this.getNodeParameter('discountType', i) as string; const couponType = this.getNodeParameter('couponType', i) as string; const discountAmount = this.getNodeParameter('discountAmount', i) as number; - const currency = this.getNodeParameter('currency', i) as string; if (couponType === 'product') { - body.product_ids = this.getNodeParameter('productIds', i) as string; + body.product_ids = (this.getNodeParameter('productIds', i) as string[]).join(); + } + + if (discountType === 'flat') { + body.currency = this.getNodeParameter('currency', i) as string; } body.coupon_type = couponType; body.discount_type = discountType; body.discount_amount = discountAmount; - body.currency = currency; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; @@ -164,16 +253,25 @@ export class Paddle implements INodeType { const endpoint = '/2.1/product/create_coupon'; responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + responseData = responseData.response.coupon_codes; } } if (operation === 'getAll') { - const productIds = this.getNodeParameter('productId', i) as string; + const productId = this.getNodeParameter('productId', i) as string; + const returnAll = this.getNodeParameter('returnAll', i) as boolean; const endpoint = '/2.0/product/list_coupons'; - body.product_id = productIds as string; + body.product_id = productId as string; responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + + if (returnAll) { + responseData = responseData.response; + } else { + const limit = this.getNodeParameter('limit', i) as number; + responseData = responseData.response.splice(0, limit); + } } if (operation === 'update') { @@ -217,9 +315,9 @@ export class Paddle implements INodeType { if (additionalFields.newGroup) { body.new_group = additionalFields.newGroup as string; } - if (additionalFields.recurring) { + if (additionalFields.recurring === true) { body.recurring = 1; - } else { + } else if (additionalFields.recurring === false) { body.recurring = 0; } if (additionalFields.productIds) { @@ -228,15 +326,29 @@ export class Paddle implements INodeType { if (additionalFields.discountAmount) { body.discount_amount = additionalFields.discountAmount as number; } + if (additionalFields.discount) { + //@ts-ignore + if (additionalFields.discount.discountProperties.discountType === 'percentage') { + // @ts-ignore + body.discount_amount = additionalFields.discount.discountProperties.discountAmount as number; + } else { + //@ts-ignore + body.currency = additionalFields.discount.discountProperties.currency as string; + //@ts-ignore + body.discount_amount = additionalFields.discount.discountProperties.discountAmount as number; + } + } } const endpoint = '/2.1/product/update_coupon'; responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + responseData = responseData.response; } } if (resource === 'payment') { if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; if (jsonParameters) { @@ -262,10 +374,10 @@ export class Paddle implements INodeType { if (additionalFields.state) { body.state = additionalFields.state as string; } - if (additionalFields.recurring) { - body.recurring = 1; + if (additionalFields.isPaid) { + body.is_paid = 1; } else { - body.recurring = 0; + body.is_paid = 0; } if (additionalFields.from) { body.from = moment(additionalFields.from as Date).format('YYYY-MM-DD') as string; @@ -277,10 +389,16 @@ export class Paddle implements INodeType { body.is_one_off_charge = additionalFields.isOneOffCharge as boolean; } } - const endpoint = '/2.0/subscription/payments'; responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + + if (returnAll) { + responseData = responseData.response; + } else { + const limit = this.getNodeParameter('limit', i) as number; + responseData = responseData.response.splice(0, limit); + } } if (operation === 'reschedule') { const paymentId = this.getNodeParameter('paymentId', i) as number; @@ -296,9 +414,17 @@ export class Paddle implements INodeType { } if (resource === 'plan') { if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; const endpoint = '/2.0/subscription/plans'; responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + + if (returnAll) { + responseData = responseData.response; + } else { + const limit = this.getNodeParameter('limit', i) as number; + responseData = responseData.response.splice(0, limit); + } } if (operation === 'get') { const planId = this.getNodeParameter('planId', i) as string; @@ -308,13 +434,22 @@ export class Paddle implements INodeType { const endpoint = '/2.0/subscription/plans'; responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + responseData = responseData.response; } } if (resource === 'product') { if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; const endpoint = '/2.0/product/get_products'; responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + + if (returnAll) { + responseData = responseData.response.products; + } else { + const limit = this.getNodeParameter('limit', i) as number; + responseData = responseData.response.products.splice(0, limit); + } } } if (resource === 'order') { @@ -329,6 +464,7 @@ export class Paddle implements INodeType { } if (resource === 'user') { if (operation === 'getAll') { + const returnAll = this.getNodeParameter('returnAll', i) as boolean; const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; @@ -344,11 +480,6 @@ export class Paddle implements INodeType { } } else { - const returnAll = this.getNodeParameter('returnAll', i) as boolean; - - if (!returnAll) { - body.results_per_page = this.getNodeParameter('limit', i) as number; - } const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; @@ -361,16 +492,20 @@ export class Paddle implements INodeType { if (additionalFields.subscriptionId) { body.subscription_id = additionalFields.subscriptionId as string; } - } + const endpoint = '/2.0/subscription/users'; - responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + if (returnAll) { + responseData = await paddleApiRequestAllItems.call(this, 'response', endpoint, 'POST', body); + } else { + body.results_per_page = this.getNodeParameter('limit', i) as number; + responseData = await paddleApiRequest.call(this, endpoint, 'POST', body); + responseData = responseData.response; + } } } - console.log(responseData); - if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); } else { diff --git a/packages/nodes-base/nodes/Paddle/PaddleTrigger.node.ts b/packages/nodes-base/nodes/Paddle/PaddleTrigger.node.ts deleted file mode 100644 index f439a5beb..000000000 --- a/packages/nodes-base/nodes/Paddle/PaddleTrigger.node.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { - IHookFunctions, - IWebhookFunctions, - } from 'n8n-core'; - - import { - IDataObject, - INodeTypeDescription, - INodeType, - IWebhookResponseData, - ILoadOptionsFunctions, - INodePropertyOptions, - } from 'n8n-workflow'; -import { paddleApiRequest } from './GenericFunctions'; - - export class PaddleTrigger implements INodeType { - description: INodeTypeDescription = { - displayName: 'Paddle Trigger', - name: 'paddleTrigger', - icon: 'file:paddle.png', - group: ['trigger'], - version: 1, - description: 'Handle Paddle events via webhooks', - defaults: { - name: 'Paddle Trigger', - color: '#32325d', - }, - inputs: [], - outputs: ['main'], - credentials: [ - { - name: 'paddleApi', - required: true, - } - ], - webhooks: [ - { - name: 'default', - httpMethod: 'POST', - reponseMode: 'onReceived', - path: 'webhook', - }, - ], - properties: [ - { - displayName: 'Events', - name: 'events', - type: 'multiOptions', - required: true, - default: [], - description: 'The event to listen to.', - typeOptions: { - loadOptionsMethod: 'getEvents' - }, - options: [], - }, - ], - }; - - - - // @ts-ignore (because of request) - webhookMethods = { - default: { - async checkExists(this: IHookFunctions): Promise { - const webhookData = this.getWorkflowStaticData('node'); - if (webhookData.webhookId === undefined) { - // No webhook id is set so no webhook can exist - return false; - } - const endpoint = `/notifications/webhooks/${webhookData.webhookId}`; - try { - await paddleApiRequest.call(this, endpoint, 'GET'); - } catch (err) { - if (err.response && err.response.name === 'INVALID_RESOURCE_ID') { - // Webhook does not exist - delete webhookData.webhookId; - return false; - } - throw new Error(`Paddle Error: ${err}`); - } - return true; - }, - - async create(this: IHookFunctions): Promise { - let webhook; - const webhookUrl = this.getNodeWebhookUrl('default'); - const events = this.getNodeParameter('events', []) as string[]; - const body = { - url: webhookUrl, - event_types: events.map(event => { - return { name: event }; - }), - }; - const endpoint = '/notifications/webhooks'; - try { - webhook = await paddleApiRequest.call(this, endpoint, 'POST', body); - } catch (e) { - throw e; - } - - if (webhook.id === undefined) { - return false; - } - const webhookData = this.getWorkflowStaticData('node'); - webhookData.webhookId = webhook.id as string; - return true; - }, - - async delete(this: IHookFunctions): Promise { - const webhookData = this.getWorkflowStaticData('node'); - if (webhookData.webhookId !== undefined) { - const endpoint = `/notifications/webhooks/${webhookData.webhookId}`; - try { - await paddleApiRequest.call(this, endpoint, 'DELETE', {}); - } catch (e) { - return false; - } - delete webhookData.webhookId; - } - return true; - }, - }, - }; - - async webhook(this: IWebhookFunctions): Promise { - let webhook; - const webhookData = this.getWorkflowStaticData('node') as IDataObject; - const bodyData = this.getBodyData() as IDataObject; - const req = this.getRequestObject(); - const headerData = this.getHeaderData() as IDataObject; - const endpoint = '/notifications/verify-webhook-signature'; - - if (headerData['PAYPAL-AUTH-ALGO'] !== undefined - && headerData['PAYPAL-CERT-URL'] !== undefined - && headerData['PAYPAL-TRANSMISSION-ID'] !== undefined - && headerData['PAYPAL-TRANSMISSION-SIG'] !== undefined - && headerData['PAYPAL-TRANSMISSION-TIME'] !== undefined) { - const body = { - auth_algo: headerData['PAYPAL-AUTH-ALGO'], - cert_url: headerData['PAYPAL-CERT-URL'], - transmission_id: headerData['PAYPAL-TRANSMISSION-ID'], - transmission_sig: headerData['PAYPAL-TRANSMISSION-SIG'], - transmission_time: headerData['PAYPAL-TRANSMISSION-TIME'], - webhook_id: webhookData.webhookId, - webhook_event: bodyData, - }; - try { - webhook = await paddleApiRequest.call(this, endpoint, 'POST', body); - } catch (e) { - throw e; - } - if (webhook.verification_status !== 'SUCCESS') { - return {}; - } - } else { - return {}; - } - return { - workflowData: [ - this.helpers.returnJsonArray(req.body) - ], - }; - } - } diff --git a/packages/nodes-base/nodes/Paddle/PaymentDescription.ts b/packages/nodes-base/nodes/Paddle/PaymentDescription.ts index 45d355385..b2020d4f5 100644 --- a/packages/nodes-base/nodes/Paddle/PaymentDescription.ts +++ b/packages/nodes-base/nodes/Paddle/PaymentDescription.ts @@ -2,7 +2,7 @@ import { INodeProperties, } from 'n8n-workflow'; -export const paymentsOperations = [ +export const paymentOperations = [ { displayName: 'Operation', name: 'operation', @@ -10,7 +10,7 @@ export const paymentsOperations = [ displayOptions: { show: { resource: [ - 'payments', + 'payment', ], }, }, @@ -18,7 +18,7 @@ export const paymentsOperations = [ { name: 'Get All', value: 'getAll', - description: 'Get all payments.', + description: 'Get all payment.', }, { name: 'Reschedule', @@ -31,10 +31,51 @@ export const paymentsOperations = [ }, ] as INodeProperties[]; -export const paymentsFields = [ -/* -------------------------------------------------------------------------- */ -/* payments:getAll */ -/* -------------------------------------------------------------------------- */ +export const paymentFields = [ + /* -------------------------------------------------------------------------- */ + /* payment:getAll */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'payment', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'payment', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 100, + description: 'How many results to return.', + }, { displayName: 'JSON Parameters', name: 'jsonParameters', @@ -44,7 +85,7 @@ export const paymentsFields = [ displayOptions: { show: { resource: [ - 'payments', + 'payment', ], operation: [ 'getAll', @@ -53,7 +94,7 @@ export const paymentsFields = [ }, }, { - displayName: ' Additional Fields', + displayName: 'Additional Fields', name: 'additionalFieldsJson', type: 'json', typeOptions: { @@ -63,7 +104,7 @@ export const paymentsFields = [ displayOptions: { show: { resource: [ - 'payments', + 'payment', ], operation: [ 'getAll', @@ -83,7 +124,7 @@ export const paymentsFields = [ displayOptions: { show: { resource: [ - 'payments', + 'payment', ], operation: [ 'getAll', @@ -100,14 +141,14 @@ export const paymentsFields = [ name: 'from', type: 'dateTime', default: '', - description: 'payments starting from date.', + description: 'payment starting from date.', }, { displayName: 'Date To', name: 'to', type: 'dateTime', default: '', - description: 'payments up until date.', + description: 'payment up until date.', }, { displayName: 'Is Paid', @@ -117,7 +158,7 @@ export const paymentsFields = [ description: 'payment is paid.', }, { - displayName: 'Plan', + displayName: 'Plan ID', name: 'plan', type: 'string', default: '', @@ -163,26 +204,29 @@ export const paymentsFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* payments:reschedule */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* payment:reschedule */ + /* -------------------------------------------------------------------------- */ { - displayName: 'payments ID', - name: 'paymentsId', - type: 'number', + displayName: 'Payment ID', + name: 'paymentId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getpayment', + }, default: '', required: true, displayOptions: { show: { resource: [ - 'payments', + 'payment', ], operation: [ 'reschedule', ], }, }, - description: 'The upcoming subscription payments ID.', // Use loadoptions to select payments + description: 'The upcoming subscription payment ID.', }, { displayName: 'Date', @@ -192,13 +236,13 @@ export const paymentsFields = [ displayOptions: { show: { resource: [ - 'payments', + 'payment', ], operation: [ 'reschedule', ], }, }, - description: 'Date you want to move the payments to.', + description: 'Date you want to move the payment to.', }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Paddle/PlanDescription.ts b/packages/nodes-base/nodes/Paddle/PlanDescription.ts index f6887ca64..152db9a7f 100644 --- a/packages/nodes-base/nodes/Paddle/PlanDescription.ts +++ b/packages/nodes-base/nodes/Paddle/PlanDescription.ts @@ -26,16 +26,16 @@ export const planOperations = [ description: 'Get all plans.', } ], - default: 'getAll', + default: 'get', description: 'The operation to perform.', }, ] as INodeProperties[]; export const planFields = [ -/* -------------------------------------------------------------------------- */ -/* plan:get */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* plan:get */ + /* -------------------------------------------------------------------------- */ { displayName: 'Plan ID', name: 'planId', @@ -54,4 +54,45 @@ export const planFields = [ }, description: 'Filter: The subscription plan ID.', }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'plan', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'plan', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 100, + description: 'How many results to return.', + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Paddle/ProductDescription.ts b/packages/nodes-base/nodes/Paddle/ProductDescription.ts index 9d6ca39b3..9a627a86e 100644 --- a/packages/nodes-base/nodes/Paddle/ProductDescription.ts +++ b/packages/nodes-base/nodes/Paddle/ProductDescription.ts @@ -27,4 +27,45 @@ export const productOperations = [ ] as INodeProperties[]; export const productFields = [ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'product', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'product', + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 100, + description: 'How many results to return.', + }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Paddle/UserDescription.ts b/packages/nodes-base/nodes/Paddle/UserDescription.ts index d45cc2ddb..50b1a9295 100644 --- a/packages/nodes-base/nodes/Paddle/UserDescription.ts +++ b/packages/nodes-base/nodes/Paddle/UserDescription.ts @@ -27,9 +27,9 @@ export const userOperations = [ ] as INodeProperties[]; export const userFields = [ -/* -------------------------------------------------------------------------- */ -/* user:getAll */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* user:getAll */ + /* -------------------------------------------------------------------------- */ { displayName: 'Return All', name: 'returnAll', @@ -51,7 +51,7 @@ export const userFields = [ displayName: 'Limit', name: 'limit', type: 'number', - default: 1, + default: 100, required: true, typeOptions: { minValue: 1, @@ -90,7 +90,7 @@ export const userFields = [ }, }, { - displayName: ' Additional Fields', + displayName: 'Additional Fields', name: 'additionalFieldsJson', type: 'json', typeOptions: {