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
@@ -0,0 +1,418 @@
1
+ "use strict";
2
+ /**
3
+ * ServiceM8 API Helper Functions
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.uploadAttachmentBinary = exports.findQueueByName = exports.findCategoryByName = exports.findBadgeByName = exports.createJobNote = exports.getJob = exports.deleteJobContact = exports.uploadBinaryAsAttachment = exports.sendEmailLegacy = exports.sendEmail = exports.sendSms = exports.assignJobToQueue = exports.assignBadgesToJob = exports.updateJob = exports.createJobContact = exports.createJob = exports.createCompanyContact = exports.createClient = exports.parseArrayResponse = exports.escapeOData = exports.buildODataFilter = exports.extractUuidFromResponse = exports.serviceM8Request = void 0;
7
+ const n8n_workflow_1 = require("n8n-workflow");
8
+ const BASE_URL = 'https://api.servicem8.com';
9
+ /**
10
+ * Make an authenticated request to the ServiceM8 API
11
+ */
12
+ async function serviceM8Request(context, options) {
13
+ const { method = 'GET', endpoint, body, query, returnFullResponse = false } = options;
14
+ const requestOptions = {
15
+ method,
16
+ url: `${BASE_URL}${endpoint}`,
17
+ headers: {
18
+ Accept: 'application/json',
19
+ 'Content-Type': 'application/json',
20
+ },
21
+ json: true,
22
+ returnFullResponse,
23
+ };
24
+ if (body) {
25
+ requestOptions.body = body;
26
+ }
27
+ if (query) {
28
+ requestOptions.qs = query;
29
+ }
30
+ try {
31
+ const response = await context.helpers.httpRequestWithAuthentication.call(context, 'serviceM8Api', requestOptions);
32
+ return response;
33
+ }
34
+ catch (error) {
35
+ const err = error;
36
+ throw new n8n_workflow_1.NodeApiError(context.getNode(), { message: err.message }, {
37
+ message: `ServiceM8 API error on ${endpoint}`,
38
+ });
39
+ }
40
+ }
41
+ exports.serviceM8Request = serviceM8Request;
42
+ /**
43
+ * Extract UUID from response headers (for POST requests that return x-record-uuid)
44
+ */
45
+ function extractUuidFromResponse(response) {
46
+ var _a;
47
+ if (!response || typeof response !== 'object') {
48
+ return null;
49
+ }
50
+ // Full response with headers
51
+ const fullResponse = response;
52
+ if ((_a = fullResponse.headers) === null || _a === void 0 ? void 0 : _a['x-record-uuid']) {
53
+ return fullResponse.headers['x-record-uuid'];
54
+ }
55
+ // Direct response with uuid field
56
+ const directResponse = response;
57
+ if (directResponse.uuid) {
58
+ return directResponse.uuid;
59
+ }
60
+ return null;
61
+ }
62
+ exports.extractUuidFromResponse = extractUuidFromResponse;
63
+ function buildODataFilter(conditions) {
64
+ return conditions
65
+ .map((c) => {
66
+ const value = typeof c.value === 'string' ? `'${escapeOData(c.value)}'` : c.value;
67
+ return `${c.field} ${c.operator} ${value}`;
68
+ })
69
+ .join(' and ');
70
+ }
71
+ exports.buildODataFilter = buildODataFilter;
72
+ /**
73
+ * Escape single quotes for OData filter values
74
+ */
75
+ function escapeOData(value) {
76
+ return value.replace(/'/g, "''");
77
+ }
78
+ exports.escapeOData = escapeOData;
79
+ /**
80
+ * Parse API response to ensure it's always an array
81
+ */
82
+ function parseArrayResponse(response) {
83
+ if (Array.isArray(response)) {
84
+ return response;
85
+ }
86
+ if (response && typeof response === 'object' && 'uuid' in response) {
87
+ return [response];
88
+ }
89
+ return [];
90
+ }
91
+ exports.parseArrayResponse = parseArrayResponse;
92
+ /**
93
+ * Create a company (client) in ServiceM8
94
+ */
95
+ async function createClient(context, data) {
96
+ const response = await serviceM8Request(context, {
97
+ method: 'POST',
98
+ endpoint: '/api_1.0/company.json',
99
+ body: {
100
+ ...data,
101
+ active: 1,
102
+ },
103
+ returnFullResponse: true,
104
+ });
105
+ const uuid = extractUuidFromResponse(response);
106
+ if (!uuid) {
107
+ throw new Error('Failed to get UUID from client creation response');
108
+ }
109
+ return uuid;
110
+ }
111
+ exports.createClient = createClient;
112
+ /**
113
+ * Create a company contact in ServiceM8
114
+ */
115
+ async function createCompanyContact(context, data) {
116
+ const response = await serviceM8Request(context, {
117
+ method: 'POST',
118
+ endpoint: '/api_1.0/companycontact.json',
119
+ body: {
120
+ ...data,
121
+ active: 1,
122
+ type: data.type || 'BILLING',
123
+ },
124
+ returnFullResponse: true,
125
+ });
126
+ const uuid = extractUuidFromResponse(response);
127
+ if (!uuid) {
128
+ throw new Error('Failed to get UUID from contact creation response');
129
+ }
130
+ return uuid;
131
+ }
132
+ exports.createCompanyContact = createCompanyContact;
133
+ /**
134
+ * Create a job in ServiceM8
135
+ */
136
+ async function createJob(context, data) {
137
+ const response = await serviceM8Request(context, {
138
+ method: 'POST',
139
+ endpoint: '/api_1.0/job.json',
140
+ body: {
141
+ ...data,
142
+ active: 1,
143
+ },
144
+ returnFullResponse: true,
145
+ });
146
+ const uuid = extractUuidFromResponse(response);
147
+ if (!uuid) {
148
+ throw new Error('Failed to get UUID from job creation response');
149
+ }
150
+ return { uuid };
151
+ }
152
+ exports.createJob = createJob;
153
+ /**
154
+ * Create a job contact in ServiceM8
155
+ */
156
+ async function createJobContact(context, data) {
157
+ var _a;
158
+ const response = await serviceM8Request(context, {
159
+ method: 'POST',
160
+ endpoint: '/api_1.0/jobcontact.json',
161
+ body: {
162
+ ...data,
163
+ active: 1,
164
+ type: 'JOB',
165
+ is_primary_contact: (_a = data.is_primary_contact) !== null && _a !== void 0 ? _a : true,
166
+ },
167
+ returnFullResponse: true,
168
+ });
169
+ const uuid = extractUuidFromResponse(response);
170
+ if (!uuid) {
171
+ throw new Error('Failed to get UUID from job contact creation response');
172
+ }
173
+ return uuid;
174
+ }
175
+ exports.createJobContact = createJobContact;
176
+ /**
177
+ * Update a job (for category assignment)
178
+ */
179
+ async function updateJob(context, jobUuid, data) {
180
+ await serviceM8Request(context, {
181
+ method: 'POST',
182
+ endpoint: `/api_1.0/job/${jobUuid}.json`,
183
+ body: data,
184
+ });
185
+ }
186
+ exports.updateJob = updateJob;
187
+ /**
188
+ * Assign badges to a job by updating the job's badges field
189
+ * The badges field is a JSON array string of badge UUIDs
190
+ */
191
+ async function assignBadgesToJob(context, jobUuid, badgeUuids) {
192
+ // ServiceM8 stores badges as a JSON array string in the job record
193
+ const badgesJson = JSON.stringify(badgeUuids);
194
+ await serviceM8Request(context, {
195
+ method: 'POST',
196
+ endpoint: `/api_1.0/job/${jobUuid}.json`,
197
+ body: {
198
+ badges: badgesJson,
199
+ },
200
+ });
201
+ }
202
+ exports.assignBadgesToJob = assignBadgesToJob;
203
+ /**
204
+ * Assign a job to a queue by updating the job's queue_uuid field
205
+ */
206
+ async function assignJobToQueue(context, jobUuid, queueUuid) {
207
+ await serviceM8Request(context, {
208
+ method: 'POST',
209
+ endpoint: `/api_1.0/job/${jobUuid}.json`,
210
+ body: {
211
+ queue_uuid: queueUuid,
212
+ },
213
+ });
214
+ }
215
+ exports.assignJobToQueue = assignJobToQueue;
216
+ /**
217
+ * Send SMS notification via ServiceM8
218
+ */
219
+ async function sendSms(context, to, message, jobUuid) {
220
+ const body = {
221
+ to,
222
+ message,
223
+ };
224
+ if (jobUuid) {
225
+ body.regardingJobUUID = jobUuid;
226
+ }
227
+ await serviceM8Request(context, {
228
+ method: 'POST',
229
+ endpoint: '/platform_service_sms',
230
+ body,
231
+ });
232
+ }
233
+ exports.sendSms = sendSms;
234
+ /**
235
+ * Send email notification via ServiceM8
236
+ * Supports both HTML and plain text format, plus attachments
237
+ */
238
+ async function sendEmail(context, options) {
239
+ const body = {
240
+ to: options.to,
241
+ subject: options.subject,
242
+ };
243
+ // Use either HTML or text body
244
+ if (options.htmlBody) {
245
+ body.htmlBody = options.htmlBody;
246
+ }
247
+ else if (options.textBody) {
248
+ body.textBody = options.textBody;
249
+ }
250
+ if (options.jobUuid) {
251
+ body.regardingJobUUID = options.jobUuid;
252
+ }
253
+ // Add attachments if provided (API expects 'attachments' field)
254
+ if (options.attachmentUuids && options.attachmentUuids.length > 0) {
255
+ body.attachments = options.attachmentUuids;
256
+ }
257
+ await serviceM8Request(context, {
258
+ method: 'POST',
259
+ endpoint: '/platform_service_email',
260
+ body,
261
+ });
262
+ }
263
+ exports.sendEmail = sendEmail;
264
+ /**
265
+ * Legacy sendEmail function for backward compatibility
266
+ * @deprecated Use sendEmail with options object instead
267
+ */
268
+ async function sendEmailLegacy(context, to, subject, htmlBody, jobUuid) {
269
+ await sendEmail(context, {
270
+ to,
271
+ subject,
272
+ htmlBody,
273
+ jobUuid,
274
+ });
275
+ }
276
+ exports.sendEmailLegacy = sendEmailLegacy;
277
+ /**
278
+ * Upload binary data as a job attachment and return the UUID
279
+ * This can be used to attach files to emails
280
+ */
281
+ async function uploadBinaryAsAttachment(context, itemIndex, jobUuid, binaryPropertyName) {
282
+ try {
283
+ const binaryData = context.helpers.assertBinaryData(itemIndex, binaryPropertyName);
284
+ const buffer = await context.helpers.getBinaryDataBuffer(itemIndex, binaryPropertyName);
285
+ const fileName = binaryData.fileName || 'attachment';
286
+ const mimeType = binaryData.mimeType || 'application/octet-stream';
287
+ // Determine file extension
288
+ const extension = fileName.includes('.') ? '.' + fileName.split('.').pop() : '';
289
+ // Step 1: Create attachment metadata
290
+ const metadataResponse = await serviceM8Request(context, {
291
+ method: 'POST',
292
+ endpoint: '/api_1.0/Attachment.json',
293
+ body: {
294
+ related_object: 'job',
295
+ related_object_uuid: jobUuid,
296
+ attachment_name: fileName,
297
+ file_type: extension,
298
+ active: 1,
299
+ },
300
+ returnFullResponse: true,
301
+ });
302
+ const attachmentUuid = extractUuidFromResponse(metadataResponse);
303
+ if (!attachmentUuid) {
304
+ return null;
305
+ }
306
+ // Step 2: Upload binary content
307
+ await uploadAttachmentBinary(context, attachmentUuid, buffer, fileName, mimeType);
308
+ return { uuid: attachmentUuid, fileName };
309
+ }
310
+ catch {
311
+ return null;
312
+ }
313
+ }
314
+ exports.uploadBinaryAsAttachment = uploadBinaryAsAttachment;
315
+ /**
316
+ * Delete a job contact
317
+ */
318
+ async function deleteJobContact(context, contactUuid) {
319
+ await serviceM8Request(context, {
320
+ method: 'DELETE',
321
+ endpoint: `/api_1.0/jobcontact/${contactUuid}.json`,
322
+ });
323
+ }
324
+ exports.deleteJobContact = deleteJobContact;
325
+ /**
326
+ * Get job details
327
+ */
328
+ async function getJob(context, jobUuid) {
329
+ const response = await serviceM8Request(context, {
330
+ method: 'GET',
331
+ endpoint: `/api_1.0/job/${jobUuid}.json`,
332
+ });
333
+ return response;
334
+ }
335
+ exports.getJob = getJob;
336
+ /**
337
+ * Create a job note
338
+ * Uses /api_1.0/note.json with related_object and related_object_uuid
339
+ */
340
+ async function createJobNote(context, jobUuid, note) {
341
+ const response = await serviceM8Request(context, {
342
+ method: 'POST',
343
+ endpoint: '/api_1.0/note.json',
344
+ body: {
345
+ related_object: 'job',
346
+ related_object_uuid: jobUuid,
347
+ note,
348
+ },
349
+ returnFullResponse: true,
350
+ });
351
+ const uuid = extractUuidFromResponse(response);
352
+ if (!uuid) {
353
+ throw new Error('Failed to get UUID from job note creation response');
354
+ }
355
+ return uuid;
356
+ }
357
+ exports.createJobNote = createJobNote;
358
+ /**
359
+ * Find badge UUID by name (case-insensitive)
360
+ */
361
+ function findBadgeByName(badges, searchName) {
362
+ const normalized = searchName.trim().toLowerCase();
363
+ return badges.find((b) => b.name.trim().toLowerCase() === normalized) || null;
364
+ }
365
+ exports.findBadgeByName = findBadgeByName;
366
+ /**
367
+ * Find category UUID by name (case-insensitive)
368
+ */
369
+ function findCategoryByName(categories, searchName) {
370
+ const normalized = searchName.trim().toLowerCase();
371
+ return categories.find((c) => c.name.trim().toLowerCase() === normalized) || null;
372
+ }
373
+ exports.findCategoryByName = findCategoryByName;
374
+ /**
375
+ * Find queue UUID by name (case-insensitive)
376
+ */
377
+ function findQueueByName(queues, searchName) {
378
+ const normalized = searchName.trim().toLowerCase();
379
+ return queues.find((q) => q.name.trim().toLowerCase() === normalized) || null;
380
+ }
381
+ exports.findQueueByName = findQueueByName;
382
+ /**
383
+ * Upload binary content to an attachment
384
+ * Uses multipart/form-data format
385
+ */
386
+ async function uploadAttachmentBinary(context, attachmentUuid, buffer, fileName, mimeType) {
387
+ // Create form data boundary
388
+ const boundary = '----n8nFormBoundary' + Date.now().toString(16);
389
+ // Build multipart form data manually
390
+ const formParts = [];
391
+ // File field
392
+ formParts.push(Buffer.from(`--${boundary}\r\n`));
393
+ formParts.push(Buffer.from(`Content-Disposition: form-data; name="file"; filename="${fileName}"\r\n`));
394
+ formParts.push(Buffer.from(`Content-Type: ${mimeType}\r\n\r\n`));
395
+ formParts.push(buffer);
396
+ formParts.push(Buffer.from('\r\n'));
397
+ // End boundary
398
+ formParts.push(Buffer.from(`--${boundary}--\r\n`));
399
+ const formBody = Buffer.concat(formParts);
400
+ try {
401
+ await context.helpers.httpRequestWithAuthentication.call(context, 'serviceM8Api', {
402
+ method: 'POST',
403
+ url: `${BASE_URL}/api_1.0/Attachment/${attachmentUuid}.file`,
404
+ headers: {
405
+ 'Content-Type': `multipart/form-data; boundary=${boundary}`,
406
+ },
407
+ body: formBody,
408
+ });
409
+ }
410
+ catch (error) {
411
+ const err = error;
412
+ throw new n8n_workflow_1.NodeApiError(context.getNode(), { message: err.message }, {
413
+ message: `Failed to upload attachment binary: ${fileName}`,
414
+ });
415
+ }
416
+ }
417
+ exports.uploadAttachmentBinary = uploadAttachmentBinary;
418
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../../../nodes/ServiceM8JobCreation/helpers/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Client Matching Logic
3
+ * Implements fuzzy name + address matching for client deduplication
4
+ */
5
+ import type { ServiceM8Client, AddressParts, NameMatchResult, MatchResult, ClientMatchResult } from '../types/index';
6
+ /**
7
+ * Compare two names and return match quality
8
+ * - 'exact': normalized strings are equal
9
+ * - 'partial': one contains the other, or starts with the other
10
+ * - 'none': no match
11
+ */
12
+ export declare function matchClientName(searchName: string, clientName: string): NameMatchResult;
13
+ export type NameFormat = 'firstLast' | 'lastFirst';
14
+ /**
15
+ * Build a client name from first/last names or business name
16
+ * For individuals: format depends on nameFormat parameter
17
+ * - 'firstLast': "John Smith"
18
+ * - 'lastFirst': "Smith, John" (ServiceM8 default)
19
+ * For businesses: businessName
20
+ */
21
+ export declare function buildClientName(firstName: string, lastName: string, businessName: string, email: string, nameFormat?: NameFormat): {
22
+ name: string;
23
+ isBusiness: boolean;
24
+ };
25
+ /**
26
+ * Build both possible name formats for matching purposes
27
+ * Returns both "First Last" and "Last, First" versions
28
+ */
29
+ export declare function buildBothNameFormats(firstName: string, lastName: string): {
30
+ firstLast: string;
31
+ lastFirst: string;
32
+ };
33
+ /**
34
+ * Find the best matching client from a list
35
+ * Implements the decision matrix:
36
+ *
37
+ * For BUSINESSES:
38
+ * - Exact name → use existing
39
+ * - Partial name + exact/near address → use existing (same business, name variant)
40
+ * - Partial name + no address match → create new
41
+ *
42
+ * For INDIVIDUALS:
43
+ * - Exact name + exact address → use existing
44
+ * - Exact name + different address → create new (different person, same name)
45
+ * - Partial name + exact/near address → use existing
46
+ */
47
+ export declare function findBestMatchingClient(searchName: string, searchAddress: AddressParts, clients: ServiceM8Client[], isBusiness: boolean): ClientMatchResult;
48
+ /**
49
+ * Determine the action to take based on contact and client matches
50
+ */
51
+ export interface ActionDecisionInput {
52
+ contactExists: boolean;
53
+ existingContactClientUuid: string | null;
54
+ matchedClient: ServiceM8Client | null;
55
+ matchType: MatchResult;
56
+ matchReason: string;
57
+ isBusiness: boolean;
58
+ kind: 'business' | 'person';
59
+ }
60
+ export interface ActionDecisionResult {
61
+ action: 'create_client_and_contact' | 'create_contact_and_job' | 'create_job_only';
62
+ reason: string;
63
+ needsClient: boolean;
64
+ needsContact: boolean;
65
+ clientUuid: string | null;
66
+ }
67
+ export declare function determineAction(input: ActionDecisionInput): ActionDecisionResult;