Add Stripe regular node (#1470)

* 🎉 Register node

* 🎨 Add SVG icon

*  Add preliminary node stub

*  Add resource description stubs

* 🎨 Fix SVG size and position

*  Implement charge operations

*  Implement customer operations

* 🎨 Apply cosmetic changes

*  Fix customer address fields

*  Add stub and fields for invoice

*  Add invoice item stubs

*  Implement source operations

*  Reduce scope per feedback

*  Add continueOnFail functionality

* 🎨 Prettify error thrown

* 🔥 Remove unused resource

*  Replace source in card with token

* 🔨 Remove logging

* 🔧 Fix shipping address in charge:create

* 🔧 Load update fields for charge:update

*  Implement token:create to ease testing

*  Simplify card token fields

*  Update description parameters

* 🔧 Fix field adjusters

*  Remove unused source options

* 🔧 Fix shipping fields adjuster

* 🔥 Remove PNG icon

* 🔥 Remove logging

* 🔨 Reorder address fields

* 🐛 Fix shipping field in charge:update

* 💄 Apply cosmetic change

*  Small improvements

*  Fix lintings in main file

*  Lint all descriptions

*  Add target="_blank" attribute

*  Fix various lintings for charge

*  Fix lintings for coupon

*  Fix lintings for customer

*  Fix lintings for source

*  Fix lintings for token

*  Reorder address fields

*  Fix casing in credentials

* 🔨 Place recipient name above address in shipping

*  Remove references to string in descriptions

*  Apply minor renamings

* 🔥 Remove logging

* 🔨 Simplify error handling

*  Fix indentation

*  Move cardFields to root level for Token creation

Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
Iván Ovejero 2021-07-10 13:15:14 +02:00 committed by GitHub
parent a3ec24e912
commit b4f4ecc77e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 2609 additions and 5 deletions

View file

@ -6,7 +6,7 @@ import {
export class StripeApi implements ICredentialType { export class StripeApi implements ICredentialType {
name = 'stripeApi'; name = 'stripeApi';
displayName = 'Stripe Api'; displayName = 'Stripe API';
documentationUrl = 'stripe'; documentationUrl = 'stripe';
properties: INodeProperties[] = [ properties: INodeProperties[] = [
// The credentials to get from user and save encrypted. // The credentials to get from user and save encrypted.

View file

@ -30,6 +30,7 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF
if (Object.keys(body).length === 0) { if (Object.keys(body).length === 0) {
delete options.body; delete options.body;
} }
console.log(options);
//@ts-ignore //@ts-ignore
return await this.helpers.requestOAuth2.call(this, 'googleCalendarOAuth2Api', options); return await this.helpers.requestOAuth2.call(this, 'googleCalendarOAuth2Api', options);
} catch (error) { } catch (error) {

View file

@ -0,0 +1,506 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import {
IDataObject,
ILoadOptionsFunctions,
INodeExecutionData,
INodePropertyOptions,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import {
isEmpty,
} from 'lodash';
import {
adjustChargeFields,
adjustCustomerFields,
adjustMetadata,
handleListing,
loadResource,
stripeApiRequest,
} from './helpers';
import {
balanceOperations,
chargeFields,
chargeOperations,
couponFields,
couponOperations,
customerCardFields,
customerCardOperations,
customerFields,
customerOperations,
sourceFields,
sourceOperations,
tokenFields,
tokenOperations,
} from './descriptions';
export class Stripe implements INodeType {
description: INodeTypeDescription = {
displayName: 'Stripe',
name: 'stripe',
icon: 'file:stripe.svg',
group: ['transform'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Consume the Stripe API',
defaults: {
name: 'Stripe',
color: '#6772e5',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'stripeApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Balance',
value: 'balance',
},
{
name: 'Charge',
value: 'charge',
},
{
name: 'Coupon',
value: 'coupon',
},
{
name: 'Customer',
value: 'customer',
},
{
name: 'Customer Card',
value: 'customerCard',
},
{
name: 'Source',
value: 'source',
},
{
name: 'Token',
value: 'token',
},
],
default: 'balance',
description: 'Resource to consume',
},
...balanceOperations,
...customerCardOperations,
...customerCardFields,
...chargeOperations,
...chargeFields,
...couponOperations,
...couponFields,
...customerOperations,
...customerFields,
...sourceOperations,
...sourceFields,
...tokenOperations,
...tokenFields,
],
};
methods = {
loadOptions: {
async getCustomers(this: ILoadOptionsFunctions) {
return await loadResource.call(this, 'customer');
},
async getCurrencies(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { data } = await stripeApiRequest.call(this, 'GET', '/country_specs', {});
for (const currency of data[0].supported_payment_currencies) {
returnData.push({
name: currency.toUpperCase(),
value: currency,
});
}
return returnData;
},
},
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string;
let responseData;
const returnData: IDataObject[] = [];
for (let i = 0; i < items.length; i++) {
try {
if (resource === 'balance') {
// *********************************************************************
// balance
// *********************************************************************
// https://stripe.com/docs/api/balance
if (operation === 'get') {
// ----------------------------------
// balance: get
// ----------------------------------
responseData = await stripeApiRequest.call(this, 'GET', '/balance', {}, {});
}
} else if (resource === 'customerCard') {
// *********************************************************************
// customer card
// *********************************************************************
// https://stripe.com/docs/api/cards
if (operation === 'add') {
// ----------------------------------
// customerCard: add
// ----------------------------------
const body = {
source: this.getNodeParameter('token', i),
} as IDataObject;
const customerId = this.getNodeParameter('customerId', i);
const endpoint = `/customers/${customerId}/sources`;
responseData = await stripeApiRequest.call(this, 'POST', endpoint, body, {});
} else if (operation === 'remove') {
// ----------------------------------
// customerCard: remove
// ----------------------------------
const customerId = this.getNodeParameter('customerId', i);
const cardId = this.getNodeParameter('cardId', i);
const endpoint = `/customers/${customerId}/sources/${cardId}`;
responseData = await stripeApiRequest.call(this, 'DELETE', endpoint, {}, {});
} else if (operation === 'get') {
// ----------------------------------
// customerCard: get
// ----------------------------------
const customerId = this.getNodeParameter('customerId', i);
const sourceId = this.getNodeParameter('sourceId', i);
const endpoint = `/customers/${customerId}/sources/${sourceId}`;
responseData = await stripeApiRequest.call(this, 'GET', endpoint, {}, {});
}
} else if (resource === 'charge') {
// *********************************************************************
// charge
// *********************************************************************
// https://stripe.com/docs/api/charges
if (operation === 'create') {
// ----------------------------------
// charge: create
// ----------------------------------
const body = {
customer: this.getNodeParameter('customerId', i),
currency: (this.getNodeParameter('currency', i) as string).toLowerCase(),
amount: this.getNodeParameter('amount', i),
source: this.getNodeParameter('source', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (!isEmpty(additionalFields)) {
Object.assign(body, adjustChargeFields(additionalFields));
}
responseData = await stripeApiRequest.call(this, 'POST', '/charges', body, {});
} else if (operation === 'get') {
// ----------------------------------
// charge: get
// ----------------------------------
const chargeId = this.getNodeParameter('chargeId', i);
responseData = await stripeApiRequest.call(this, 'GET', `/charges/${chargeId}`, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// charge: getAll
// ----------------------------------
responseData = await handleListing.call(this, resource);
} else if (operation === 'update') {
// ----------------------------------
// charge: update
// ----------------------------------
const body = {} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new Error(`Please enter at least one field to update for the ${resource}.`);
}
Object.assign(body, adjustChargeFields(updateFields));
const chargeId = this.getNodeParameter('chargeId', i);
responseData = await stripeApiRequest.call(this, 'POST', `/charges/${chargeId}`, body, {});
}
} else if (resource === 'coupon') {
// *********************************************************************
// coupon
// *********************************************************************
// https://stripe.com/docs/api/coupons
if (operation === 'create') {
// ----------------------------------
// coupon: create
// ----------------------------------
const body = {
duration: this.getNodeParameter('duration', i),
} as IDataObject;
const type = this.getNodeParameter('type', i);
if (type === 'fixedAmount') {
body.amount_off = this.getNodeParameter('amountOff', i);
body.currency = this.getNodeParameter('currency', i);
} else {
body.percent_off = this.getNodeParameter('percentOff', i);
}
responseData = await stripeApiRequest.call(this, 'POST', '/coupons', body, {});
} else if (operation === 'getAll') {
// ----------------------------------
// coupon: getAll
// ----------------------------------
responseData = await handleListing.call(this, resource);
}
} else if (resource === 'customer') {
// *********************************************************************
// customer
// *********************************************************************
// https://stripe.com/docs/api/customers
if (operation === 'create') {
// ----------------------------------
// customer: create
// ----------------------------------
const body = {
name: this.getNodeParameter('name', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (!isEmpty(additionalFields)) {
Object.assign(body, adjustCustomerFields(additionalFields));
}
responseData = await stripeApiRequest.call(this, 'POST', '/customers', body, {});
} else if (operation === 'delete') {
// ----------------------------------
// customer: delete
// ----------------------------------
const customerId = this.getNodeParameter('customerId', i);
responseData = await stripeApiRequest.call(this, 'DELETE', `/customers/${customerId}`, {}, {});
} else if (operation === 'get') {
// ----------------------------------
// customer: get
// ----------------------------------
const customerId = this.getNodeParameter('customerId', i);
responseData = await stripeApiRequest.call(this, 'GET', `/customers/${customerId}`, {}, {});
} else if (operation === 'getAll') {
// ----------------------------------
// customer: getAll
// ----------------------------------
const qs = {} as IDataObject;
const filters = this.getNodeParameter('filters', i) as IDataObject;
if (!isEmpty(filters)) {
qs.email = filters.email;
}
responseData = await handleListing.call(this, resource, qs);
} else if (operation === 'update') {
// ----------------------------------
// customer: update
// ----------------------------------
const body = {} as IDataObject;
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
if (isEmpty(updateFields)) {
throw new Error(`Please enter at least one field to update for the ${resource}.`);
}
Object.assign(body, adjustCustomerFields(updateFields));
const customerId = this.getNodeParameter('customerId', i);
responseData = await stripeApiRequest.call(this, 'POST', `/customers/${customerId}`, body, {});
}
} else if (resource === 'source') {
// *********************************************************************
// source
// *********************************************************************
// https://stripe.com/docs/api/sources
if (operation === 'create') {
// ----------------------------------
// source: create
// ----------------------------------
const customerId = this.getNodeParameter('customerId', i);
const body = {
type: this.getNodeParameter('type', i),
amount: this.getNodeParameter('amount', i),
currency: this.getNodeParameter('currency', i),
} as IDataObject;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (!isEmpty(additionalFields)) {
Object.assign(body, adjustMetadata(additionalFields));
}
responseData = await stripeApiRequest.call(this, 'POST', '/sources', body, {});
// attach source to customer
const endpoint = `/customers/${customerId}/sources`;
await stripeApiRequest.call(this, 'POST', endpoint, { source: responseData.id }, {});
} else if (operation === 'delete') {
// ----------------------------------
// source: delete
// ----------------------------------
const sourceId = this.getNodeParameter('sourceId', i);
const customerId = this.getNodeParameter('customerId', i);
const endpoint = `/customers/${customerId}/sources/${sourceId}`;
responseData = await stripeApiRequest.call(this, 'DELETE', endpoint, {}, {});
} else if (operation === 'get') {
// ----------------------------------
// source: get
// ----------------------------------
const sourceId = this.getNodeParameter('sourceId', i);
responseData = await stripeApiRequest.call(this, 'GET', `/sources/${sourceId}`, {}, {});
}
} else if (resource === 'token') {
// *********************************************************************
// token
// *********************************************************************
// https://stripe.com/docs/api/tokens
if (operation === 'create') {
// ----------------------------------
// token: create
// ----------------------------------
const type = this.getNodeParameter('type', i);
const body = {} as IDataObject;
if (type !== 'cardToken') {
throw new Error('Only card token creation implemented.');
}
body.card = {
number: this.getNodeParameter('number', i),
exp_month: this.getNodeParameter('expirationMonth', i),
exp_year: this.getNodeParameter('expirationYear', i),
cvc: this.getNodeParameter('cvc', i),
};
responseData = await stripeApiRequest.call(this, 'POST', '/tokens', body, {});
}
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message });
continue;
}
throw error;
}
Array.isArray(responseData)
? returnData.push(...responseData)
: returnData.push(responseData);
}
return [this.helpers.returnJsonArray(returnData)];
}
}

View file

@ -0,0 +1,27 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const balanceOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
default: 'get',
description: 'Operation to perform',
options: [
{
name: 'Get',
value: 'get',
description: 'Get a balance',
},
],
displayOptions: {
show: {
resource: [
'balance',
],
},
},
},
] as INodeProperties[];

View file

@ -0,0 +1,509 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const chargeOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
default: 'get',
description: 'Operation to perform',
options: [
{
name: 'Create',
value: 'create',
description: 'Create a charge',
},
{
name: 'Get',
value: 'get',
description: 'Get a charge',
},
{
name: 'Get All',
value: 'getAll',
description: 'Get all charges',
},
{
name: 'Update',
value: 'update',
description: 'Update a charge',
},
],
displayOptions: {
show: {
resource: [
'charge',
],
},
},
},
] as INodeProperties[];
export const chargeFields = [
// ----------------------------------
// charge: create
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer to be associated with this charge',
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Amount',
name: 'amount',
type: 'number',
required: true,
default: 0,
description: 'Amount in cents to be collected for this charge, e.g. enter <code>100</code> for $1.00',
typeOptions: {
minValue: 0,
maxValue: 99999999,
},
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Currency',
name: 'currency',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getCurrencies',
},
required: true,
default: '',
description: 'Three-letter ISO currency code, e.g. <code>USD</code> or <code>EUR</code>. It must be a <a target="_blank" href="https://stripe.com/docs/currencies">Stripe-supported currency</a>',
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Source ID',
name: 'source',
type: 'string',
required: true,
default: '',
description: 'ID of the customer\'s payment source to be charged',
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Description',
name: 'description',
type: 'string',
default: '',
description: 'Arbitrary text to describe the charge to create',
},
{
displayName: 'Metadata',
name: 'metadata',
type: 'fixedCollection',
default: [],
placeholder: 'Add Metadata Item',
description: 'Set of key-value pairs to attach to the charge to create',
typeOptions: {
multipleValues: true,
},
options: [
{
displayName: 'Metadata Properties',
name: 'metadataProperties',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Receipt Email',
name: 'receipt_email',
type: 'string',
default: '',
description: 'Email address to which the receipt for this charge will be sent',
},
{
displayName: 'Shipping',
name: 'shipping',
type: 'fixedCollection',
description: 'Shipping information for the charge',
placeholder: 'Add Field',
typeOptions: {
multipleValues: true,
},
default: [],
options: [
{
displayName: 'Shipping Properties',
name: 'shippingProperties',
values: [
{
displayName: 'Recipient Name',
name: 'name',
type: 'string',
description: 'Name of the person who will receive the shipment',
default: '',
},
{
displayName: 'Address',
name: 'address',
type: 'fixedCollection',
default: {},
placeholder: 'Add Field',
options: [
{
displayName: 'Details',
name: 'details',
values: [
{
displayName: 'Line 1',
name: 'line1',
description: 'Address line 1 (e.g. street, PO Box, or company name)',
type: 'string',
default: '',
},
{
displayName: 'Line 2',
name: 'line2',
description: 'Address line 2 (e.g. apartment, suite, unit, or building)',
type: 'string',
default: '',
},
{
displayName: 'City',
name: 'city',
description: 'City, district, suburb, town, or village',
type: 'string',
default: '',
},
{
displayName: 'State',
name: 'state',
description: 'State, county, province, or region',
type: 'string',
default: '',
},
{
displayName: 'Country',
name: 'country',
description: 'Two-letter country code (<a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2</a>)',
type: 'string',
default: '',
},
{
displayName: 'Postal Code',
name: 'postal_code',
description: 'ZIP or postal code',
type: 'string',
default: '',
},
],
},
],
},
],
},
],
},
],
},
// ----------------------------------
// charge: get
// ----------------------------------
{
displayName: 'Charge ID',
name: 'chargeId',
type: 'string',
required: true,
default: '',
description: 'ID of the charge to retrieve.',
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'get',
],
},
},
},
// ----------------------------------
// charge: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
// ----------------------------------
// charge: update
// ----------------------------------
{
displayName: 'Charge ID',
name: 'chargeId',
type: 'string',
required: true,
default: '',
description: 'ID of the charge to update',
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'charge',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Description',
name: 'description',
type: 'string',
default: '',
description: 'Arbitrary text to describe the charge to update',
},
{
displayName: 'Metadata',
name: 'metadata',
type: 'fixedCollection',
placeholder: 'Add Metadata Item',
description: 'Set of key-value pairs to attach to the charge to update',
typeOptions: {
multipleValues: true,
},
options: [
{
displayName: 'Metadata Properties',
name: 'metadataProperties',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Receipt Email',
name: 'receipt_email',
type: 'string',
default: '',
description: 'The email address to which the receipt for this charge will be sent',
},
{
displayName: 'Shipping',
name: 'shipping',
type: 'fixedCollection',
description: 'Shipping information for the charge',
placeholder: 'Add Field',
typeOptions: {
multipleValues: true,
},
options: [
{
displayName: 'Shipping Properties',
name: 'shippingProperties',
default: {},
values: [
{
displayName: 'Recipient Name',
name: 'name',
type: 'string',
default: '',
},
{
displayName: 'Recipient Address',
name: 'address',
type: 'fixedCollection',
default: {},
placeholder: 'Add Address Details',
options: [
{
displayName: 'Details',
name: 'details',
values: [
{
displayName: 'Line 1',
name: 'line1',
description: 'Address line 1 (e.g. street, PO Box, or company name)',
type: 'string',
default: '',
},
{
displayName: 'Line 2',
name: 'line2',
description: 'Address line 2 (e.g. apartment, suite, unit, or building)',
type: 'string',
default: '',
},
{
displayName: 'City',
name: 'city',
description: 'City, district, suburb, town, or village',
type: 'string',
default: '',
},
{
displayName: 'State',
name: 'state',
description: 'State, county, province, or region',
type: 'string',
default: '',
},
{
displayName: 'Country',
name: 'country',
description: 'Two-letter country code (<a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2</a>)',
type: 'string',
default: '',
},
{
displayName: 'Postal Code',
name: 'postal_code',
description: 'ZIP or postal code',
type: 'string',
default: '',
},
],
},
],
},
],
},
],
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,213 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const couponOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
default: 'create',
description: 'Operation to perform',
options: [
{
name: 'Create',
value: 'create',
description: 'Create a coupon',
},
{
name: 'Get All',
value: 'getAll',
description: 'Get all coupons',
},
],
displayOptions: {
show: {
resource: [
'coupon',
],
},
},
},
] as INodeProperties[];
export const couponFields = [
// ----------------------------------
// coupon: create
// ----------------------------------
{
displayName: 'Apply',
name: 'duration',
type: 'options',
required: true,
default: 'once',
description: 'How long the discount will be in effect',
options: [
{
name: 'Forever',
value: 'forever',
},
{
name: 'Once',
value: 'once',
},
],
displayOptions: {
show: {
resource: [
'coupon',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Discount Type',
name: 'type',
type: 'options',
required: true,
default: 'percent',
description: 'Whether the coupon discount is a percentage or a fixed amount',
options: [
{
name: 'Fixed Amount (in Cents)',
value: 'fixedAmount',
},
{
name: 'Percent',
value: 'percent',
},
],
displayOptions: {
show: {
resource: [
'coupon',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Amount Off',
name: 'amountOff',
type: 'number',
required: true,
default: 0,
description: 'Amount in cents to subtract from an invoice total, e.g. enter <code>100</code> for $1.00',
typeOptions: {
minValue: 0,
maxValue: 99999999,
},
displayOptions: {
show: {
resource: [
'coupon',
],
operation: [
'create',
],
type: [
'fixedAmount',
],
},
},
},
{
displayName: 'Currency',
name: 'currency',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getCurrencies',
},
required: true,
default: '',
description: 'Three-letter ISO currency code, e.g. <code>USD</code> or <code>EUR</code>. It must be a <a target="_blank" href="https://stripe.com/docs/currencies">Stripe-supported currency</a>',
displayOptions: {
show: {
resource: [
'coupon',
],
operation: [
'create',
],
type: [
'fixedAmount',
],
},
},
},
{
displayName: 'Percent Off',
name: 'percentOff',
type: 'number',
required: true,
default: 1,
description: 'Percentage to apply with the coupon',
typeOptions: {
minValue: 1,
maxValue: 100,
},
displayOptions: {
show: {
resource: [
'coupon',
],
operation: [
'create',
],
type: [
'percent',
],
},
},
},
// ----------------------------------
// coupon: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'coupon',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: [
'coupon',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
] as INodeProperties[];

View file

@ -0,0 +1,160 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const customerCardOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
default: 'get',
description: 'Operation to perform',
options: [
{
name: 'Add',
value: 'add',
description: 'Add a customer card',
},
{
name: 'Get',
value: 'get',
description: 'Get a customer card',
},
{
name: 'Remove',
value: 'remove',
description: 'Remove a customer card',
},
],
displayOptions: {
show: {
resource: [
'customerCard',
],
},
},
},
] as INodeProperties[];
export const customerCardFields = [
// ----------------------------------
// customerCard: add
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer to be associated with this card',
displayOptions: {
show: {
resource: [
'customerCard',
],
operation: [
'add',
],
},
},
},
{
displayName: 'Card Token',
name: 'token',
type: 'string',
required: true,
default: '',
placeholder: 'tok_1IMfKdJhRTnqS5TKQVG1LI9o',
description: 'Token representing sensitive card information',
displayOptions: {
show: {
resource: [
'customerCard',
],
operation: [
'add',
],
},
},
},
// ----------------------------------
// customerCard: remove
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer whose card to remove',
displayOptions: {
show: {
resource: [
'customerCard',
],
operation: [
'remove',
],
},
},
},
{
displayName: 'Card ID',
name: 'cardId',
type: 'string',
required: true,
default: '',
description: 'ID of the card to remove',
displayOptions: {
show: {
resource: [
'customerCard',
],
operation: [
'remove',
],
},
},
},
// ----------------------------------
// customerCard: get
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer whose card to retrieve',
displayOptions: {
show: {
resource: [
'customerCard',
],
operation: [
'get',
],
},
},
},
{
displayName: 'Source ID',
name: 'sourceId',
type: 'string',
required: true,
default: '',
description: 'ID of the source to retrieve',
displayOptions: {
show: {
resource: [
'customerCard',
],
operation: [
'get',
],
},
},
},
] as INodeProperties[];

View file

@ -0,0 +1,649 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const customerOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
default: 'get',
description: 'Operation to perform',
options: [
{
name: 'Create',
value: 'create',
description: 'Create a customer',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a customer',
},
{
name: 'Get',
value: 'get',
description: 'Get a customer',
},
{
name: 'Get All',
value: 'getAll',
description: 'Get all customers',
},
{
name: 'Update',
value: 'update',
description: 'Update a customer',
},
],
displayOptions: {
show: {
resource: [
'customer',
],
},
},
},
] as INodeProperties[];
export const customerFields = [
// ----------------------------------
// customer: create
// ----------------------------------
{
displayName: 'Name',
name: 'name',
type: 'string',
required: true,
default: '',
description: 'Full name or business name of the customer to create',
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Address',
name: 'address',
type: 'fixedCollection',
description: 'Address of the customer to create',
placeholder: 'Add Field',
default: {},
options: [
{
displayName: 'Details',
name: 'details',
values: [
{
displayName: 'Line 1',
name: 'line1',
description: 'Address line 1 (e.g. street, PO Box, or company name)',
type: 'string',
default: '',
},
{
displayName: 'Line 2',
name: 'line2',
description: 'Address line 2 (e.g. apartment, suite, unit, or building)',
type: 'string',
default: '',
},
{
displayName: 'City',
name: 'city',
description: 'City, district, suburb, town, or village',
type: 'string',
default: '',
},
{
displayName: 'State',
name: 'state',
description: 'State, county, province, or region',
type: 'string',
default: '',
},
{
displayName: 'Country',
name: 'country',
description: 'Two-letter country code (<a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2</a>)',
type: 'string',
default: '',
},
{
displayName: 'Postal Code',
name: 'postal_code',
description: 'ZIP or postal code',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Description',
name: 'description',
type: 'string',
default: '',
description: 'Arbitrary text to describe the customer to create',
},
{
displayName: 'Email',
name: 'email',
type: 'string',
default: '',
description: 'Email of the customer to create',
},
{
displayName: 'Metadata',
name: 'metadata',
type: 'fixedCollection',
default: {},
placeholder: 'Add Metadata Item',
description: 'Set of key-value pairs to attach to the customer to create',
typeOptions: {
multipleValues: true,
},
options: [
{
displayName: 'Metadata Properties',
name: 'metadataProperties',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'Telephone number of the customer to create',
},
{
displayName: 'Shipping',
name: 'shipping',
type: 'fixedCollection',
description: 'Shipping information for the customer',
typeOptions: {
multipleValues: true,
},
placeholder: 'Add Field',
options: [
{
displayName: 'Shipping Properties',
name: 'shippingProperties',
values: [
{
displayName: 'Recipient Name',
name: 'name',
type: 'string',
default: '',
},
{
displayName: 'Recipient Address',
name: 'address',
type: 'fixedCollection',
default: {},
placeholder: 'Add Address Details',
options: [
{
displayName: 'Details',
name: 'details',
values: [
{
displayName: 'Line 1',
name: 'line1',
description: 'Address line 1 (e.g. street, PO Box, or company name)',
type: 'string',
default: '',
},
{
displayName: 'Line 2',
name: 'line2',
description: 'Address line 2 (e.g. apartment, suite, unit, or building)',
type: 'string',
default: '',
},
{
displayName: 'City',
name: 'city',
description: 'City, district, suburb, town, or village',
type: 'string',
default: '',
},
{
displayName: 'State',
name: 'state',
description: 'State, county, province, or region',
type: 'string',
default: '',
},
{
displayName: 'Country',
name: 'country',
description: 'Two-letter country code (<a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2</a>)',
type: 'string',
default: '',
},
{
displayName: 'Postal Code',
name: 'postal_code',
description: 'ZIP or postal code',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Recipient Phone',
name: 'phone',
type: 'string',
default: '',
},
],
},
],
},
],
},
// ----------------------------------
// customer: delete
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer to delete',
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------
// customer: get
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer to retrieve',
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'get',
],
},
},
},
// ----------------------------------
// customer: getAll
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
default: false,
description: 'Whether to return all results or only up to a given limit',
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'getAll',
],
},
},
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
default: 50,
description: 'How many results to return',
typeOptions: {
minValue: 1,
maxValue: 1000,
},
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'getAll',
],
},
},
options: [
{
displayName: 'Email',
name: 'email',
type: 'string',
default: '',
description: 'Customer\'s email to filter by',
},
],
},
// ----------------------------------
// customer: update
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer to update',
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'update',
],
},
},
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'customer',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Address',
name: 'address',
type: 'fixedCollection',
description: 'Address of the customer to update',
placeholder: 'Add Field',
default: {},
options: [
{
displayName: 'Details',
name: 'details',
values: [
{
displayName: 'Line 1',
name: 'line1',
description: 'Address line 1 (e.g. street, PO Box, or company name)',
type: 'string',
default: '',
},
{
displayName: 'Line 2',
name: 'line2',
description: 'Address line 2 (e.g. apartment, suite, unit, or building)',
type: 'string',
default: '',
},
{
displayName: 'City',
name: 'city',
description: 'City, district, suburb, town, or village',
type: 'string',
default: '',
},
{
displayName: 'State',
name: 'state',
description: 'State, county, province, or region',
type: 'string',
default: '',
},
{
displayName: 'Country',
name: 'country',
description: 'Two-letter country code (<a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2</a>)',
type: 'string',
default: '',
},
{
displayName: 'Postal Code',
name: 'postal_code',
description: 'ZIP or postal code',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Description',
name: 'description',
type: 'string',
default: '',
description: 'Arbitrary text to describe the customer to create',
},
{
displayName: 'Email',
name: 'email',
type: 'string',
default: '',
description: 'Email of the customer to create',
},
{
displayName: 'Metadata',
name: 'metadata',
type: 'fixedCollection',
placeholder: 'Add Metadata Item',
description: 'Set of key-value pairs to attach to the customer to create',
typeOptions: {
multipleValues: true,
},
options: [
{
displayName: 'Metadata Properties',
name: 'metadataProperties',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
description: 'Full name or business name of the customer to create',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'Telephone number of this customer',
},
{
displayName: 'Shipping',
name: 'shipping',
type: 'fixedCollection',
description: 'Shipping information for the customer',
placeholder: 'Add Field',
typeOptions: {
multipleValues: true,
},
default: {},
options: [
{
displayName: 'Shipping Properties',
name: 'shippingProperties',
values: [
{
displayName: 'Recipient Name',
name: 'name',
type: 'string',
default: '',
description: 'Name of the person who will receive the shipment',
},
{
displayName: 'Recipient Address',
name: 'address',
type: 'fixedCollection',
default: {},
placeholder: 'Add Address Details',
options: [
{
displayName: 'Details',
name: 'details',
values: [
{
displayName: 'Line 1',
name: 'line1',
description: 'Address line 1 (e.g. street, PO Box, or company name)',
type: 'string',
default: '',
},
{
displayName: 'Line 2',
name: 'line2',
description: 'Address line 2 (e.g. apartment, suite, unit, or building)',
type: 'string',
default: '',
},
{
displayName: 'City',
name: 'city',
description: 'City, district, suburb, town, or village',
type: 'string',
default: '',
},
{
displayName: 'State',
name: 'state',
description: 'State, county, province, or region',
type: 'string',
default: '',
},
{
displayName: 'Country',
name: 'country',
description: 'Two-letter country code (<a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2</a>)',
type: 'string',
default: '',
},
{
displayName: 'Postal Code',
name: 'postal_code',
description: 'ZIP or postal code',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Recipient Phone',
name: 'phone',
type: 'string',
default: '',
description: 'Phone number of the person who will receive the shipment',
},
],
},
],
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,246 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const sourceOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
default: 'get',
description: 'Operation to perform',
options: [
{
name: 'Create',
value: 'create',
description: 'Create a source',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a source',
},
{
name: 'Get',
value: 'get',
description: 'Get a source',
},
],
displayOptions: {
show: {
resource: [
'source',
],
},
},
},
] as INodeProperties[];
export const sourceFields = [
// ----------------------------------
// source: create
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer to attach the source to',
displayOptions: {
show: {
resource: [
'source',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Type',
name: 'type',
type: 'options',
required: true,
default: 'wechat',
description: 'Type of source (payment instrument) to create',
options: [
{
name: 'WeChat',
value: 'wechat',
},
],
displayOptions: {
show: {
resource: [
'source',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Amount',
name: 'amount',
type: 'number',
default: 0,
description: 'Amount in cents to be collected for this charge, e.g. enter <code>100</code> for $1.00',
typeOptions: {
minValue: 0,
maxValue: 99999999,
},
displayOptions: {
show: {
resource: [
'source',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Currency',
name: 'currency',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getCurrencies',
},
default: '',
description: 'Three-letter ISO currency code, e.g. <code>USD</code> or <code>EUR</code>. It must be a <a target="_blank" href="https://stripe.com/docs/currencies">Stripe-supported currency</a>',
displayOptions: {
show: {
resource: [
'source',
],
operation: [
'create',
],
},
},
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'source',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Metadata',
name: 'metadata',
type: 'fixedCollection',
placeholder: 'Add Metadata Item',
description: 'Set of key-value pairs to attach to the source to create',
default: {},
typeOptions: {
multipleValues: true,
},
options: [
{
displayName: 'Metadata Properties',
name: 'metadataProperties',
values: [
{
displayName: 'Key',
name: 'key',
type: 'string',
default: '',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Statement Descriptor',
name: 'statement_descriptor',
type: 'string',
default: '',
description: 'Arbitrary text to display on the customer\'s statement',
},
],
},
// ----------------------------------
// source: delete
// ----------------------------------
{
displayName: 'Customer ID',
name: 'customerId',
type: 'string',
required: true,
default: '',
description: 'ID of the customer whose source to delete',
displayOptions: {
show: {
resource: [
'source',
],
operation: [
'delete',
],
},
},
},
{
displayName: 'Source ID',
name: 'sourceId',
type: 'string',
required: true,
default: '',
description: 'ID of the source to delete',
displayOptions: {
show: {
resource: [
'source',
],
operation: [
'delete',
],
},
},
},
// ----------------------------------
// source: get
// ----------------------------------
{
displayName: 'Source ID',
name: 'sourceId',
type: 'string',
required: true,
default: '',
description: 'ID of the source to retrieve',
displayOptions: {
show: {
resource: [
'source',
],
operation: [
'get',
],
},
},
},
] as INodeProperties[];

View file

@ -0,0 +1,130 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const tokenOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
default: 'create',
description: 'Operation to perform',
options: [
{
name: 'Create',
value: 'create',
description: 'Create a token',
},
],
displayOptions: {
show: {
resource: [
'token',
],
},
},
},
] as INodeProperties[];
export const tokenFields = [
// ----------------------------------
// token: create
// ----------------------------------
{
displayName: 'Type',
name: 'type',
type: 'options',
required: true,
default: 'cardToken',
description: 'Type of token to create',
options: [
{
name: 'Card Token',
value: 'cardToken',
},
],
},
{
displayName: 'Card Number',
name: 'number',
type: 'string',
displayOptions: {
show: {
resource: [
'token',
],
operation: [
'create',
],
type: [
'cardToken'
],
},
},
placeholder: '4242424242424242',
default: '',
},
{
displayName: 'CVC',
name: 'cvc',
type: 'string',
displayOptions: {
show: {
resource: [
'token',
],
operation: [
'create',
],
type: [
'cardToken'
],
},
},
default: '',
placeholder: '314',
description: 'Security code printed on the back of the card',
},
{
displayName: 'Expiration Month',
description: 'Number of the month when the card will expire',
name: 'expirationMonth',
type: 'string',
displayOptions: {
show: {
resource: [
'token',
],
operation: [
'create',
],
type: [
'cardToken'
],
},
},
default: '',
placeholder: '10',
},
{
displayName: 'Expiration Year',
description: 'Year when the card will expire',
name: 'expirationYear',
type: 'string',
displayOptions: {
show: {
resource: [
'token',
],
operation: [
'create',
],
type: [
'cardToken'
],
},
},
default: '',
placeholder: '2022',
},
] as INodeProperties[];

View file

@ -0,0 +1,7 @@
export * from './BalanceDescription';
export * from './CustomerCardDescription';
export * from './ChargeDescription';
export * from './CouponDescription';
export * from './CustomerDescription';
export * from './SourceDescription';
export * from './TokenDescription';

View file

@ -2,7 +2,23 @@ import {
IExecuteFunctions, IExecuteFunctions,
IHookFunctions, IHookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { NodeApiError, NodeOperationError, } from 'n8n-workflow';
import {
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
import {
flow,
isEmpty,
omit,
} from 'lodash';
import {
IDataObject,
ILoadOptionsFunctions,
INodePropertyOptions,
} from 'n8n-workflow';
/** /**
* Make an API request to Stripe * Make an API request to Stripe
@ -13,7 +29,13 @@ import { NodeApiError, NodeOperationError, } from 'n8n-workflow';
* @param {object} body * @param {object} body
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
export async function stripeApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: object, query?: object): Promise<any> { // tslint:disable-line:no-any export async function stripeApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
body: object,
query?: object,
) {
const credentials = this.getCredentials('stripeApi'); const credentials = this.getCredentials('stripeApi');
if (credentials === undefined) { if (credentials === undefined) {
throw new NodeOperationError(this.getNode(), 'No credentials got returned!'); throw new NodeOperationError(this.getNode(), 'No credentials got returned!');
@ -30,9 +52,121 @@ export async function stripeApiRequest(this: IHookFunctions | IExecuteFunctions,
json: true, json: true,
}; };
if (options.qs && Object.keys(options.qs).length === 0) {
delete options.qs;
}
try { try {
return await this.helpers.request(options); return await this.helpers.request!.call(this, options);
} catch (error) { } catch (error) {
throw new NodeApiError(this.getNode(), error); throw new NodeApiError(this.getNode(), error);
} }
} }
/**
* Make n8n's charge fields compliant with the Stripe API request object.
*/
export const adjustChargeFields = flow([
adjustShipping,
adjustMetadata,
]);
/**
* Make n8n's customer fields compliant with the Stripe API request object.
*/
export const adjustCustomerFields = flow([
adjustShipping,
adjustAddress,
adjustMetadata,
]);
/**
* Convert n8n's address object into a Stripe API request shipping object.
*/
function adjustAddress(
addressFields: { address: { details: IDataObject } },
) {
if (!addressFields.address) return addressFields;
return {
...omit(addressFields, ['address']),
address: addressFields.address.details,
};
}
/**
* Convert n8n's `fixedCollection` metadata object into a Stripe API request metadata object.
*/
export function adjustMetadata(
fields: { metadata?: { metadataProperties: Array<{ key: string; value: string }> } },
) {
if (!fields.metadata || isEmpty(fields.metadata)) return fields;
let adjustedMetadata = {};
fields.metadata.metadataProperties.forEach(pair => {
adjustedMetadata = { ...adjustedMetadata, ...pair };
});
return {
...omit(fields, ['metadata']),
metadata: adjustedMetadata,
};
}
/**
* Convert n8n's shipping object into a Stripe API request shipping object.
*/
function adjustShipping(
shippingFields: { shipping?: { shippingProperties: Array<{ address: { details: IDataObject }; name: string }> } },
) {
const shippingProperties = shippingFields.shipping?.shippingProperties[0];
if (!shippingProperties?.address || isEmpty(shippingProperties.address)) return shippingFields;
return {
...omit(shippingFields, ['shipping']),
shipping: {
...omit(shippingProperties, ['address']),
address: shippingProperties.address.details,
},
};
}
/**
* Load a resource so it can be selected by name from a dropdown.
*/
export async function loadResource(
this: ILoadOptionsFunctions,
resource: 'charge' | 'customer' | 'source',
): Promise<INodePropertyOptions[]> {
const responseData = await stripeApiRequest.call(this, 'GET', `/${resource}s`, {}, {});
return responseData.data.map(({ name, id }: { name: string, id: string }) => ({
name,
value: id,
}));
}
/**
* Handles a Stripe listing by returning all items or up to a limit.
*/
export async function handleListing(
this: IExecuteFunctions,
resource: string,
qs: IDataObject = {},
) {
let responseData;
responseData = await stripeApiRequest.call(this, 'GET', `/${resource}s`, qs, {});
responseData = responseData.data;
const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
if (!returnAll) {
const limit = this.getNodeParameter('limit', 0) as number;
responseData = responseData.slice(0, limit);
}
return responseData;
}

View file

@ -1 +1,22 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="54 -80 360 360"><style>.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#635bff}</style><path class="st0" d="M414 113.4c0-25.6-12.4-45.8-36.1-45.8-23.8 0-38.2 20.2-38.2 45.6 0 30.1 17 45.3 41.4 45.3 11.9 0 20.9-2.7 27.7-6.5v-20c-6.8 3.4-14.6 5.5-24.5 5.5-9.7 0-18.3-3.4-19.4-15.2h48.9c0-1.3.2-6.5.2-8.9zm-49.4-9.5c0-11.3 6.9-16 13.2-16 6.1 0 12.6 4.7 12.6 16h-25.8zM301.1 67.6c-9.8 0-16.1 4.6-19.6 7.8l-1.3-6.2h-22v116.6l25-5.3.1-28.3c3.6 2.6 8.9 6.3 17.7 6.3 17.9 0 34.2-14.4 34.2-46.1-.1-29-16.6-44.8-34.1-44.8zm-6 68.9c-5.9 0-9.4-2.1-11.8-4.7l-.1-37.1c2.6-2.9 6.2-4.9 11.9-4.9 9.1 0 15.4 10.2 15.4 23.3 0 13.4-6.2 23.4-15.4 23.4zM223.8 61.7l25.1-5.4V36l-25.1 5.3zM223.8 69.3h25.1v87.5h-25.1zM196.9 76.7l-1.6-7.4h-21.6v87.5h25V97.5c5.9-7.7 15.9-6.3 19-5.2v-23c-3.2-1.2-14.9-3.4-20.8 7.4zM146.9 47.6l-24.4 5.2-.1 80.1c0 14.8 11.1 25.7 25.9 25.7 8.2 0 14.2-1.5 17.5-3.3V135c-3.2 1.3-19 5.9-19-8.9V90.6h19V69.3h-19l.1-21.7zM79.3 94.7c0-3.9 3.2-5.4 8.5-5.4 7.6 0 17.2 2.3 24.8 6.4V72.2c-8.3-3.3-16.5-4.6-24.8-4.6C67.5 67.6 54 78.2 54 95.9c0 27.6 38 23.2 38 35.1 0 4.6-4 6.1-9.6 6.1-8.3 0-18.9-3.4-27.3-8v23.8c9.3 4 18.7 5.7 27.3 5.7 20.8 0 35.1-10.3 35.1-28.2-.1-29.8-38.2-24.5-38.2-35.7z"/></svg> <?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="54 -80 360 360">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#635BFF;}
</style>
<g>
<path class="st0" d="M414,113.4c0-25.6-12.4-45.8-36.1-45.8c-23.8,0-38.2,20.2-38.2,45.6c0,30.1,17,45.3,41.4,45.3
c11.9,0,20.9-2.7,27.7-6.5v-20c-6.8,3.4-14.6,5.5-24.5,5.5c-9.7,0-18.3-3.4-19.4-15.2h48.9C413.8,121,414,115.8,414,113.4z
M364.6,103.9c0-11.3,6.9-16,13.2-16c6.1,0,12.6,4.7,12.6,16H364.6z"/>
<path class="st0" d="M301.1,67.6c-9.8,0-16.1,4.6-19.6,7.8l-1.3-6.2h-22v116.6l25-5.3l0.1-28.3c3.6,2.6,8.9,6.3,17.7,6.3
c17.9,0,34.2-14.4,34.2-46.1C335.1,83.4,318.6,67.6,301.1,67.6z M295.1,136.5c-5.9,0-9.4-2.1-11.8-4.7l-0.1-37.1
c2.6-2.9,6.2-4.9,11.9-4.9c9.1,0,15.4,10.2,15.4,23.3C310.5,126.5,304.3,136.5,295.1,136.5z"/>
<polygon class="st0" points="223.8,61.7 248.9,56.3 248.9,36 223.8,41.3 "/>
<rect x="223.8" y="69.3" class="st0" width="25.1" height="87.5"/>
<path class="st0" d="M196.9,76.7l-1.6-7.4h-21.6v87.5h25V97.5c5.9-7.7,15.9-6.3,19-5.2v-23C214.5,68.1,202.8,65.9,196.9,76.7z"/>
<path class="st0" d="M146.9,47.6l-24.4,5.2l-0.1,80.1c0,14.8,11.1,25.7,25.9,25.7c8.2,0,14.2-1.5,17.5-3.3V135
c-3.2,1.3-19,5.9-19-8.9V90.6h19V69.3h-19L146.9,47.6z"/>
<path class="st0" d="M79.3,94.7c0-3.9,3.2-5.4,8.5-5.4c7.6,0,17.2,2.3,24.8,6.4V72.2c-8.3-3.3-16.5-4.6-24.8-4.6
C67.5,67.6,54,78.2,54,95.9c0,27.6,38,23.2,38,35.1c0,4.6-4,6.1-9.6,6.1c-8.3,0-18.9-3.4-27.3-8v23.8c9.3,4,18.7,5.7,27.3,5.7
c20.8,0,35.1-10.3,35.1-28.2C117.4,100.6,79.3,105.9,79.3,94.7z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -530,6 +530,7 @@
"dist/nodes/Strapi/Strapi.node.js", "dist/nodes/Strapi/Strapi.node.js",
"dist/nodes/Strava/Strava.node.js", "dist/nodes/Strava/Strava.node.js",
"dist/nodes/Strava/StravaTrigger.node.js", "dist/nodes/Strava/StravaTrigger.node.js",
"dist/nodes/Stripe/Stripe.node.js",
"dist/nodes/Stripe/StripeTrigger.node.js", "dist/nodes/Stripe/StripeTrigger.node.js",
"dist/nodes/Switch.node.js", "dist/nodes/Switch.node.js",
"dist/nodes/Salesmate/Salesmate.node.js", "dist/nodes/Salesmate/Salesmate.node.js",