n8n-nodes-servicem8-jobcreation 1.0.0

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.
Files changed (153) hide show
  1. package/README.md +517 -0
  2. package/dist/credentials/ServiceM8Api.credentials.d.ts +9 -0
  3. package/dist/credentials/ServiceM8Api.credentials.js +38 -0
  4. package/dist/credentials/ServiceM8Api.credentials.js.map +1 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.js +8 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/nodes/ServiceM8JobCreation/ServiceM8JobCreation.node.d.ts +18 -0
  9. package/dist/nodes/ServiceM8JobCreation/ServiceM8JobCreation.node.js +39 -0
  10. package/dist/nodes/ServiceM8JobCreation/ServiceM8JobCreation.node.js.map +1 -0
  11. package/dist/nodes/ServiceM8JobCreation/execute.d.ts +6 -0
  12. package/dist/nodes/ServiceM8JobCreation/execute.js +47 -0
  13. package/dist/nodes/ServiceM8JobCreation/execute.js.map +1 -0
  14. package/dist/nodes/ServiceM8JobCreation/helpers/addressUtils.d.ts +56 -0
  15. package/dist/nodes/ServiceM8JobCreation/helpers/addressUtils.js +124 -0
  16. package/dist/nodes/ServiceM8JobCreation/helpers/addressUtils.js.map +1 -0
  17. package/dist/nodes/ServiceM8JobCreation/helpers/api.d.ts +180 -0
  18. package/dist/nodes/ServiceM8JobCreation/helpers/api.js +418 -0
  19. package/dist/nodes/ServiceM8JobCreation/helpers/api.js.map +1 -0
  20. package/dist/nodes/ServiceM8JobCreation/helpers/clientMatcher.d.ts +67 -0
  21. package/dist/nodes/ServiceM8JobCreation/helpers/clientMatcher.js +216 -0
  22. package/dist/nodes/ServiceM8JobCreation/helpers/clientMatcher.js.map +1 -0
  23. package/dist/nodes/ServiceM8JobCreation/helpers/phoneUtils.d.ts +35 -0
  24. package/dist/nodes/ServiceM8JobCreation/helpers/phoneUtils.js +122 -0
  25. package/dist/nodes/ServiceM8JobCreation/helpers/phoneUtils.js.map +1 -0
  26. package/dist/nodes/ServiceM8JobCreation/methods/index.d.ts +13 -0
  27. package/dist/nodes/ServiceM8JobCreation/methods/index.js +17 -0
  28. package/dist/nodes/ServiceM8JobCreation/methods/index.js.map +1 -0
  29. package/dist/nodes/ServiceM8JobCreation/methods/loadOptions.d.ts +9 -0
  30. package/dist/nodes/ServiceM8JobCreation/methods/loadOptions.js +61 -0
  31. package/dist/nodes/ServiceM8JobCreation/methods/loadOptions.js.map +1 -0
  32. package/dist/nodes/ServiceM8JobCreation/operations/create/categoryAssign.d.ts +22 -0
  33. package/dist/nodes/ServiceM8JobCreation/operations/create/categoryAssign.js +61 -0
  34. package/dist/nodes/ServiceM8JobCreation/operations/create/categoryAssign.js.map +1 -0
  35. package/dist/nodes/ServiceM8JobCreation/operations/create/clientCreate.d.ts +36 -0
  36. package/dist/nodes/ServiceM8JobCreation/operations/create/clientCreate.js +66 -0
  37. package/dist/nodes/ServiceM8JobCreation/operations/create/clientCreate.js.map +1 -0
  38. package/dist/nodes/ServiceM8JobCreation/operations/create/clientLookup.d.ts +28 -0
  39. package/dist/nodes/ServiceM8JobCreation/operations/create/clientLookup.js +46 -0
  40. package/dist/nodes/ServiceM8JobCreation/operations/create/clientLookup.js.map +1 -0
  41. package/dist/nodes/ServiceM8JobCreation/operations/create/contactLookup.d.ts +18 -0
  42. package/dist/nodes/ServiceM8JobCreation/operations/create/contactLookup.js +48 -0
  43. package/dist/nodes/ServiceM8JobCreation/operations/create/contactLookup.js.map +1 -0
  44. package/dist/nodes/ServiceM8JobCreation/operations/create/index.d.ts +12 -0
  45. package/dist/nodes/ServiceM8JobCreation/operations/create/index.js +40 -0
  46. package/dist/nodes/ServiceM8JobCreation/operations/create/index.js.map +1 -0
  47. package/dist/nodes/ServiceM8JobCreation/operations/create/inputProcessor.d.ts +63 -0
  48. package/dist/nodes/ServiceM8JobCreation/operations/create/inputProcessor.js +176 -0
  49. package/dist/nodes/ServiceM8JobCreation/operations/create/inputProcessor.js.map +1 -0
  50. package/dist/nodes/ServiceM8JobCreation/operations/create/jobCreate.d.ts +43 -0
  51. package/dist/nodes/ServiceM8JobCreation/operations/create/jobCreate.js +82 -0
  52. package/dist/nodes/ServiceM8JobCreation/operations/create/jobCreate.js.map +1 -0
  53. package/dist/nodes/ServiceM8JobCreation/operations/create/notifications.d.ts +38 -0
  54. package/dist/nodes/ServiceM8JobCreation/operations/create/notifications.js +123 -0
  55. package/dist/nodes/ServiceM8JobCreation/operations/create/notifications.js.map +1 -0
  56. package/dist/nodes/ServiceM8JobCreation/operations/create/orchestrator.d.ts +12 -0
  57. package/dist/nodes/ServiceM8JobCreation/operations/create/orchestrator.js +192 -0
  58. package/dist/nodes/ServiceM8JobCreation/operations/create/orchestrator.js.map +1 -0
  59. package/dist/nodes/ServiceM8JobCreation/operations/create/queueAssign.d.ts +22 -0
  60. package/dist/nodes/ServiceM8JobCreation/operations/create/queueAssign.js +61 -0
  61. package/dist/nodes/ServiceM8JobCreation/operations/create/queueAssign.js.map +1 -0
  62. package/dist/nodes/ServiceM8JobCreation/operations/index.d.ts +8 -0
  63. package/dist/nodes/ServiceM8JobCreation/operations/index.js +35 -0
  64. package/dist/nodes/ServiceM8JobCreation/operations/index.js.map +1 -0
  65. package/dist/nodes/ServiceM8JobCreation/operations/shared/attachmentsUpload.d.ts +41 -0
  66. package/dist/nodes/ServiceM8JobCreation/operations/shared/attachmentsUpload.js +243 -0
  67. package/dist/nodes/ServiceM8JobCreation/operations/shared/attachmentsUpload.js.map +1 -0
  68. package/dist/nodes/ServiceM8JobCreation/operations/shared/badgesAssign.d.ts +21 -0
  69. package/dist/nodes/ServiceM8JobCreation/operations/shared/badgesAssign.js +65 -0
  70. package/dist/nodes/ServiceM8JobCreation/operations/shared/badgesAssign.js.map +1 -0
  71. package/dist/nodes/ServiceM8JobCreation/operations/shared/index.d.ts +7 -0
  72. package/dist/nodes/ServiceM8JobCreation/operations/shared/index.js +15 -0
  73. package/dist/nodes/ServiceM8JobCreation/operations/shared/index.js.map +1 -0
  74. package/dist/nodes/ServiceM8JobCreation/operations/shared/notesCreate.d.ts +42 -0
  75. package/dist/nodes/ServiceM8JobCreation/operations/shared/notesCreate.js +103 -0
  76. package/dist/nodes/ServiceM8JobCreation/operations/shared/notesCreate.js.map +1 -0
  77. package/dist/nodes/ServiceM8JobCreation/operations/update/index.d.ts +5 -0
  78. package/dist/nodes/ServiceM8JobCreation/operations/update/index.js +9 -0
  79. package/dist/nodes/ServiceM8JobCreation/operations/update/index.js.map +1 -0
  80. package/dist/nodes/ServiceM8JobCreation/operations/update/jobUpdate.d.ts +10 -0
  81. package/dist/nodes/ServiceM8JobCreation/operations/update/jobUpdate.js +239 -0
  82. package/dist/nodes/ServiceM8JobCreation/operations/update/jobUpdate.js.map +1 -0
  83. package/dist/nodes/ServiceM8JobCreation/properties/create/address.d.ts +5 -0
  84. package/dist/nodes/ServiceM8JobCreation/properties/create/address.js +145 -0
  85. package/dist/nodes/ServiceM8JobCreation/properties/create/address.js.map +1 -0
  86. package/dist/nodes/ServiceM8JobCreation/properties/create/business.d.ts +5 -0
  87. package/dist/nodes/ServiceM8JobCreation/properties/create/business.js +22 -0
  88. package/dist/nodes/ServiceM8JobCreation/properties/create/business.js.map +1 -0
  89. package/dist/nodes/ServiceM8JobCreation/properties/create/contact.d.ts +5 -0
  90. package/dist/nodes/ServiceM8JobCreation/properties/create/contact.js +85 -0
  91. package/dist/nodes/ServiceM8JobCreation/properties/create/contact.js.map +1 -0
  92. package/dist/nodes/ServiceM8JobCreation/properties/create/index.d.ts +10 -0
  93. package/dist/nodes/ServiceM8JobCreation/properties/create/index.js +30 -0
  94. package/dist/nodes/ServiceM8JobCreation/properties/create/index.js.map +1 -0
  95. package/dist/nodes/ServiceM8JobCreation/properties/create/job.d.ts +5 -0
  96. package/dist/nodes/ServiceM8JobCreation/properties/create/job.js +43 -0
  97. package/dist/nodes/ServiceM8JobCreation/properties/create/job.js.map +1 -0
  98. package/dist/nodes/ServiceM8JobCreation/properties/create/options/additionalOptions.d.ts +5 -0
  99. package/dist/nodes/ServiceM8JobCreation/properties/create/options/additionalOptions.js +49 -0
  100. package/dist/nodes/ServiceM8JobCreation/properties/create/options/additionalOptions.js.map +1 -0
  101. package/dist/nodes/ServiceM8JobCreation/properties/create/options/attachments.d.ts +5 -0
  102. package/dist/nodes/ServiceM8JobCreation/properties/create/options/attachments.js +151 -0
  103. package/dist/nodes/ServiceM8JobCreation/properties/create/options/attachments.js.map +1 -0
  104. package/dist/nodes/ServiceM8JobCreation/properties/create/options/badges.d.ts +5 -0
  105. package/dist/nodes/ServiceM8JobCreation/properties/create/options/badges.js +65 -0
  106. package/dist/nodes/ServiceM8JobCreation/properties/create/options/badges.js.map +1 -0
  107. package/dist/nodes/ServiceM8JobCreation/properties/create/options/category.d.ts +5 -0
  108. package/dist/nodes/ServiceM8JobCreation/properties/create/options/category.js +65 -0
  109. package/dist/nodes/ServiceM8JobCreation/properties/create/options/category.js.map +1 -0
  110. package/dist/nodes/ServiceM8JobCreation/properties/create/options/index.d.ts +12 -0
  111. package/dist/nodes/ServiceM8JobCreation/properties/create/options/index.js +38 -0
  112. package/dist/nodes/ServiceM8JobCreation/properties/create/options/index.js.map +1 -0
  113. package/dist/nodes/ServiceM8JobCreation/properties/create/options/notes.d.ts +5 -0
  114. package/dist/nodes/ServiceM8JobCreation/properties/create/options/notes.js +49 -0
  115. package/dist/nodes/ServiceM8JobCreation/properties/create/options/notes.js.map +1 -0
  116. package/dist/nodes/ServiceM8JobCreation/properties/create/options/notifications.d.ts +5 -0
  117. package/dist/nodes/ServiceM8JobCreation/properties/create/options/notifications.js +197 -0
  118. package/dist/nodes/ServiceM8JobCreation/properties/create/options/notifications.js.map +1 -0
  119. package/dist/nodes/ServiceM8JobCreation/properties/create/options/queue.d.ts +5 -0
  120. package/dist/nodes/ServiceM8JobCreation/properties/create/options/queue.js +65 -0
  121. package/dist/nodes/ServiceM8JobCreation/properties/create/options/queue.js.map +1 -0
  122. package/dist/nodes/ServiceM8JobCreation/properties/index.d.ts +9 -0
  123. package/dist/nodes/ServiceM8JobCreation/properties/index.js +23 -0
  124. package/dist/nodes/ServiceM8JobCreation/properties/index.js.map +1 -0
  125. package/dist/nodes/ServiceM8JobCreation/properties/operation.d.ts +5 -0
  126. package/dist/nodes/ServiceM8JobCreation/properties/operation.js +28 -0
  127. package/dist/nodes/ServiceM8JobCreation/properties/operation.js.map +1 -0
  128. package/dist/nodes/ServiceM8JobCreation/properties/update/fields.d.ts +5 -0
  129. package/dist/nodes/ServiceM8JobCreation/properties/update/fields.js +74 -0
  130. package/dist/nodes/ServiceM8JobCreation/properties/update/fields.js.map +1 -0
  131. package/dist/nodes/ServiceM8JobCreation/properties/update/index.d.ts +8 -0
  132. package/dist/nodes/ServiceM8JobCreation/properties/update/index.js +22 -0
  133. package/dist/nodes/ServiceM8JobCreation/properties/update/index.js.map +1 -0
  134. package/dist/nodes/ServiceM8JobCreation/properties/update/jobSelection.d.ts +5 -0
  135. package/dist/nodes/ServiceM8JobCreation/properties/update/jobSelection.js +63 -0
  136. package/dist/nodes/ServiceM8JobCreation/properties/update/jobSelection.js.map +1 -0
  137. package/dist/nodes/ServiceM8JobCreation/properties/update/options.d.ts +5 -0
  138. package/dist/nodes/ServiceM8JobCreation/properties/update/options.js +142 -0
  139. package/dist/nodes/ServiceM8JobCreation/properties/update/options.js.map +1 -0
  140. package/dist/nodes/ServiceM8JobCreation/servicem8.svg +75 -0
  141. package/dist/nodes/ServiceM8JobCreation/types/api.d.ts +59 -0
  142. package/dist/nodes/ServiceM8JobCreation/types/api.js +34 -0
  143. package/dist/nodes/ServiceM8JobCreation/types/api.js.map +1 -0
  144. package/dist/nodes/ServiceM8JobCreation/types/index.d.ts +7 -0
  145. package/dist/nodes/ServiceM8JobCreation/types/index.js +21 -0
  146. package/dist/nodes/ServiceM8JobCreation/types/index.js.map +1 -0
  147. package/dist/nodes/ServiceM8JobCreation/types/input.d.ts +119 -0
  148. package/dist/nodes/ServiceM8JobCreation/types/input.js +6 -0
  149. package/dist/nodes/ServiceM8JobCreation/types/input.js.map +1 -0
  150. package/dist/nodes/ServiceM8JobCreation/types/result.d.ts +79 -0
  151. package/dist/nodes/ServiceM8JobCreation/types/result.js +96 -0
  152. package/dist/nodes/ServiceM8JobCreation/types/result.js.map +1 -0
  153. package/package.json +66 -0
package/README.md ADDED
@@ -0,0 +1,517 @@
1
+ # n8n-nodes-servicem8-jobcreation
2
+
3
+ A custom n8n community node for creating and updating ServiceM8 jobs with **intelligent client/contact deduplication**.
4
+
5
+ This node consolidates what would typically be a 50+ node workflow into a single, configurable node that handles:
6
+ - Client lookup and matching
7
+ - Contact deduplication
8
+ - Business vs individual classification
9
+ - Job creation with all optional features
10
+ - Job updates with badges, attachments, and notes
11
+
12
+ ## Installation
13
+
14
+ ### Community Node (Recommended)
15
+ 1. Go to **Settings** > **Community Nodes**
16
+ 2. Select **Install**
17
+ 3. Enter `n8n-nodes-servicem8-jobcreation`
18
+ 4. Click **Install**
19
+
20
+ ### Manual Installation
21
+ ```bash
22
+ npm install n8n-nodes-servicem8-jobcreation
23
+ ```
24
+
25
+ ## Credentials
26
+
27
+ This node requires ServiceM8 API credentials. Create a new credential of type **ServiceM8 API** with your API key.
28
+
29
+ To get your API key:
30
+ 1. Log into ServiceM8
31
+ 2. Go to **Settings** > **API & Webhooks**
32
+ 3. Generate or copy your API key
33
+
34
+ ---
35
+
36
+ ## Operations
37
+
38
+ ### Create Job
39
+
40
+ Creates a new ServiceM8 job with intelligent client/contact deduplication.
41
+
42
+ #### How Deduplication Works
43
+
44
+ 1. **Contact Lookup**: Searches for existing contacts by email > mobile > phone (in priority order)
45
+ 2. **Client Matching**: If a contact is found, checks if it belongs to a matching client
46
+ 3. **Decision Matrix**: Determines whether to use an existing client or create a new one based on:
47
+ - Name match quality (exact, partial, none)
48
+ - Address match quality (exact, near, none)
49
+ - Business vs individual classification
50
+
51
+ #### Required Fields
52
+
53
+ | Field | Description |
54
+ |-------|-------------|
55
+ | **First Name** | Required for individuals. Can be omitted if Business Name is provided. |
56
+ | **Email, Phone, or Mobile** | At least one contact method is required for deduplication. |
57
+
58
+ #### Contact Information
59
+
60
+ | Field | Description |
61
+ |-------|-------------|
62
+ | First Name | Contact's first name |
63
+ | Last Name | Contact's last name (optional) |
64
+ | Email | Primary lookup identifier for deduplication |
65
+ | Phone | Landline number (Australian format supported) |
66
+ | Mobile | Mobile number (Australian format supported) |
67
+
68
+ #### Business Information
69
+
70
+ | Field | Description |
71
+ |-------|-------------|
72
+ | Business Name | If provided, client is created as a business; otherwise as individual |
73
+
74
+ #### Address Fields
75
+
76
+ **Client Address** (fixedCollection):
77
+ | Field | Description |
78
+ |-------|-------------|
79
+ | Street | Street address including unit/suite |
80
+ | City | City or suburb |
81
+ | State/Province | State, province, or region |
82
+ | Postcode | Postal or ZIP code |
83
+ | Country | Country name |
84
+
85
+ **Job Address**:
86
+ | Field | Description |
87
+ |-------|-------------|
88
+ | Job Address Same as Client | Toggle to use client address for job site |
89
+ | Job Address | Separate address fields (only shown when toggle is off) |
90
+
91
+ #### Job Information
92
+
93
+ | Field | Description |
94
+ |-------|-------------|
95
+ | Job Details | Multiline job description/notes |
96
+ | Job Status | Quote, Work Order, In Progress, or Completed |
97
+
98
+ #### Optional Features
99
+
100
+ All optional features have an enable toggle. When enabled, additional configuration fields appear.
101
+
102
+ **Category Assignment**:
103
+ | Field | Description |
104
+ |-------|-------------|
105
+ | Enable Category | Toggle to enable |
106
+ | Use Dynamic Category | Toggle between dropdown or expression input |
107
+ | Category | Dropdown selection (loads from ServiceM8) |
108
+ | Category Name | Text/expression input for dynamic mode |
109
+
110
+ **Badges Assignment**:
111
+ | Field | Description |
112
+ |-------|-------------|
113
+ | Enable Badges | Toggle to enable |
114
+ | Use Dynamic Badges | Toggle between multi-select or expression input |
115
+ | Badges | Multi-select dropdown (loads from ServiceM8) |
116
+ | Badge Names | Comma-separated names for dynamic mode |
117
+
118
+ **Queue Assignment**:
119
+ | Field | Description |
120
+ |-------|-------------|
121
+ | Enable Queue | Toggle to enable |
122
+ | Use Dynamic Queue | Toggle between dropdown or expression input |
123
+ | Queue | Dropdown selection (loads from ServiceM8) |
124
+ | Queue Name | Text/expression input for dynamic mode |
125
+
126
+ **Notifications**:
127
+ | Field | Description |
128
+ |-------|-------------|
129
+ | Enable Notifications | Toggle to enable |
130
+ | Notification Recipients | Collection of recipients (see below) |
131
+
132
+ Each notification recipient has the following options:
133
+
134
+ | Field | Description |
135
+ |-------|-------------|
136
+ | Notification Type | **Email** or **SMS** |
137
+ | Email Address | Recipient email (for Email type) |
138
+ | Phone Number | Recipient phone (for SMS type) |
139
+ | Recipient Name | Name used in greeting |
140
+ | Email Format | **HTML** or **Plain Text** (for Email type) |
141
+ | Custom Subject | Toggle to use custom email subject |
142
+ | Subject | Custom subject line (supports placeholders) |
143
+ | Custom Message | Toggle to use custom message content |
144
+ | Message (HTML) | Custom HTML email body (when format is HTML) |
145
+ | Message (Text) | Custom plain text email body (when format is Text) |
146
+ | SMS Message | Custom SMS message (max 160 chars recommended) |
147
+ | Include Attachments | Toggle to attach files to email |
148
+ | Attachment Source | **All Binary Data** or **Specific Property** |
149
+ | Binary Property | Property name when using specific property |
150
+
151
+ **Message Placeholders**: Custom messages support these placeholders:
152
+ - `{{name}}` - Recipient name
153
+ - `{{jobNumber}}` - Job number (e.g., "J00123")
154
+ - `{{clientName}}` - Client/customer name
155
+ - `{{jobAddress}}` - Job site address
156
+ - `{{jobDetails}}` - Job description
157
+
158
+ **Attachments**:
159
+ | Field | Description |
160
+ |-------|-------------|
161
+ | Enable Attachments | Toggle to enable |
162
+ | Attachment Mode | "All Binary Data" (auto-upload from previous node) or "URL List" |
163
+ | URL List | Comma-separated URLs to download and attach |
164
+
165
+ **Notes**:
166
+ | Field | Description |
167
+ |-------|-------------|
168
+ | Enable Custom Note | Toggle to add a custom note |
169
+ | Custom Note Content | Note text to add to the job |
170
+
171
+ *Note: A system report note is always created with job creation details.*
172
+
173
+ #### Additional Options
174
+
175
+ | Field | Description |
176
+ |-------|-------------|
177
+ | Individual Name Format | "First Last" or "Last, First" - must match your ServiceM8 settings |
178
+ | Return Headers | Include all created record UUIDs in output |
179
+
180
+ ---
181
+
182
+ ### Update Job
183
+
184
+ Updates an existing ServiceM8 job with optional badges, attachments, and notes.
185
+
186
+ #### Job Selection
187
+
188
+ | Field | Description |
189
+ |-------|-------------|
190
+ | Job Selection Mode | "Select from Dropdown" or "Enter Job Number" |
191
+ | Job | Dropdown selection of recent jobs |
192
+ | Job Number | Manual entry (e.g., "J00123") |
193
+
194
+ #### Update Fields
195
+
196
+ Collection of job fields that can be updated:
197
+ - Status
198
+ - Job Description
199
+ - Job Address
200
+ - And more (based on ServiceM8 API)
201
+
202
+ #### Optional Features
203
+
204
+ **Add Badges**: Same as Create operation
205
+ **Upload Attachments**: Same as Create operation
206
+ **Add Note**: Add a note to the job
207
+
208
+ #### Additional Options
209
+
210
+ | Field | Description |
211
+ |-------|-------------|
212
+ | Return Headers | Include created record UUIDs (note, attachments) in output |
213
+
214
+ ---
215
+
216
+ ## Output Schema
217
+
218
+ Both operations return a **fixed schema** - all fields are always present (empty strings, false, or empty arrays when not applicable). This ensures predictable downstream processing.
219
+
220
+ ### Create Job Output
221
+
222
+ ```json
223
+ {
224
+ "success": true,
225
+ "error": "",
226
+ "jobUuid": "abc-123-def-456",
227
+ "jobNumber": "J00789",
228
+ "clientUuid": "xyz-789-uvw-012",
229
+ "action": "created_client_and_contact",
230
+ "summary": {
231
+ "clientCreated": true,
232
+ "contactCreated": true,
233
+ "categoryAssigned": true,
234
+ "categoryName": "Plumbing",
235
+ "categoryMissing": "",
236
+ "badgesAssigned": ["Urgent", "VIP"],
237
+ "badgesMissing": ["NonexistentBadge"],
238
+ "queueAssigned": true,
239
+ "queueName": "Today",
240
+ "queueMissing": "",
241
+ "notificationsSent": {
242
+ "email": 2,
243
+ "sms": 1
244
+ },
245
+ "attachmentsUploaded": ["invoice.pdf", "photo.jpg"],
246
+ "attachmentsFailed": [],
247
+ "noteAdded": true,
248
+ "customNoteAdded": false
249
+ },
250
+ "debug": {
251
+ "classification": "business",
252
+ "contactLookupField": "email",
253
+ "matchType": {
254
+ "name": "exact",
255
+ "address": "near"
256
+ },
257
+ "reason": "Exact name match with existing client",
258
+ "clientsChecked": 45,
259
+ "executionTimeMs": 1234
260
+ },
261
+ "createdRecords": {
262
+ "clientUuid": "xyz-789-uvw-012",
263
+ "companyContactUuid": "contact-456",
264
+ "jobUuid": "abc-123-def-456",
265
+ "jobContactUuid": "jc-789",
266
+ "systemNoteUuid": "note-111",
267
+ "customNoteUuid": "",
268
+ "attachmentUuids": ["att-001", "att-002"]
269
+ }
270
+ }
271
+ ```
272
+
273
+ ### Update Job Output
274
+
275
+ ```json
276
+ {
277
+ "success": true,
278
+ "error": "",
279
+ "jobUuid": "abc-123-def-456",
280
+ "jobNumber": "J00789",
281
+ "fieldsUpdated": ["status", "job_description"],
282
+ "badgesAssigned": ["Priority"],
283
+ "badgesMissing": [],
284
+ "attachmentsUploaded": ["document.pdf"],
285
+ "attachmentsFailed": [],
286
+ "noteAdded": true,
287
+ "createdRecords": {
288
+ "noteUuid": "note-333",
289
+ "attachmentUuids": ["att-003"]
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Error Output (Continue On Fail)
295
+
296
+ When "Continue On Fail" is enabled and an error occurs:
297
+
298
+ ```json
299
+ {
300
+ "success": false,
301
+ "error": "Job with number J99999 not found",
302
+ "jobUuid": "",
303
+ "jobNumber": "",
304
+ "fieldsUpdated": [],
305
+ "badgesAssigned": [],
306
+ "badgesMissing": [],
307
+ "attachmentsUploaded": [],
308
+ "attachmentsFailed": [],
309
+ "noteAdded": false,
310
+ "createdRecords": {
311
+ "noteUuid": "",
312
+ "attachmentUuids": []
313
+ }
314
+ }
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Error Handling
320
+
321
+ ### Hard Failures (Node Stops)
322
+
323
+ | Error | Cause |
324
+ |-------|-------|
325
+ | `First Name is required (or provide a Business Name)` | No first name or business name provided |
326
+ | `At least one contact method is required` | No email, phone, or mobile provided |
327
+ | `No job selected` | Update operation with no job selected |
328
+ | `Job with UUID/number not found` | Job was deleted or doesn't exist |
329
+ | `ServiceM8 API error on {endpoint}` | API authentication, network, or server error |
330
+
331
+ ### Soft Failures (Reported in Output)
332
+
333
+ These don't stop execution but are reported in the output:
334
+
335
+ | Field | Meaning |
336
+ |-------|---------|
337
+ | `categoryMissing` | Category name not found in ServiceM8 |
338
+ | `badgesMissing` | One or more badge names not found |
339
+ | `queueMissing` | Queue name not found in ServiceM8 |
340
+ | `attachmentsFailed` | Files that failed to upload |
341
+
342
+ ---
343
+
344
+ ## Decision Matrix
345
+
346
+ ### Business Client Matching
347
+
348
+ | Name Match | Address Match | Action |
349
+ |------------|---------------|--------|
350
+ | Exact | Any | Use existing client |
351
+ | Partial | Exact/Near | Use existing client |
352
+ | Partial | None | Create new client |
353
+ | None | Any | Create new client |
354
+
355
+ ### Individual Client Matching
356
+
357
+ | Name Match | Address Match | Action |
358
+ |------------|---------------|--------|
359
+ | Exact | Exact | Use existing client |
360
+ | Exact | Different | Create new (different person, same name) |
361
+ | Partial | Exact/Near | Use existing client |
362
+ | None | Any | Create new client |
363
+
364
+ ---
365
+
366
+ ## Australian Phone Number Support
367
+
368
+ The node automatically normalizes Australian phone numbers:
369
+
370
+ | Input | Normalized |
371
+ |-------|------------|
372
+ | `0412345678` | `0412 345 678` |
373
+ | `+61412345678` | `0412 345 678` |
374
+ | `0298765432` | `02 9876 5432` |
375
+ | `98765432` | `02 9876 5432` (if looks like landline) |
376
+
377
+ ---
378
+
379
+ ## Name Format Configuration
380
+
381
+ ServiceM8 can store individual client names in two formats:
382
+
383
+ | Format | Example | When to Use |
384
+ |--------|---------|-------------|
385
+ | First Last | `John Smith` | If your ServiceM8 is configured for standard format |
386
+ | Last, First | `Smith, John` | If your ServiceM8 uses inverted format (default) |
387
+
388
+ **Important**: The name format setting must match your ServiceM8 configuration for deduplication to work correctly. Check your ServiceM8 settings under **Settings** > **Account Settings** > **Name Format**.
389
+
390
+ ---
391
+
392
+ ## ServiceM8 API Endpoints Used
393
+
394
+ | Endpoint | Method | Purpose |
395
+ |----------|--------|---------|
396
+ | `/api_1.0/companycontact.json` | GET, POST | Contact lookup/create |
397
+ | `/api_1.0/company.json` | GET, POST | Client lookup/create |
398
+ | `/api_1.0/job.json` | GET, POST | Job create/update |
399
+ | `/api_1.0/jobcontact.json` | GET, POST, DELETE | Job contact management |
400
+ | `/api_1.0/category.json` | GET | Category lookup |
401
+ | `/api_1.0/badge.json` | GET | Badge lookup |
402
+ | `/api_1.0/jobbadge.json` | POST | Apply badge to job |
403
+ | `/api_1.0/queue.json` | GET | Queue lookup |
404
+ | `/api_1.0/jobqueue.json` | POST | Assign job to queue |
405
+ | `/api_1.0/jobnote.json` | POST | Create job note |
406
+ | `/api_1.0/note.json` | POST | Create note |
407
+ | `/api_1.0/Attachment.json` | POST | Create attachment metadata |
408
+ | `/api_1.0/Attachment/{uuid}.file` | POST | Upload attachment binary |
409
+ | `/platform_service_sms` | POST | Send SMS notification |
410
+ | `/platform_service_email` | POST | Send email notification |
411
+
412
+ ---
413
+
414
+ ## Development
415
+
416
+ ### Build
417
+
418
+ ```bash
419
+ npm run build
420
+ ```
421
+
422
+ ### Local Testing
423
+
424
+ ```bash
425
+ npm run build
426
+ npm link
427
+ # Then in your n8n custom nodes directory:
428
+ npm link n8n-nodes-servicem8-jobcreation
429
+ ```
430
+
431
+ ### Project Structure
432
+
433
+ ```
434
+ n8n-nodes-servicem8-jobcreation/
435
+ ├── credentials/
436
+ │ └── ServiceM8Api.credentials.ts
437
+ ├── nodes/
438
+ │ └── ServiceM8JobCreation/
439
+ │ ├── ServiceM8JobCreation.node.ts
440
+ │ ├── servicem8.svg
441
+ │ ├── execute.ts
442
+ │ ├── types/
443
+ │ │ ├── api.ts
444
+ │ │ ├── input.ts
445
+ │ │ ├── result.ts
446
+ │ │ └── index.ts
447
+ │ ├── helpers/
448
+ │ │ ├── api.ts
449
+ │ │ ├── phoneUtils.ts
450
+ │ │ ├── addressUtils.ts
451
+ │ │ └── clientMatcher.ts
452
+ │ ├── methods/
453
+ │ │ ├── loadOptions.ts
454
+ │ │ └── index.ts
455
+ │ ├── properties/
456
+ │ │ ├── operation.ts
457
+ │ │ ├── create/
458
+ │ │ │ ├── contact.ts
459
+ │ │ │ ├── business.ts
460
+ │ │ │ ├── address.ts
461
+ │ │ │ ├── job.ts
462
+ │ │ │ ├── options/
463
+ │ │ │ │ ├── category.ts
464
+ │ │ │ │ ├── badges.ts
465
+ │ │ │ │ ├── queue.ts
466
+ │ │ │ │ ├── notifications.ts
467
+ │ │ │ │ ├── attachments.ts
468
+ │ │ │ │ ├── notes.ts
469
+ │ │ │ │ └── additionalOptions.ts
470
+ │ │ │ └── index.ts
471
+ │ │ └── update/
472
+ │ │ ├── jobSelection.ts
473
+ │ │ ├── fields.ts
474
+ │ │ ├── options.ts
475
+ │ │ └── index.ts
476
+ │ └── operations/
477
+ │ ├── create/
478
+ │ │ ├── orchestrator.ts
479
+ │ │ ├── inputProcessor.ts
480
+ │ │ ├── contactLookup.ts
481
+ │ │ ├── clientLookup.ts
482
+ │ │ ├── clientCreate.ts
483
+ │ │ ├── jobCreate.ts
484
+ │ │ ├── categoryAssign.ts
485
+ │ │ ├── queueAssign.ts
486
+ │ │ ├── notifications.ts
487
+ │ │ └── index.ts
488
+ │ ├── update/
489
+ │ │ ├── jobUpdate.ts
490
+ │ │ └── index.ts
491
+ │ └── shared/
492
+ │ ├── attachmentsUpload.ts
493
+ │ ├── badgesAssign.ts
494
+ │ ├── notesCreate.ts
495
+ │ └── index.ts
496
+ ├── package.json
497
+ ├── tsconfig.json
498
+ └── README.md
499
+ ```
500
+
501
+ ---
502
+
503
+ ## License
504
+
505
+ MIT
506
+
507
+ ---
508
+
509
+ ## Author
510
+
511
+ Trade Magnet - [www.trademagnet.com.au](https://www.trademagnet.com.au)
512
+
513
+ ---
514
+
515
+ ## Support
516
+
517
+ For issues and feature requests, please open an issue on GitHub.
@@ -0,0 +1,9 @@
1
+ import { IAuthenticateGeneric, ICredentialTestRequest, ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class ServiceM8Api implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ authenticate: IAuthenticateGeneric;
8
+ test: ICredentialTestRequest;
9
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceM8Api = void 0;
4
+ class ServiceM8Api {
5
+ constructor() {
6
+ this.name = 'serviceM8Api';
7
+ this.displayName = 'ServiceM8 API';
8
+ this.documentationUrl = 'https://developer.servicem8.com/docs/authentication';
9
+ this.properties = [
10
+ {
11
+ displayName: 'API Key',
12
+ name: 'apiKey',
13
+ type: 'string',
14
+ typeOptions: { password: true },
15
+ default: '',
16
+ required: true,
17
+ description: 'Your ServiceM8 API Key from Settings > API Access',
18
+ },
19
+ ];
20
+ this.authenticate = {
21
+ type: 'generic',
22
+ properties: {
23
+ headers: {
24
+ 'X-Api-Key': '={{$credentials.apiKey}}',
25
+ },
26
+ },
27
+ };
28
+ this.test = {
29
+ request: {
30
+ baseURL: 'https://api.servicem8.com',
31
+ url: '/api_1.0/vendor.json',
32
+ method: 'GET',
33
+ },
34
+ };
35
+ }
36
+ }
37
+ exports.ServiceM8Api = ServiceM8Api;
38
+ //# sourceMappingURL=ServiceM8Api.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceM8Api.credentials.js","sourceRoot":"","sources":["../../credentials/ServiceM8Api.credentials.ts"],"names":[],"mappings":";;;AAOA,MAAa,YAAY;IAAzB;QACC,SAAI,GAAG,cAAc,CAAC;QACtB,gBAAW,GAAG,eAAe,CAAC;QAC9B,qBAAgB,GAAG,qDAAqD,CAAC;QAEzE,eAAU,GAAsB;YAC/B;gBACC,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,mDAAmD;aAChE;SACD,CAAC;QAEF,iBAAY,GAAyB;YACpC,IAAI,EAAE,SAAS;YACf,UAAU,EAAE;gBACX,OAAO,EAAE;oBACR,WAAW,EAAE,0BAA0B;iBACvC;aACD;SACD,CAAC;QAEF,SAAI,GAA2B;YAC9B,OAAO,EAAE;gBACR,OAAO,EAAE,2BAA2B;gBACpC,GAAG,EAAE,sBAAsB;gBAC3B,MAAM,EAAE,KAAK;aACb;SACD,CAAC;IACH,CAAC;CAAA;AAjCD,oCAiCC"}
@@ -0,0 +1,3 @@
1
+ import { ServiceM8JobCreation } from './nodes/ServiceM8JobCreation/ServiceM8JobCreation.node';
2
+ import { ServiceM8Api } from './credentials/ServiceM8Api.credentials';
3
+ export { ServiceM8JobCreation, ServiceM8Api };
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceM8Api = exports.ServiceM8JobCreation = void 0;
4
+ const ServiceM8JobCreation_node_1 = require("./nodes/ServiceM8JobCreation/ServiceM8JobCreation.node");
5
+ Object.defineProperty(exports, "ServiceM8JobCreation", { enumerable: true, get: function () { return ServiceM8JobCreation_node_1.ServiceM8JobCreation; } });
6
+ const ServiceM8Api_credentials_1 = require("./credentials/ServiceM8Api.credentials");
7
+ Object.defineProperty(exports, "ServiceM8Api", { enumerable: true, get: function () { return ServiceM8Api_credentials_1.ServiceM8Api; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;AAAA,sGAA8F;AAGrF,qGAHA,gDAAoB,OAGA;AAF7B,qFAAsE;AAEvC,6FAFtB,uCAAY,OAEsB"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * ServiceM8 Smart Job Creation Node
3
+ * Creates or updates ServiceM8 jobs with intelligent client/contact deduplication
4
+ */
5
+ import type { INodeType, INodeTypeDescription } from 'n8n-workflow';
6
+ import { execute } from './execute';
7
+ export declare class ServiceM8JobCreation implements INodeType {
8
+ description: INodeTypeDescription;
9
+ methods: {
10
+ loadOptions: {
11
+ getCategories: typeof import("./methods/loadOptions").getCategories;
12
+ getBadges: typeof import("./methods/loadOptions").getBadges;
13
+ getQueues: typeof import("./methods/loadOptions").getQueues;
14
+ getJobs: typeof import("./methods/loadOptions").getJobs;
15
+ };
16
+ };
17
+ execute: typeof execute;
18
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * ServiceM8 Smart Job Creation Node
4
+ * Creates or updates ServiceM8 jobs with intelligent client/contact deduplication
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ServiceM8JobCreation = void 0;
8
+ const properties_1 = require("./properties");
9
+ const methods_1 = require("./methods");
10
+ const execute_1 = require("./execute");
11
+ class ServiceM8JobCreation {
12
+ constructor() {
13
+ this.description = {
14
+ displayName: 'ServiceM8 Smart Job Creation',
15
+ name: 'serviceM8SmartJobCreation',
16
+ icon: 'file:servicem8.svg',
17
+ group: ['transform'],
18
+ version: 1,
19
+ subtitle: '={{$parameter["operation"]}}',
20
+ description: 'Create or update ServiceM8 jobs with intelligent client/contact deduplication',
21
+ defaults: {
22
+ name: 'ServiceM8 Smart Job Creation',
23
+ },
24
+ inputs: ['main'],
25
+ outputs: ['main'],
26
+ credentials: [
27
+ {
28
+ name: 'serviceM8Api',
29
+ required: true,
30
+ },
31
+ ],
32
+ properties: properties_1.properties,
33
+ };
34
+ this.methods = methods_1.methods;
35
+ this.execute = execute_1.execute;
36
+ }
37
+ }
38
+ exports.ServiceM8JobCreation = ServiceM8JobCreation;
39
+ //# sourceMappingURL=ServiceM8JobCreation.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ServiceM8JobCreation.node.js","sourceRoot":"","sources":["../../../nodes/ServiceM8JobCreation/ServiceM8JobCreation.node.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH,6CAA0C;AAC1C,uCAAoC;AACpC,uCAAoC;AAEpC,MAAa,oBAAoB;IAAjC;QACC,gBAAW,GAAyB;YACnC,WAAW,EAAE,8BAA8B;YAC3C,IAAI,EAAE,2BAA2B;YACjC,IAAI,EAAE,oBAAoB;YAC1B,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,8BAA8B;YACxC,WAAW,EAAE,+EAA+E;YAC5F,QAAQ,EAAE;gBACT,IAAI,EAAE,8BAA8B;aACpC;YACD,MAAM,EAAE,CAAC,MAAM,CAAC;YAChB,OAAO,EAAE,CAAC,MAAM,CAAC;YACjB,WAAW,EAAE;gBACZ;oBACC,IAAI,EAAE,cAAc;oBACpB,QAAQ,EAAE,IAAI;iBACd;aACD;YACD,UAAU,EAAV,uBAAU;SACV,CAAC;QAEF,YAAO,GAAG,iBAAO,CAAC;QAClB,YAAO,GAAG,iBAAO,CAAC;IACnB,CAAC;CAAA;AAzBD,oDAyBC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Execute Method
3
+ * Main execution logic for the ServiceM8 Smart Job Creation node
4
+ */
5
+ import type { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
6
+ export declare function execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;