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.
- package/README.md +517 -0
- package/dist/credentials/ServiceM8Api.credentials.d.ts +9 -0
- package/dist/credentials/ServiceM8Api.credentials.js +38 -0
- package/dist/credentials/ServiceM8Api.credentials.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/ServiceM8JobCreation.node.d.ts +18 -0
- package/dist/nodes/ServiceM8JobCreation/ServiceM8JobCreation.node.js +39 -0
- package/dist/nodes/ServiceM8JobCreation/ServiceM8JobCreation.node.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/execute.d.ts +6 -0
- package/dist/nodes/ServiceM8JobCreation/execute.js +47 -0
- package/dist/nodes/ServiceM8JobCreation/execute.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/addressUtils.d.ts +56 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/addressUtils.js +124 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/addressUtils.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/api.d.ts +180 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/api.js +418 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/api.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/clientMatcher.d.ts +67 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/clientMatcher.js +216 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/clientMatcher.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/phoneUtils.d.ts +35 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/phoneUtils.js +122 -0
- package/dist/nodes/ServiceM8JobCreation/helpers/phoneUtils.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/methods/index.d.ts +13 -0
- package/dist/nodes/ServiceM8JobCreation/methods/index.js +17 -0
- package/dist/nodes/ServiceM8JobCreation/methods/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/methods/loadOptions.d.ts +9 -0
- package/dist/nodes/ServiceM8JobCreation/methods/loadOptions.js +61 -0
- package/dist/nodes/ServiceM8JobCreation/methods/loadOptions.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/categoryAssign.d.ts +22 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/categoryAssign.js +61 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/categoryAssign.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/clientCreate.d.ts +36 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/clientCreate.js +66 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/clientCreate.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/clientLookup.d.ts +28 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/clientLookup.js +46 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/clientLookup.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/contactLookup.d.ts +18 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/contactLookup.js +48 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/contactLookup.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/index.d.ts +12 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/index.js +40 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/inputProcessor.d.ts +63 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/inputProcessor.js +176 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/inputProcessor.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/jobCreate.d.ts +43 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/jobCreate.js +82 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/jobCreate.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/notifications.d.ts +38 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/notifications.js +123 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/notifications.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/orchestrator.d.ts +12 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/orchestrator.js +192 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/orchestrator.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/queueAssign.d.ts +22 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/queueAssign.js +61 -0
- package/dist/nodes/ServiceM8JobCreation/operations/create/queueAssign.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/index.d.ts +8 -0
- package/dist/nodes/ServiceM8JobCreation/operations/index.js +35 -0
- package/dist/nodes/ServiceM8JobCreation/operations/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/attachmentsUpload.d.ts +41 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/attachmentsUpload.js +243 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/attachmentsUpload.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/badgesAssign.d.ts +21 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/badgesAssign.js +65 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/badgesAssign.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/index.d.ts +7 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/index.js +15 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/notesCreate.d.ts +42 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/notesCreate.js +103 -0
- package/dist/nodes/ServiceM8JobCreation/operations/shared/notesCreate.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/update/index.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/operations/update/index.js +9 -0
- package/dist/nodes/ServiceM8JobCreation/operations/update/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/operations/update/jobUpdate.d.ts +10 -0
- package/dist/nodes/ServiceM8JobCreation/operations/update/jobUpdate.js +239 -0
- package/dist/nodes/ServiceM8JobCreation/operations/update/jobUpdate.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/address.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/address.js +145 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/address.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/business.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/business.js +22 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/business.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/contact.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/contact.js +85 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/contact.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/index.d.ts +10 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/index.js +30 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/job.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/job.js +43 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/job.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/additionalOptions.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/additionalOptions.js +49 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/additionalOptions.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/attachments.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/attachments.js +151 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/attachments.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/badges.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/badges.js +65 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/badges.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/category.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/category.js +65 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/category.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/index.d.ts +12 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/index.js +38 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/notes.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/notes.js +49 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/notes.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/notifications.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/notifications.js +197 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/notifications.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/queue.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/queue.js +65 -0
- package/dist/nodes/ServiceM8JobCreation/properties/create/options/queue.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/index.d.ts +9 -0
- package/dist/nodes/ServiceM8JobCreation/properties/index.js +23 -0
- package/dist/nodes/ServiceM8JobCreation/properties/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/operation.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/operation.js +28 -0
- package/dist/nodes/ServiceM8JobCreation/properties/operation.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/fields.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/fields.js +74 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/fields.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/index.d.ts +8 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/index.js +22 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/jobSelection.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/jobSelection.js +63 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/jobSelection.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/options.d.ts +5 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/options.js +142 -0
- package/dist/nodes/ServiceM8JobCreation/properties/update/options.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/servicem8.svg +75 -0
- package/dist/nodes/ServiceM8JobCreation/types/api.d.ts +59 -0
- package/dist/nodes/ServiceM8JobCreation/types/api.js +34 -0
- package/dist/nodes/ServiceM8JobCreation/types/api.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/types/index.d.ts +7 -0
- package/dist/nodes/ServiceM8JobCreation/types/index.js +21 -0
- package/dist/nodes/ServiceM8JobCreation/types/index.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/types/input.d.ts +119 -0
- package/dist/nodes/ServiceM8JobCreation/types/input.js +6 -0
- package/dist/nodes/ServiceM8JobCreation/types/input.js.map +1 -0
- package/dist/nodes/ServiceM8JobCreation/types/result.d.ts +79 -0
- package/dist/nodes/ServiceM8JobCreation/types/result.js +96 -0
- package/dist/nodes/ServiceM8JobCreation/types/result.js.map +1 -0
- 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;
|