pull:初次提交

This commit is contained in:
Yep_Q
2025-09-08 04:48:28 +08:00
parent 5c0619656d
commit f64f498365
11751 changed files with 1953723 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
{
"node": "n8n-nodes-base.chargebee",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Finance & Accounting"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/chargebee/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.chargebee/"
}
]
}
}

View File

@@ -0,0 +1,641 @@
import type {
IExecuteFunctions,
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
JsonObject,
NodeParameterValue,
IRequestOptions,
IHttpRequestMethods,
} from 'n8n-workflow';
import { NodeApiError, NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
interface CustomProperty {
name: string;
value: string;
}
interface FilterValue {
operation: string;
value: NodeParameterValue;
}
interface FilterValues {
[key: string]: FilterValue[];
}
export class Chargebee implements INodeType {
description: INodeTypeDescription = {
displayName: 'Chargebee',
name: 'chargebee',
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
icon: 'file:chargebee.png',
group: ['input'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Retrieve data from Chargebee API',
defaults: {
name: 'Chargebee',
},
usableAsTool: true,
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
credentials: [
{
name: 'chargebeeApi',
required: true,
},
],
properties: [
{
displayName: 'Resource',
name: 'resource',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Customer',
value: 'customer',
},
{
name: 'Invoice',
value: 'invoice',
},
{
name: 'Subscription',
value: 'subscription',
},
],
default: 'invoice',
},
// ----------------------------------
// customer
// ----------------------------------
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['customer'],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a customer',
action: 'Create a customer',
},
],
default: 'create',
},
// ----------------------------------
// customer:create
// ----------------------------------
{
displayName: 'Properties',
name: 'properties',
type: 'collection',
displayOptions: {
show: {
operation: ['create'],
resource: ['customer'],
},
},
default: {},
description: 'Properties to set on the new user',
placeholder: 'Add Property',
options: [
{
displayName: 'User ID',
name: 'id',
type: 'string',
default: '',
description: 'ID for the new customer. If not given, this will be auto-generated.',
},
{
displayName: 'First Name',
name: 'first_name',
type: 'string',
default: '',
description: 'The first name of the customer',
},
{
displayName: 'Last Name',
name: 'last_name',
type: 'string',
default: '',
description: 'The last name of the customer',
},
{
displayName: 'Email',
name: 'email',
type: 'string',
placeholder: 'name@email.com',
default: '',
description: 'The email address of the customer',
},
{
displayName: 'Phone',
name: 'phone',
type: 'string',
default: '',
description: 'The phone number of the customer',
},
{
displayName: 'Company',
name: 'company',
type: 'string',
default: '',
description: 'The company of the customer',
},
{
displayName: 'Custom Properties',
name: 'customProperties',
placeholder: 'Add Custom Property',
description: 'Adds a custom property to set also values which have not been predefined',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
default: {},
options: [
{
name: 'property',
displayName: 'Property',
values: [
{
displayName: 'Property Name',
name: 'name',
type: 'string',
default: '',
description: 'Name of the property to set',
},
{
displayName: 'Property Value',
name: 'value',
type: 'string',
default: '',
description: 'Value of the property to set',
},
],
},
],
},
],
},
// ----------------------------------
// invoice
// ----------------------------------
{
displayName: 'Operation',
name: 'operation',
default: 'list',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['invoice'],
},
},
options: [
{
name: 'List',
value: 'list',
description: 'Return the invoices',
action: 'List an invoice',
},
{
name: 'PDF Invoice URL',
value: 'pdfUrl',
description: 'Get URL for the invoice PDF',
action: 'Get URL for the invoice PDF',
},
],
},
// ----------------------------------
// invoice:list
// ----------------------------------
{
displayName: 'Max Results',
name: 'maxResults',
type: 'number',
typeOptions: {
minValue: 1,
maxValue: 100,
},
default: 10,
displayOptions: {
show: {
operation: ['list'],
resource: ['invoice'],
},
},
description: 'Max. amount of results to return(< 100).',
},
{
displayName: 'Filters',
name: 'filters',
placeholder: 'Add Filter',
description: 'Filter for invoices',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
default: {},
displayOptions: {
show: {
operation: ['list'],
resource: ['invoice'],
},
},
options: [
{
name: 'date',
displayName: 'Invoice Date',
values: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Is',
value: 'is',
},
{
name: 'Is Not',
value: 'is_not',
},
{
name: 'After',
value: 'after',
},
{
name: 'Before',
value: 'before',
},
],
default: 'after',
description: 'Operation to decide where the data should be mapped to',
},
{
displayName: 'Date',
name: 'value',
type: 'dateTime',
default: '',
description: 'Query date',
},
],
},
{
name: 'total',
displayName: 'Invoice Amount',
values: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{
name: 'Greater Equal Than',
value: 'gte',
},
{
name: 'Greater Than',
value: 'gt',
},
{
name: 'Is',
value: 'is',
},
{
name: 'Is Not',
value: 'is_not',
},
{
name: 'Less Equal Than',
value: 'lte',
},
{
name: 'Less Than',
value: 'lt',
},
],
default: 'gt',
description: 'Operation to decide where the data should be mapped to',
},
{
displayName: 'Amount',
name: 'value',
type: 'number',
typeOptions: {
numberPrecision: 2,
},
default: 0,
description: 'Query amount',
},
],
},
],
},
// ----------------------------------
// invoice:pdfUrl
// ----------------------------------
{
displayName: 'Invoice ID',
name: 'invoiceId',
description: 'The ID of the invoice to get',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: ['pdfUrl'],
resource: ['invoice'],
},
},
},
// ----------------------------------
// subscription
// ----------------------------------
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
displayOptions: {
show: {
resource: ['subscription'],
},
},
options: [
{
name: 'Cancel',
value: 'cancel',
description: 'Cancel a subscription',
action: 'Cancel a subscription',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a subscription',
action: 'Delete a subscription',
},
],
default: 'delete',
},
// ----------------------------------
// subscription:cancel
// ----------------------------------
{
displayName: 'Subscription ID',
name: 'subscriptionId',
description: 'The ID of the subscription to cancel',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: ['cancel'],
resource: ['subscription'],
},
},
},
{
displayName: 'Schedule End of Term',
name: 'endOfTerm',
type: 'boolean',
default: false,
displayOptions: {
show: {
operation: ['cancel'],
resource: ['subscription'],
},
},
description:
'Whether it will not cancel it directly in will instead schedule the cancelation for the end of the term',
},
// ----------------------------------
// subscription:delete
// ----------------------------------
{
displayName: 'Subscription ID',
name: 'subscriptionId',
description: 'The ID of the subscription to delete',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: ['delete'],
resource: ['subscription'],
},
},
},
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: INodeExecutionData[] = [];
const credentials = await this.getCredentials('chargebeeApi');
const baseUrl = `https://${credentials.accountName}.chargebee.com/api/v2`;
// For Post
let body: IDataObject;
// For Query string
let qs: IDataObject;
for (let i = 0; i < items.length; i++) {
try {
const resource = this.getNodeParameter('resource', i);
const operation = this.getNodeParameter('operation', i);
let requestMethod: IHttpRequestMethods = 'GET';
let endpoint = '';
body = {};
qs = {};
if (resource === 'customer') {
if (operation === 'create') {
// ----------------------------------
// create
// ----------------------------------
requestMethod = 'POST';
const properties = this.getNodeParameter('properties', i, {}) as IDataObject;
for (const key of Object.keys(properties)) {
if (
key === 'customProperties' &&
(properties.customProperties as IDataObject).property !== undefined
) {
for (const customProperty of (properties.customProperties as IDataObject)
.property! as CustomProperty[]) {
qs[customProperty.name] = customProperty.value;
}
} else {
qs[key] = properties[key];
}
}
endpoint = 'customers';
} else {
throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known!`,
{ itemIndex: i },
);
}
} else if (resource === 'invoice') {
if (operation === 'list') {
// ----------------------------------
// list
// ----------------------------------
endpoint = 'invoices';
// TODO: Make also sorting configurable
qs['sort_by[desc]'] = 'date';
qs.limit = this.getNodeParameter('maxResults', i, {});
const setFilters: FilterValues = this.getNodeParameter(
'filters',
i,
{},
) as unknown as FilterValues;
let filter: FilterValue;
let value: NodeParameterValue;
for (const filterProperty of Object.keys(setFilters)) {
for (filter of setFilters[filterProperty]) {
value = filter.value;
if (filterProperty === 'date') {
value = Math.floor(new Date(value as string).getTime() / 1000);
}
qs[`${filterProperty}[${filter.operation}]`] = value;
}
}
} else if (operation === 'pdfUrl') {
// ----------------------------------
// pdfUrl
// ----------------------------------
requestMethod = 'POST';
const invoiceId = this.getNodeParameter('invoiceId', i) as string;
endpoint = `invoices/${invoiceId.trim()}/pdf`;
} else {
throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known!`,
{ itemIndex: i },
);
}
} else if (resource === 'subscription') {
if (operation === 'cancel') {
// ----------------------------------
// cancel
// ----------------------------------
requestMethod = 'POST';
const subscriptionId = this.getNodeParameter('subscriptionId', i, '') as string;
body.end_of_term = this.getNodeParameter('endOfTerm', i, false) as boolean;
endpoint = `subscriptions/${subscriptionId.trim()}/cancel`;
} else if (operation === 'delete') {
// ----------------------------------
// delete
// ----------------------------------
requestMethod = 'POST';
const subscriptionId = this.getNodeParameter('subscriptionId', i, '') as string;
endpoint = `subscriptions/${subscriptionId.trim()}/delete`;
} else {
throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known!`,
{ itemIndex: i },
);
}
} else {
throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`, {
itemIndex: i,
});
}
const options = {
method: requestMethod,
body,
qs,
uri: `${baseUrl}/${endpoint}`,
auth: {
user: credentials.apiKey as string,
pass: '',
},
json: true,
} satisfies IRequestOptions;
let responseData;
try {
responseData = await this.helpers.request(options);
} catch (error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
if (resource === 'invoice' && operation === 'list') {
responseData.list.forEach((data: IDataObject) => {
responseData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ ...(data.invoice as IDataObject) }),
{ itemData: { item: i } },
);
returnData.push(...responseData);
});
} else if (resource === 'invoice' && operation === 'pdfUrl') {
const data: IDataObject = {};
Object.assign(data, items[i].json);
data.pdfUrl = responseData.download.download_url;
responseData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray({ ...data }),
{ itemData: { item: i } },
);
returnData.push(...responseData);
} else {
responseData = this.helpers.constructExecutionMetaData(
this.helpers.returnJsonArray(responseData as IDataObject[]),
{ itemData: { item: i } },
);
returnData.push(...responseData);
}
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.message, json: {}, itemIndex: i });
continue;
}
throw error;
}
}
return [returnData];
}
}

View File

@@ -0,0 +1,18 @@
{
"node": "n8n-nodes-base.chargebeeTrigger",
"nodeVersion": "1.0",
"codexVersion": "1.0",
"categories": ["Finance & Accounting"],
"resources": {
"credentialDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/credentials/chargebee/"
}
],
"primaryDocumentation": [
{
"url": "https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.chargebeetrigger/"
}
]
}
}

View File

@@ -0,0 +1,247 @@
import {
type IDataObject,
type IWebhookFunctions,
type INodeType,
type INodeTypeDescription,
type IWebhookResponseData,
NodeConnectionTypes,
} from 'n8n-workflow';
export class ChargebeeTrigger implements INodeType {
description: INodeTypeDescription = {
displayName: 'Chargebee Trigger',
name: 'chargebeeTrigger',
// eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg
icon: 'file:chargebee.png',
group: ['trigger'],
version: 1,
description: 'Starts the workflow when Chargebee events occur',
defaults: {
name: 'Chargebee Trigger',
},
inputs: [],
outputs: [NodeConnectionTypes.Main],
webhooks: [
{
name: 'default',
httpMethod: 'POST',
responseMode: 'onReceived',
path: 'webhook',
},
],
properties: [
{
displayName: 'Events',
name: 'events',
type: 'multiOptions',
required: true,
default: [],
options: [
{
name: '*',
value: '*',
description: 'Any time any event is triggered (Wildcard Event)',
},
{
name: 'Card Added',
value: 'card_added',
description: 'Triggered when a card is added for a customer',
},
{
name: 'Card Deleted',
value: 'card_deleted',
description: 'Triggered when a card is deleted for a customer',
},
{
name: 'Card Expired',
value: 'card_expired',
description: 'Triggered when the card for a customer has expired',
},
{
name: 'Card Expiring',
value: 'card_expiring',
description:
"Triggered when the customer's credit card is expiring soon.Triggered 30 days before the expiry date",
},
{
name: 'Card Updated',
value: 'card_updated',
description: 'Triggered when the card is updated for a customer',
},
{
name: 'Customer Changed',
value: 'customer_changed',
description: 'Triggered when a customer is changed',
},
{
name: 'Customer Created',
value: 'customer_created',
description: 'Triggered when a customer is created',
},
{
name: 'Customer Deleted',
value: 'customer_deleted',
description: 'Triggered when a customer is deleted',
},
{
name: 'Invoice Created',
value: 'invoice_created',
description:
"Event triggered (in the case of metered billing) when a 'Pending' invoice is created that has usage related charges or line items to be added, before being closed. This is triggered only when the “Notify for Pending Invoices” option is enabled.",
},
{
name: 'Invoice Deleted',
value: 'invoice_deleted',
description: 'Event triggered when an invoice is deleted',
},
{
name: 'Invoice Generated',
value: 'invoice_generated',
description:
"Event triggered when a new invoice is generated. In case of metered billing, this event is triggered when a 'Pending' invoice is closed.",
},
{
name: 'Invoice Updated',
value: 'invoice_updated',
description:
'Triggered when the invoices shipping/billing address is updated, if the invoice is voided, or when the amount due is modified due to payments applied/removed',
},
{
name: 'Payment Failed',
value: 'payment_failed',
description: "Triggered when attempt to charge customer's credit card fails",
},
{
name: 'Payment Initiated',
value: 'payment_initiated',
description: 'Triggered when a payment is initiated via direct debit',
},
{
name: 'Payment Refunded',
value: 'payment_refunded',
description: 'Triggered when a payment refund is made',
},
{
name: 'Payment Succeeded',
value: 'payment_succeeded',
description: 'Triggered when the payment is successfully collected',
},
{
name: 'Refund Initiated',
value: 'refund_initiated',
description: 'Triggered when a refund is initiated via direct debit',
},
{
name: 'Subscription Activated',
value: 'subscription_activated',
description:
"Triggered after the subscription has been moved from 'Trial' to 'Active' state",
},
{
name: 'Subscription Cancellation Scheduled',
value: 'subscription_cancellation_scheduled',
description:
'Triggered when subscription is scheduled to cancel at end of current term',
},
{
name: 'Subscription Cancelled',
value: 'subscription_cancelled',
description:
"Triggered when the subscription is cancelled. If it is cancelled due to non payment or because the card details are not present, the subscription will have the possible reason as 'cancel_reason'.",
},
{
name: 'Subscription Cancelling',
value: 'subscription_cancelling',
description: 'Triggered 6 days prior to the scheduled cancellation date',
},
{
name: 'Subscription Changed',
value: 'subscription_changed',
description: "Triggered when the subscription's recurring items are changed",
},
{
name: 'Subscription Created',
value: 'subscription_created',
description: 'Triggered when a new subscription is created',
},
{
name: 'Subscription Deleted',
value: 'subscription_deleted',
description: 'Triggered when a subscription is deleted',
},
{
name: 'Subscription Reactivated',
value: 'subscription_reactivated',
description:
"Triggered when the subscription is moved from cancelled state to 'Active' or 'Trial' state",
},
{
name: 'Subscription Renewal Reminder',
value: 'subscription_renewal_reminder',
description: "Triggered 3 days before each subscription's renewal",
},
{
name: 'Subscription Renewed',
value: 'subscription_renewed',
description: 'Triggered when the subscription is renewed from the current term',
},
{
name: 'Subscription Scheduled Cancellation Removed',
value: 'subscription_scheduled_cancellation_removed',
description: 'Triggered when scheduled cancellation is removed for the subscription',
},
{
name: 'Subscription Shipping Address Updated',
value: 'subscription_shipping_address_updated',
description: 'Triggered when shipping address is added or updated for a subscription',
},
{
name: 'Subscription Started',
value: 'subscription_started',
description: "Triggered when a 'future' subscription gets started",
},
{
name: 'Subscription Trial Ending',
value: 'subscription_trial_ending',
description: "Triggered 6 days prior to the trial period's end date",
},
{
name: 'Transaction Created',
value: 'transaction_created',
description: 'Triggered when a transaction is recorded',
},
{
name: 'Transaction Deleted',
value: 'transaction_deleted',
description: 'Triggered when a transaction is deleted',
},
{
name: 'Transaction Updated',
value: 'transaction_updated',
description:
'Triggered when a transaction is updated. E.g. (1) When a transaction is removed, (2) or when an excess payment is applied on an invoice, (3) or when amount_capturable gets updated.',
},
],
},
],
};
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const bodyData = this.getBodyData();
const req = this.getRequestObject();
const events = this.getNodeParameter('events', []) as string[];
const eventType = bodyData.event_type as string | undefined;
if (eventType === undefined || (!events.includes('*') && !events.includes(eventType))) {
// If not eventType is defined or when one is defined but we are not
// listening to it do not start the workflow.
return {};
}
return {
workflowData: [this.helpers.returnJsonArray(req.body as IDataObject[])],
};
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B