n8n-nodes-didar-crm 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025
3
+ Copyright (c) 2025 Ali Mozayyani
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,45 +1,138 @@
1
1
  # n8n-nodes-didar-crm
2
2
 
3
- Community node for [n8n](https://n8n.io) to integrate with [Didar CRM](https://app.didar.me).
3
+ Custom **n8n nodes** for integrating with **Didar CRM**.
4
+ This package provides actions and triggers to automate workflows with your Didar CRM account.
4
5
 
5
- This node allows you to:
6
- - **Trigger workflows** from Didar CRM webhooks
7
- - **Create Deals** with all required fields (Title, Owner, Pipeline, Stage, Person, Company, Status)
8
- - Use **Additional Fields** like description, source, lost reason, price, currency, custom fields, etc.
9
- - Select Owner, Pipeline, and Stage from dropdowns (or manually enter IDs).
6
+ ---
7
+
8
+ ## Features
9
+
10
+ * **Trigger**
11
+
12
+ * Receive webhook events from Didar CRM (entity changes, updates, deletions, etc.)
13
+
14
+ * **Deal**
15
+
16
+ * Create a deal
17
+ * Update a deal (by Id)
18
+ * Get deal details (by Id)
19
+
20
+ * **Person (Contact)**
21
+
22
+ * Create a person
23
+ * Update a person (by Id)
24
+ * Get person details (by Id)
25
+
26
+ * **Common**
27
+
28
+ * Dropdown selectors for Pipelines, Pipeline Stages, Owners (Users)
29
+ * Manual ID input option for each dropdown field
30
+ * Support for additional fields like Source, Lost Reason, Visibility Type, Custom Fields, etc.
31
+ * Proper handling of default values (zero-guid where needed)
32
+ * Webhook trigger enforces POST requests
33
+
34
+ ---
35
+
36
+ ## 📦 Installation
37
+
38
+ ```bash
39
+ npm install n8n-nodes-didar-crm
40
+ ```
10
41
 
11
- More operations (update deal, get deal, person/company operations) will be added soon.
42
+ Then, place the module inside your n8n custom directory (usually `~/.n8n/custom/`) and restart n8n.
12
43
 
13
44
  ---
14
45
 
15
- ## ⚙️ Installation
46
+ ## Usage
47
+
48
+ ### 1. Trigger node
49
+
50
+ Add the **Didar CRM Trigger** node to your workflow.
51
+
52
+ * It exposes a webhook URL in n8n.
53
+ * Only **POST** requests are accepted.
54
+ * Returns payload structured into:
16
55
 
17
- In your n8n instance, go to:
56
+ ```json
57
+ {
58
+ "data": { ... },
59
+ "changes": [ ... ],
60
+ "meta": { ... },
61
+ "raw": { ... },
62
+ "receivedAt": "timestamp"
63
+ }
64
+ ```
18
65
 
19
- `Settings > Community Nodes > Install`
66
+ ### 2. Deal operations
20
67
 
21
- and enter: n8n-nodes-didar-crm
68
+ * **Create Deal** → required fields: `Title`, `OwnerId`, `PipelineId`, `PipelineStageId`, `PersonId`, `CompanyId`, `Status`
69
+ * **Update Deal** → same as Create, plus required `Id`
70
+ * **Get Deal** → requires `Id`
22
71
 
72
+ ### 3. Person (Contact) operations
73
+
74
+ * **Create Person** → required fields: `LastName`, `OwnerId`
75
+ * **Update Person** → same as Create, plus required `Id`
76
+ * **Get Person** → requires `Id`
23
77
 
24
78
  ---
25
79
 
26
- ## 🔑 Authentication
80
+ ## 🔑 Credentials
81
+
82
+ A new credential type **Didar API** is provided.
83
+
84
+ * You must set your **API Key** and (if required) authentication cookies.
85
+ * Used across all operations.
27
86
 
28
- Currently the node uses an **API Key** (query param `?apikey=...`) for authentication.
29
- You need to generate and provide your API key from your Didar CRM account.
87
+ ---
88
+
89
+ ## 📂 Project structure
90
+
91
+ ```
92
+ n8n-nodes-didar-crm/
93
+ │── package.json
94
+ │── README.md
95
+ │── LICENSE
96
+ │── nodes/
97
+ │ ├── DidarCrm.node.ts # Main entry for resource & operation switch
98
+ │ ├── DidarCrmTrigger.node.ts # Trigger node
99
+ │ └── deal/ # Deal operations
100
+ │ ├── create.operation.ts
101
+ │ ├── update.operation.ts
102
+ │ └── get.operation.ts
103
+ │ └── person/ # Person operations
104
+ │ ├── create.operation.ts
105
+ │ ├── update.operation.ts
106
+ │ └── get.operation.ts
107
+ │── lib/
108
+ ├── http.ts # Request helper
109
+ └── loadOptions.ts # Dropdown population (pipelines, stages, users)
110
+ ```
30
111
 
31
112
  ---
32
113
 
33
- ## 🧪 Development
114
+ ## 🛠 Development
34
115
 
35
- Clone repo and build:
116
+ 1. Clone the repo
117
+ 2. Install dependencies:
36
118
 
37
- ```bash
38
- npm install
39
- npm run build
119
+ ```bash
120
+ npm install
121
+ ```
122
+ 3. Build:
123
+
124
+ ```bash
125
+ npm run build
126
+ ```
127
+ 4. Link into your n8n custom directory and restart n8n:
128
+
129
+ ```bash
130
+ npm link
131
+ n8n start
132
+ ```
133
+
134
+ ---
40
135
 
41
- For local testing in n8n:
136
+ ## 📜 License
42
137
 
43
- # inside n8n custom folder
44
- cd ~/.n8n/custom
45
- npm install /path/to/n8n-nodes-didar-crm
138
+ MIT License see [LICENSE](./LICENSE) for details.
@@ -92,6 +92,8 @@ class DidarCrm {
92
92
  displayOptions: { show: { resource: ['person'] } },
93
93
  options: [
94
94
  { name: 'Create', value: 'create', action: 'Create a person' },
95
+ { name: 'Update', value: 'update', action: 'Update a person by Id' },
96
+ { name: 'Get', value: 'get', action: 'Get a person by Id' },
95
97
  ],
96
98
  default: 'create',
97
99
  description: 'Select the action to perform on the selected resource.',
@@ -102,6 +104,8 @@ class DidarCrm {
102
104
  ...deal_1.dealGetProperties,
103
105
  // Person properties (imported)
104
106
  ...person_1.personCreateProperties,
107
+ ...person_1.personUpdateProperties,
108
+ ...person_1.personGetProperties,
105
109
  ],
106
110
  };
107
111
  }
@@ -130,6 +134,14 @@ class DidarCrm {
130
134
  await PersonOps.personCreate.call(this, i, returnData);
131
135
  continue;
132
136
  }
137
+ if (operation === 'update') {
138
+ await PersonOps.personUpdate.call(this, i, returnData);
139
+ continue;
140
+ }
141
+ if (operation === 'get') {
142
+ await PersonOps.personGet.call(this, i, returnData);
143
+ continue;
144
+ }
133
145
  }
134
146
  }
135
147
  return [returnData];
@@ -0,0 +1,2 @@
1
+ import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
2
+ export declare function personGet(this: IExecuteFunctions, i: number, returnData: INodeExecutionData[]): Promise<void>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.personGet = personGet;
4
+ const http_1 = require("../../lib/http");
5
+ async function personGet(i, returnData) {
6
+ const personId = this.getNodeParameter('personId', i, '');
7
+ if (!personId)
8
+ throw new Error('Person Id is required.');
9
+ const resp = await (0, http_1.didarRequest)(this, i, {
10
+ method: 'POST',
11
+ path: '/api/contact/GetContactDetail',
12
+ body: { Id: personId },
13
+ });
14
+ returnData.push({ json: resp });
15
+ }
@@ -0,0 +1,2 @@
1
+ import { INodeProperties } from 'n8n-workflow';
2
+ export declare const personGetProperties: INodeProperties[];
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.personGetProperties = void 0;
4
+ exports.personGetProperties = [
5
+ {
6
+ displayName: 'Person Id',
7
+ name: 'personId',
8
+ type: 'string',
9
+ default: '',
10
+ required: true,
11
+ displayOptions: { show: { resource: ['person'], operation: ['get'] } },
12
+ description: 'Person Id to fetch (required).',
13
+ },
14
+ ];
@@ -1,2 +1,6 @@
1
1
  export { personCreate } from './create.operation';
2
+ export { personUpdate } from './update.operation';
3
+ export { personGet } from './get.operation';
2
4
  export { personCreateProperties } from './create.properties';
5
+ export { personUpdateProperties } from './update.properties';
6
+ export { personGetProperties } from './get.properties';
@@ -1,8 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.personCreateProperties = exports.personCreate = void 0;
4
- // src/nodes/person/index.ts
3
+ exports.personGetProperties = exports.personUpdateProperties = exports.personCreateProperties = exports.personGet = exports.personUpdate = exports.personCreate = void 0;
5
4
  var create_operation_1 = require("./create.operation");
6
5
  Object.defineProperty(exports, "personCreate", { enumerable: true, get: function () { return create_operation_1.personCreate; } });
6
+ var update_operation_1 = require("./update.operation");
7
+ Object.defineProperty(exports, "personUpdate", { enumerable: true, get: function () { return update_operation_1.personUpdate; } });
8
+ var get_operation_1 = require("./get.operation");
9
+ Object.defineProperty(exports, "personGet", { enumerable: true, get: function () { return get_operation_1.personGet; } });
7
10
  var create_properties_1 = require("./create.properties");
8
11
  Object.defineProperty(exports, "personCreateProperties", { enumerable: true, get: function () { return create_properties_1.personCreateProperties; } });
12
+ var update_properties_1 = require("./update.properties");
13
+ Object.defineProperty(exports, "personUpdateProperties", { enumerable: true, get: function () { return update_properties_1.personUpdateProperties; } });
14
+ var get_properties_1 = require("./get.properties");
15
+ Object.defineProperty(exports, "personGetProperties", { enumerable: true, get: function () { return get_properties_1.personGetProperties; } });
@@ -0,0 +1,2 @@
1
+ import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
2
+ export declare function personUpdate(this: IExecuteFunctions, i: number, returnData: INodeExecutionData[]): Promise<void>;
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.personUpdate = personUpdate;
4
+ const http_1 = require("../../lib/http");
5
+ async function personUpdate(i, returnData) {
6
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
7
+ const id = this.getNodeParameter('Id', i, '');
8
+ if (!id)
9
+ throw new Error('Id is required.');
10
+ const lastName = this.getNodeParameter('LastName', i, '');
11
+ if (!lastName)
12
+ throw new Error('LastName is required.');
13
+ const firstName = this.getNodeParameter('FirstName', i, '');
14
+ const mobile = this.getNodeParameter('MobilePhone', i, '');
15
+ const workPhone = this.getNodeParameter('WorkPhone', i, '');
16
+ // Owner
17
+ const ownerMode = this.getNodeParameter('OwnerMode', i);
18
+ const ownerId = ownerMode === 'select'
19
+ ? this.getNodeParameter('OwnerIdSelect', i, '')
20
+ : this.getNodeParameter('OwnerIdManual', i, '');
21
+ if (!ownerId)
22
+ throw new Error('OwnerId is required (select from list or enter manually).');
23
+ const add = this.getNodeParameter('additionalFields', i, {}) || {};
24
+ const title = (_a = add.Title) !== null && _a !== void 0 ? _a : '';
25
+ const companyName = (_b = add.CompanyName) !== null && _b !== void 0 ? _b : '';
26
+ const companyId = (_c = add.CompanyId) !== null && _c !== void 0 ? _c : '00000000-0000-0000-0000-000000000000';
27
+ const birthDate = (_d = add.BirthDate) !== null && _d !== void 0 ? _d : '';
28
+ const birthDateMessageId = (_e = add.BirthDateMessageId) !== null && _e !== void 0 ? _e : '00000000-0000-0000-0000-000000000000';
29
+ const workPhoneExt = (_f = add.WorkPhoneExtension) !== null && _f !== void 0 ? _f : '';
30
+ const fax = (_g = add.Fax) !== null && _g !== void 0 ? _g : '';
31
+ const email = (_h = add.Email) !== null && _h !== void 0 ? _h : '';
32
+ const isVip = (_j = add.IsVIP) !== null && _j !== void 0 ? _j : false;
33
+ const backgroundInfo = (_k = add.BackgroundInfo) !== null && _k !== void 0 ? _k : '';
34
+ const position = (_l = add.Position) !== null && _l !== void 0 ? _l : '';
35
+ const customerCode = (_m = add.CustomerCode) !== null && _m !== void 0 ? _m : '';
36
+ const nationalCode = (_o = add.NationalCode) !== null && _o !== void 0 ? _o : '';
37
+ const zipCode = (_p = add.ZipCode) !== null && _p !== void 0 ? _p : '';
38
+ const visibilityType = (_q = add.VisibilityType) !== null && _q !== void 0 ? _q : 'Owner';
39
+ // Fields
40
+ let fields;
41
+ if (typeof add.Fields === 'string' && add.Fields.trim()) {
42
+ try {
43
+ fields = JSON.parse(add.Fields);
44
+ }
45
+ catch {
46
+ throw new Error('Invalid JSON in "Custom Fields (JSON)".');
47
+ }
48
+ }
49
+ else if (typeof add.Fields === 'object' && add.Fields) {
50
+ fields = add.Fields;
51
+ }
52
+ // helpers
53
+ const toKeyValues = (obj) => {
54
+ var _a;
55
+ if (!obj || typeof obj !== 'object')
56
+ return undefined;
57
+ const list = (_a = obj.KeyValues) !== null && _a !== void 0 ? _a : [];
58
+ if (!Array.isArray(list) || !list.length)
59
+ return undefined;
60
+ return { KeyValues: list.map(e => { var _a, _b; return ({ Key: (_a = e.Key) !== null && _a !== void 0 ? _a : '', Value: (_b = e.Value) !== null && _b !== void 0 ? _b : '' }); }) };
61
+ };
62
+ const websites = toKeyValues(add.Websites);
63
+ const otherPhones = toKeyValues(add.OtherPhones);
64
+ const otherEmails = toKeyValues(add.OtherEmails);
65
+ const addresses = toKeyValues(add.Addresses);
66
+ let bankAccounts;
67
+ if (add.BankAccounts && typeof add.BankAccounts === 'object') {
68
+ const vals = add.BankAccounts.Values;
69
+ if (Array.isArray(vals) && vals.length) {
70
+ bankAccounts = { Values: vals.map(v => {
71
+ var _a, _b, _c, _d;
72
+ return ({
73
+ Value1: (_a = v.Value1) !== null && _a !== void 0 ? _a : '', Value2: (_b = v.Value2) !== null && _b !== void 0 ? _b : '', Value3: (_c = v.Value3) !== null && _c !== void 0 ? _c : '', Value4: (_d = v.Value4) !== null && _d !== void 0 ? _d : '',
74
+ });
75
+ }) };
76
+ }
77
+ }
78
+ let segmentIds;
79
+ const seg = add.SegmentIds;
80
+ if (Array.isArray(seg))
81
+ segmentIds = seg.filter(Boolean);
82
+ else if (typeof seg === 'string' && seg)
83
+ segmentIds = [seg];
84
+ // Contact body (Type همیشه Person)
85
+ const contact = {
86
+ Id: id,
87
+ Type: 'Person',
88
+ FirstName: firstName,
89
+ LastName: lastName,
90
+ Title: title,
91
+ OwnerId: ownerId,
92
+ CompanyName: companyName,
93
+ CompanyId: companyId,
94
+ BirthDate: birthDate || undefined,
95
+ BirthDateMessageId: birthDateMessageId,
96
+ MobilePhone: mobile,
97
+ WorkPhone: workPhone,
98
+ WorkPhoneExtension: workPhoneExt,
99
+ Fax: fax,
100
+ Email: email,
101
+ IsVIP: isVip,
102
+ BackgroundInfo: backgroundInfo,
103
+ Position: position,
104
+ CustomerCode: customerCode,
105
+ NationalCode: nationalCode,
106
+ ZipCode: zipCode,
107
+ VisibilityType: visibilityType,
108
+ };
109
+ if (fields)
110
+ contact['Fields'] = fields;
111
+ if (websites)
112
+ contact['Websites'] = websites;
113
+ if (otherPhones)
114
+ contact['OtherPhones'] = otherPhones;
115
+ if (otherEmails)
116
+ contact['OtherEmails'] = otherEmails;
117
+ if (addresses)
118
+ contact['Addresses'] = addresses;
119
+ if (bankAccounts)
120
+ contact['BankAccounts'] = bankAccounts;
121
+ const body = { Contact: contact };
122
+ if (segmentIds && segmentIds.length)
123
+ body['SegmentIds'] = segmentIds;
124
+ const resp = await (0, http_1.didarRequest)(this, i, {
125
+ method: 'POST',
126
+ path: '/api/contact/save',
127
+ body,
128
+ });
129
+ returnData.push({ json: resp });
130
+ }
@@ -0,0 +1,2 @@
1
+ import { INodeProperties } from 'n8n-workflow';
2
+ export declare const personUpdateProperties: INodeProperties[];
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.personUpdateProperties = void 0;
4
+ const showForPersonUpdate = { show: { resource: ['person'], operation: ['update'] } };
5
+ exports.personUpdateProperties = [
6
+ // Id (required)
7
+ {
8
+ displayName: 'Id',
9
+ name: 'Id',
10
+ type: 'string',
11
+ default: '',
12
+ required: true,
13
+ displayOptions: showForPersonUpdate,
14
+ description: 'Person Id to update (required).',
15
+ },
16
+ // ترتیب اصلی: FirstName, LastName(required), MobilePhone, WorkPhone
17
+ {
18
+ displayName: 'First Name',
19
+ name: 'FirstName',
20
+ type: 'string',
21
+ default: '',
22
+ displayOptions: showForPersonUpdate,
23
+ description: 'Optional given name of the person.',
24
+ },
25
+ {
26
+ displayName: 'Last Name',
27
+ name: 'LastName',
28
+ type: 'string',
29
+ default: '',
30
+ required: true,
31
+ displayOptions: showForPersonUpdate,
32
+ description: 'Required family name (last name) of the person.',
33
+ },
34
+ {
35
+ displayName: 'Mobile Phone',
36
+ name: 'MobilePhone',
37
+ type: 'string',
38
+ default: '',
39
+ displayOptions: showForPersonUpdate,
40
+ description: 'Primary mobile phone number.',
41
+ },
42
+ {
43
+ displayName: 'Work Phone',
44
+ name: 'WorkPhone',
45
+ type: 'string',
46
+ default: '',
47
+ displayOptions: showForPersonUpdate,
48
+ description: 'Work phone number.',
49
+ },
50
+ // Owner (select/manual) مثل Create
51
+ {
52
+ displayName: 'Owner Input Mode',
53
+ name: 'OwnerMode',
54
+ type: 'options',
55
+ options: [
56
+ { name: 'Select from list', value: 'select' },
57
+ { name: 'Enter ID manually', value: 'manual' },
58
+ ],
59
+ default: 'select',
60
+ displayOptions: showForPersonUpdate,
61
+ description: 'Choose how to set the owner of this person.',
62
+ },
63
+ {
64
+ displayName: 'Owner',
65
+ name: 'OwnerIdSelect',
66
+ type: 'options',
67
+ typeOptions: { loadOptionsMethod: 'getUsers' },
68
+ default: '',
69
+ displayOptions: { show: { ...showForPersonUpdate.show, OwnerMode: ['select'] } },
70
+ description: 'Select the owner user (required if select mode).',
71
+ },
72
+ {
73
+ displayName: 'Owner ID',
74
+ name: 'OwnerIdManual',
75
+ type: 'string',
76
+ default: '',
77
+ displayOptions: { show: { ...showForPersonUpdate.show, OwnerMode: ['manual'] } },
78
+ description: 'Enter owner user ID manually (required if manual mode).',
79
+ },
80
+ // Additional Fields (همان Create)
81
+ {
82
+ displayName: 'Additional Fields',
83
+ name: 'additionalFields',
84
+ type: 'collection',
85
+ placeholder: 'Add field',
86
+ default: {},
87
+ displayOptions: showForPersonUpdate,
88
+ options: [
89
+ { displayName: 'Title', name: 'Title', type: 'string', default: '', description: 'Honorific or title (e.g., Mr., Ms., Dr.).' },
90
+ { displayName: 'Company Name', name: 'CompanyName', type: 'string', default: '', description: 'Related company name (plain text).' },
91
+ { displayName: 'Company ID', name: 'CompanyId', type: 'string', default: '00000000-0000-0000-0000-000000000000', description: 'Related company ID (GUID).' },
92
+ { displayName: 'Birth Date (ISO)', name: 'BirthDate', type: 'string', default: '', description: 'Birth date in ISO format (e.g., 2025-08-31T08:02:06Z).' },
93
+ { displayName: 'Birth Date Message ID', name: 'BirthDateMessageId', type: 'string', default: '00000000-0000-0000-0000-000000000000', description: 'Notification/message template ID for birthday (GUID).' },
94
+ { displayName: 'Work Phone Extension', name: 'WorkPhoneExtension', type: 'string', default: '', description: 'Extension for the work phone.' },
95
+ { displayName: 'Fax', name: 'Fax', type: 'string', default: '', description: 'Fax number.' },
96
+ { displayName: 'Email', name: 'Email', type: 'string', default: '', description: 'Primary email address.' },
97
+ { displayName: 'Is VIP', name: 'IsVIP', type: 'boolean', default: false, description: 'Mark this person as VIP.' },
98
+ { displayName: 'Background Info', name: 'BackgroundInfo', type: 'string', default: '', description: 'Notes or background information.' },
99
+ { displayName: 'Position', name: 'Position', type: 'string', default: '', description: 'Job title or position.' },
100
+ { displayName: 'Customer Code', name: 'CustomerCode', type: 'string', default: '', description: 'Internal or CRM customer code.' },
101
+ { displayName: 'National Code', name: 'NationalCode associated with the person', type: 'string', default: '', description: 'National ID code.' },
102
+ { displayName: 'Zip Code', name: 'ZipCode', type: 'string', default: '', description: 'Postal/ZIP code.' },
103
+ {
104
+ displayName: 'Visibility Type',
105
+ name: 'VisibilityType',
106
+ type: 'options',
107
+ options: [
108
+ { name: 'Owner', value: 'Owner' },
109
+ { name: 'Owner Group', value: 'OwnerGroup' },
110
+ { name: 'Owner SubGroup', value: 'OwnerSubGroup' },
111
+ { name: 'All', value: 'All' },
112
+ ],
113
+ default: 'Owner',
114
+ description: 'Visibility setting for this person.',
115
+ },
116
+ { displayName: 'Custom Fields (JSON)', name: 'Fields', type: 'json', default: '', placeholder: '{ "Field_996_0_7": "value" }', description: 'JSON object of custom fields.' },
117
+ // Lists
118
+ {
119
+ displayName: 'Websites',
120
+ name: 'Websites',
121
+ type: 'fixedCollection',
122
+ typeOptions: { multipleValues: true },
123
+ default: {},
124
+ options: [{ name: 'KeyValues', displayName: 'Website', values: [
125
+ { displayName: 'Key', name: 'Key', type: 'string', default: '' },
126
+ { displayName: 'Value', name: 'Value', type: 'string', default: '' },
127
+ ] }],
128
+ description: 'List of websites as key/value pairs.',
129
+ },
130
+ {
131
+ displayName: 'Other Phones',
132
+ name: 'OtherPhones',
133
+ type: 'fixedCollection',
134
+ typeOptions: { multipleValues: true },
135
+ default: {},
136
+ options: [{ name: 'KeyValues', displayName: 'Phone', values: [
137
+ { displayName: 'Key', name: 'Key', type: 'string', default: '' },
138
+ { displayName: 'Value', name: 'Value', type: 'string', default: '' },
139
+ ] }],
140
+ description: 'Additional phone numbers as key/value pairs.',
141
+ },
142
+ {
143
+ displayName: 'Other Emails',
144
+ name: 'OtherEmails',
145
+ type: 'fixedCollection',
146
+ typeOptions: { multipleValues: true },
147
+ default: {},
148
+ options: [{ name: 'KeyValues', displayName: 'Email', values: [
149
+ { displayName: 'Key', name: 'Key', type: 'string', default: '' },
150
+ { displayName: 'Value', name: 'Value', type: 'string', default: '' },
151
+ ] }],
152
+ description: 'Additional emails as key/value pairs.',
153
+ },
154
+ {
155
+ displayName: 'Addresses',
156
+ name: 'Addresses',
157
+ type: 'fixedCollection',
158
+ typeOptions: { multipleValues: true },
159
+ default: {},
160
+ options: [{ name: 'KeyValues', displayName: 'Address', values: [
161
+ { displayName: 'Key', name: 'Key', type: 'string', default: '' },
162
+ { displayName: 'Value', name: 'Value', type: 'string', default: '' },
163
+ ] }],
164
+ description: 'Addresses as key/value pairs (e.g., Home/Work/etc.).',
165
+ },
166
+ {
167
+ displayName: 'Bank Accounts',
168
+ name: 'BankAccounts',
169
+ type: 'fixedCollection',
170
+ typeOptions: { multipleValues: true },
171
+ default: {},
172
+ options: [{ name: 'Values', displayName: 'Bank Account', values: [
173
+ { displayName: 'Value1', name: 'Value1', type: 'string', default: '' },
174
+ { displayName: 'Value2', name: 'Value2', type: 'string', default: '' },
175
+ { displayName: 'Value3', name: 'Value3', type: 'string', default: '' },
176
+ { displayName: 'Value4', name: 'Value4', type: 'string', default: '' },
177
+ ] }],
178
+ description: 'Bank account details (four flexible fields per entry).',
179
+ },
180
+ // SegmentIds
181
+ {
182
+ displayName: 'Segment IDs',
183
+ name: 'SegmentIds',
184
+ type: 'string',
185
+ typeOptions: { multipleValues: true },
186
+ default: [],
187
+ description: 'List of segment IDs (GUIDs).',
188
+ },
189
+ ],
190
+ },
191
+ ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-didar-crm",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "Didar CRM nodes for n8n (Trigger + Deal.create)",
5
5
  "author": "You",
6
6
  "license": "MIT",