@xapp/stentor-service-fieldpulse 1.64.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/LICENSE.md +176 -0
- package/README.md +19 -0
- package/lib/Data/JobTypes.d.ts +18 -0
- package/lib/Data/JobTypes.js +132 -0
- package/lib/Data/JobTypes.js.map +1 -0
- package/lib/FieldPulseService.d.ts +41 -0
- package/lib/FieldPulseService.js +689 -0
- package/lib/FieldPulseService.js.map +1 -0
- package/lib/ai.d.ts +21 -0
- package/lib/ai.js +117 -0
- package/lib/ai.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +19 -0
- package/lib/index.js.map +1 -0
- package/lib/models.d.ts +167 -0
- package/lib/models.js +13 -0
- package/lib/models.js.map +1 -0
- package/lib/util.d.ts +14 -0
- package/lib/util.js +169 -0
- package/lib/util.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.FieldPulseService = void 0;
|
|
16
|
+
/*! Copyright (c) 2024, XAPP AI */
|
|
17
|
+
const stentor_service_fetch_1 = require("stentor-service-fetch");
|
|
18
|
+
const stentor_logger_1 = require("stentor-logger");
|
|
19
|
+
const axios_1 = __importDefault(require("axios"));
|
|
20
|
+
const ai_1 = require("./ai");
|
|
21
|
+
const moment_1 = __importDefault(require("moment"));
|
|
22
|
+
const JobTypes_1 = require("./Data/JobTypes");
|
|
23
|
+
const base_url = "https://ywe3crmpll.execute-api.us-east-2.amazonaws.com/stage/";
|
|
24
|
+
const lead_source = "XAPP AI";
|
|
25
|
+
const default_tag_color = "#0983b6"; // XAPP Blue
|
|
26
|
+
const util_1 = require("./util");
|
|
27
|
+
class FieldPulseService extends stentor_service_fetch_1.FetchService {
|
|
28
|
+
constructor(props) {
|
|
29
|
+
super(props);
|
|
30
|
+
this.props = Object.assign({}, props);
|
|
31
|
+
if (!this.props.channel) {
|
|
32
|
+
this.props.channel = "Chat";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
getAvailability(range, options) {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
var _a, _b, _c, _d, _e, _f;
|
|
38
|
+
const daysOut = this.props.lookAheadDays | 20; // Default to 20 days out
|
|
39
|
+
const availability = {
|
|
40
|
+
range,
|
|
41
|
+
unavailabilities: []
|
|
42
|
+
};
|
|
43
|
+
if (!options) {
|
|
44
|
+
options = {
|
|
45
|
+
blockedDays: []
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
// Get all appointments on or after the start date
|
|
49
|
+
const startDate = ((_a = range === null || range === void 0 ? void 0 : range.start) === null || _a === void 0 ? void 0 : _a.date) ? (0, moment_1.default)(range.start.date).unix() : new Date().getTime();
|
|
50
|
+
const appointments = yield this.getJobs({
|
|
51
|
+
createdOnOrAfter: (0, moment_1.default)(startDate).unix()
|
|
52
|
+
});
|
|
53
|
+
if (appointments.status !== "Success") {
|
|
54
|
+
return Promise.resolve(availability); // All available if we fail
|
|
55
|
+
}
|
|
56
|
+
// Booking dates as yyyy-mm-dd
|
|
57
|
+
const bookings = [];
|
|
58
|
+
// Any full days?
|
|
59
|
+
// loop through the appointments and add the full days to the unavailabilities
|
|
60
|
+
(_c = (_b = appointments.data) === null || _b === void 0 ? void 0 : _b.response) === null || _c === void 0 ? void 0 : _c.forEach((appointment) => {
|
|
61
|
+
bookings.push((0, moment_1.default)(appointment.start_time).format("YYYY-MM-DD"));
|
|
62
|
+
});
|
|
63
|
+
// Add locked days for job type (usually skip next N). This needs a map (jobType: skippedDays) in the CRM constructor
|
|
64
|
+
if ((options === null || options === void 0 ? void 0 : options.jobType) && ((_d = this.props) === null || _d === void 0 ? void 0 : _d.delayedJobTypes)) {
|
|
65
|
+
if (this.props.delayedJobTypes.indexOf((_e = options === null || options === void 0 ? void 0 : options.jobType) === null || _e === void 0 ? void 0 : _e.id) !== -1) {
|
|
66
|
+
const nextDays = (0, util_1.getNextDays)(3);
|
|
67
|
+
const skippedDays = nextDays.map((date) => ({
|
|
68
|
+
date,
|
|
69
|
+
available: false
|
|
70
|
+
}));
|
|
71
|
+
availability.unavailabilities = availability.unavailabilities.concat(skippedDays);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Add class specific blocked days
|
|
75
|
+
if ((_f = options === null || options === void 0 ? void 0 : options.jobType) === null || _f === void 0 ? void 0 : _f.class) {
|
|
76
|
+
let daysToSkip = 0;
|
|
77
|
+
switch (options.jobType.class) {
|
|
78
|
+
case "ESTIMATION":
|
|
79
|
+
case "MAINTENANCE":
|
|
80
|
+
case "INSTALLATION":
|
|
81
|
+
daysToSkip = 5;
|
|
82
|
+
break;
|
|
83
|
+
case "REPAIR":
|
|
84
|
+
daysToSkip = 2;
|
|
85
|
+
break;
|
|
86
|
+
default:
|
|
87
|
+
daysToSkip = 0;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
const nextDays = (0, util_1.getNextDays)(daysToSkip);
|
|
91
|
+
const skippedDays = nextDays.map((date) => ({
|
|
92
|
+
date,
|
|
93
|
+
available: false
|
|
94
|
+
}));
|
|
95
|
+
availability.unavailabilities = availability.unavailabilities.concat(skippedDays);
|
|
96
|
+
}
|
|
97
|
+
// Update blocked days on calendar based on availability
|
|
98
|
+
options = this.setBlockedDays(daysOut, availability, bookings, options);
|
|
99
|
+
// Add explicitly specified blocked days (holidays)
|
|
100
|
+
const blockedDays = (options === null || options === void 0 ? void 0 : options.blockedDays) || this.props.blockedDays;
|
|
101
|
+
if (blockedDays) {
|
|
102
|
+
const holidays = blockedDays.map((date) => ({
|
|
103
|
+
date,
|
|
104
|
+
available: false
|
|
105
|
+
}));
|
|
106
|
+
availability.unavailabilities = availability.unavailabilities.concat(holidays);
|
|
107
|
+
}
|
|
108
|
+
return Promise.resolve(availability);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
setBlockedDays(daysOut, availability, bookings, options) {
|
|
112
|
+
const nextDays = (0, util_1.getNextDays)(daysOut);
|
|
113
|
+
// Init empty array
|
|
114
|
+
if (!options.blockedDays) {
|
|
115
|
+
options.blockedDays = [];
|
|
116
|
+
}
|
|
117
|
+
// Go through next {daysOut} days and check if there are any days to block
|
|
118
|
+
nextDays.forEach((date) => {
|
|
119
|
+
// Count how many matching bookings we have for the day
|
|
120
|
+
const dayUnavailable = bookings.filter((x) => x === date.date).length >= (this.props.maxJobsPerDay | 4);
|
|
121
|
+
const match = availability.unavailabilities.find((d) => d.date.date === date.date);
|
|
122
|
+
if (match && !match.available) {
|
|
123
|
+
options.blockedDays.push(date);
|
|
124
|
+
}
|
|
125
|
+
else if (dayUnavailable) {
|
|
126
|
+
options.blockedDays.push(date);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
return options;
|
|
130
|
+
}
|
|
131
|
+
getJobType(message, externalLead) {
|
|
132
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
133
|
+
const jobTypes = (0, JobTypes_1.getJobTypes)();
|
|
134
|
+
const aiService = new ai_1.AIService({
|
|
135
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
136
|
+
jobTypes
|
|
137
|
+
});
|
|
138
|
+
const response = yield aiService.selectJobCategoryFromDescription(message, Object.keys(jobTypes.Category));
|
|
139
|
+
let jobType;
|
|
140
|
+
if (response === null || response === void 0 ? void 0 : response.id) {
|
|
141
|
+
jobType = {
|
|
142
|
+
id: response.id,
|
|
143
|
+
name: response.name
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
switch (response === null || response === void 0 ? void 0 : response.name) {
|
|
147
|
+
case "Install":
|
|
148
|
+
jobType.class = "INSTALLATION";
|
|
149
|
+
break;
|
|
150
|
+
case "Repair":
|
|
151
|
+
jobType.class = "REPAIR";
|
|
152
|
+
break;
|
|
153
|
+
case "Diagnostic":
|
|
154
|
+
jobType.class = "ESTIMATION";
|
|
155
|
+
break;
|
|
156
|
+
case "Maintenance":
|
|
157
|
+
jobType.class = "MAINTENANCE";
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
if (jobType === null || jobType === void 0 ? void 0 : jobType.id) {
|
|
163
|
+
return jobType;
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// Send the lead or scheduling request
|
|
171
|
+
send(externalLead, extras) {
|
|
172
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
173
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
174
|
+
const customerQuery = {};
|
|
175
|
+
const crmResponse = {
|
|
176
|
+
status: "Failure",
|
|
177
|
+
message: ""
|
|
178
|
+
};
|
|
179
|
+
try {
|
|
180
|
+
let transcript = "";
|
|
181
|
+
(_a = externalLead.transcript) === null || _a === void 0 ? void 0 : _a.forEach((x) => {
|
|
182
|
+
var _a, _b;
|
|
183
|
+
return (transcript += `${((_a = x.from) === null || _a === void 0 ? void 0 : _a.id) != this.props.appId && ((_b = x.from) === null || _b === void 0 ? void 0 : _b.id) != "bot" ? "user: " : this.props.appId + ": "} ${x.message} \n`);
|
|
184
|
+
});
|
|
185
|
+
// Parse first/last name
|
|
186
|
+
const names = (0, util_1.getName)(externalLead);
|
|
187
|
+
const address = (_b = externalLead.fields.find((x) => x.name == "ADDRESS")) === null || _b === void 0 ? void 0 : _b.value;
|
|
188
|
+
const phone = (_c = externalLead.fields.find((x) => x.name == "PHONE")) === null || _c === void 0 ? void 0 : _c.value;
|
|
189
|
+
const email = (_d = externalLead.fields.find((x) => x.name == "EMAIL")) === null || _d === void 0 ? void 0 : _d.value;
|
|
190
|
+
const message = (_e = externalLead.fields.find((x) => x.name == "MESSAGE")) === null || _e === void 0 ? void 0 : _e.value;
|
|
191
|
+
const dateTime = (_f = externalLead.fields.find((x) => x.name == "DATETIME")) === null || _f === void 0 ? void 0 : _f.value;
|
|
192
|
+
const preferredTime = (_g = externalLead.fields.find((x) => x.name == "PREFERRED_TIME")) === null || _g === void 0 ? void 0 : _g.value;
|
|
193
|
+
const consentApproval = (_h = externalLead.fields.find((x) => x.name == "CONSENT_APPROVAL")) === null || _h === void 0 ? void 0 : _h.value;
|
|
194
|
+
let parsedAddress;
|
|
195
|
+
try {
|
|
196
|
+
parsedAddress = yield (0, util_1.parseAddress)(address);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Invalid address "${address}"`);
|
|
200
|
+
}
|
|
201
|
+
const crmRequest = {
|
|
202
|
+
first_name: names.firstName,
|
|
203
|
+
last_name: names.lastName,
|
|
204
|
+
phone,
|
|
205
|
+
email,
|
|
206
|
+
job_notes: message,
|
|
207
|
+
notes: transcript.substring(0, 600), // Limit to 600 characters (api constraint)
|
|
208
|
+
lead_source,
|
|
209
|
+
status: "lead",
|
|
210
|
+
customfields: [
|
|
211
|
+
{
|
|
212
|
+
id: 1,
|
|
213
|
+
value: lead_source
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
};
|
|
217
|
+
if (parsedAddress) {
|
|
218
|
+
crmRequest.address_1 = parsedAddress.addressLine1;
|
|
219
|
+
crmRequest.city = parsedAddress.placeName;
|
|
220
|
+
crmRequest.state = parsedAddress.stateAbbreviation;
|
|
221
|
+
crmRequest.zip_code = parsedAddress.zipCode;
|
|
222
|
+
}
|
|
223
|
+
// Check if customer exists
|
|
224
|
+
if (phone) {
|
|
225
|
+
customerQuery.phone = phone;
|
|
226
|
+
}
|
|
227
|
+
if (email) {
|
|
228
|
+
customerQuery.email = email;
|
|
229
|
+
}
|
|
230
|
+
const customerMatches = yield this.getCustomers(customerQuery);
|
|
231
|
+
// Customer exists, use this account
|
|
232
|
+
if (customerMatches.status === "Success" && ((_j = customerMatches.data) === null || _j === void 0 ? void 0 : _j.length) > 0) {
|
|
233
|
+
crmRequest.id = customerMatches.data[0].id;
|
|
234
|
+
yield this.updCustomer(crmRequest);
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
const addCustomerResponse = yield this.addCustomer(crmRequest);
|
|
238
|
+
crmRequest.id = addCustomerResponse.data.response.id;
|
|
239
|
+
}
|
|
240
|
+
yield this.processJobRequest({
|
|
241
|
+
dateTime,
|
|
242
|
+
consentApproval: consentApproval && consentApproval.includes("agreed"),
|
|
243
|
+
message,
|
|
244
|
+
crmRequest,
|
|
245
|
+
parsedAddress,
|
|
246
|
+
preferredTime
|
|
247
|
+
});
|
|
248
|
+
crmResponse.status = "Success";
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
(0, stentor_logger_1.log)().error(`FieldPulse error send(): ${err}`);
|
|
252
|
+
crmResponse.message = err;
|
|
253
|
+
}
|
|
254
|
+
return crmResponse;
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
processJobRequest(request) {
|
|
258
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
259
|
+
var _a, _b, _c, _d, _e;
|
|
260
|
+
let location_id = "";
|
|
261
|
+
if (request.dateTime && request.consentApproval) {
|
|
262
|
+
const jobs = (0, JobTypes_1.getJobTypes)();
|
|
263
|
+
const aiService = new ai_1.AIService({
|
|
264
|
+
jobTypes: jobs,
|
|
265
|
+
apiKey: this.props.openAI.apiKey
|
|
266
|
+
});
|
|
267
|
+
const aiResponse = yield aiService.labelJob(request.message);
|
|
268
|
+
let jobNote = request.message;
|
|
269
|
+
if (aiResponse.success && aiResponse.jobCategory) {
|
|
270
|
+
jobNote = `${aiResponse.serviceType} - ${aiResponse.jobCategory} - ${aiResponse.jobService}`;
|
|
271
|
+
}
|
|
272
|
+
const customerAddresses = yield this.getCustomerAddresses(request.crmRequest.id.toString());
|
|
273
|
+
if (customerAddresses.status === "Success" && ((_a = customerAddresses.data.response) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
274
|
+
location_id = customerAddresses.data.response[0].id;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const addLocationResponse = yield this.addLocation({
|
|
278
|
+
title: request.parsedAddress.addressLine1,
|
|
279
|
+
object_type: "customer",
|
|
280
|
+
object_id: request.crmRequest.id,
|
|
281
|
+
address_1: request.parsedAddress.addressLine1,
|
|
282
|
+
city: request.parsedAddress.placeName,
|
|
283
|
+
state: request.parsedAddress.stateAbbreviation,
|
|
284
|
+
zip_code: request.parsedAddress.zipCode,
|
|
285
|
+
is_main_location: true
|
|
286
|
+
});
|
|
287
|
+
location_id = addLocationResponse.data.id;
|
|
288
|
+
}
|
|
289
|
+
const appointmentTime = (0, moment_1.default)(request.dateTime); // Localized time
|
|
290
|
+
const zoneOffset = 0;
|
|
291
|
+
let offsetHours;
|
|
292
|
+
if (request.preferredTime) {
|
|
293
|
+
if (request.preferredTime.includes("morning")) {
|
|
294
|
+
offsetHours = 8 + zoneOffset;
|
|
295
|
+
}
|
|
296
|
+
else if (request.preferredTime.includes("afternoon")) {
|
|
297
|
+
offsetHours = 14 + zoneOffset;
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
offsetHours = 8 + zoneOffset; // first available = morning
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
offsetHours = 8; // no time part
|
|
305
|
+
}
|
|
306
|
+
appointmentTime.add(offsetHours, "hours");
|
|
307
|
+
const requestTime = appointmentTime ? appointmentTime.utc().format() : undefined;
|
|
308
|
+
const tags = yield this.getTags();
|
|
309
|
+
// Set Attribution Tag
|
|
310
|
+
const xappTag = tags.data.response.find((tag) => tag.title === "XAPP");
|
|
311
|
+
let tag = 0;
|
|
312
|
+
if (xappTag) {
|
|
313
|
+
tag = xappTag.id;
|
|
314
|
+
}
|
|
315
|
+
else {
|
|
316
|
+
const addTagResponse = yield this.addTag({
|
|
317
|
+
type: "job",
|
|
318
|
+
title: lead_source,
|
|
319
|
+
color: default_tag_color
|
|
320
|
+
});
|
|
321
|
+
tag = addTagResponse.data.response.id;
|
|
322
|
+
}
|
|
323
|
+
yield this.addJob({
|
|
324
|
+
customer_id: request.crmRequest.id,
|
|
325
|
+
status: 1,
|
|
326
|
+
start_time: (0, moment_1.default)(requestTime).unix(),
|
|
327
|
+
end_time: (0, moment_1.default)(requestTime).add(2, "hours").unix(),
|
|
328
|
+
job_type: jobNote,
|
|
329
|
+
billing: 1,
|
|
330
|
+
tags: [tag],
|
|
331
|
+
notes: request.message,
|
|
332
|
+
location_id: Number(location_id),
|
|
333
|
+
location: `${(_b = request.crmRequest) === null || _b === void 0 ? void 0 : _b.address_1} ${(_c = request.crmRequest) === null || _c === void 0 ? void 0 : _c.city}, ${(_d = request.crmRequest) === null || _d === void 0 ? void 0 : _d.state} ${(_e = request.crmRequest) === null || _e === void 0 ? void 0 : _e.zip_code}`
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
getCustomers(query_1) {
|
|
339
|
+
return __awaiter(this, arguments, void 0, function* (query, page = 1) {
|
|
340
|
+
var _a;
|
|
341
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
342
|
+
let q = "";
|
|
343
|
+
if (query.name)
|
|
344
|
+
q = query.name;
|
|
345
|
+
else if (query.phone)
|
|
346
|
+
q = query.phone;
|
|
347
|
+
else if (query.email)
|
|
348
|
+
q = query.email;
|
|
349
|
+
try {
|
|
350
|
+
const config = {
|
|
351
|
+
method: "get",
|
|
352
|
+
url: `${base_url}customers?search=${q}&page=${page}`,
|
|
353
|
+
headers: {
|
|
354
|
+
Accept: "application/json",
|
|
355
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
const response = yield (0, axios_1.default)(config);
|
|
359
|
+
FieldPulseResponse.status = "Success";
|
|
360
|
+
FieldPulseResponse.data = (_a = response.data.response) === null || _a === void 0 ? void 0 : _a.map((x) => {
|
|
361
|
+
return {
|
|
362
|
+
id: x === null || x === void 0 ? void 0 : x.id,
|
|
363
|
+
company_id: x.company_id,
|
|
364
|
+
first_name: x.first_name,
|
|
365
|
+
last_name: x.last_name,
|
|
366
|
+
email: x.email,
|
|
367
|
+
phone: x.phone,
|
|
368
|
+
notes: x.notes,
|
|
369
|
+
address_1: x.address_1,
|
|
370
|
+
address_2: x.address_2,
|
|
371
|
+
city: x.city,
|
|
372
|
+
state: x.state,
|
|
373
|
+
zip_code: x.zip_code,
|
|
374
|
+
company_name: x.company_name,
|
|
375
|
+
tags: x.tags,
|
|
376
|
+
lead_source: x.lead_source,
|
|
377
|
+
job_notes: x.job_notes,
|
|
378
|
+
created_at: x.created_at,
|
|
379
|
+
updated_at: x.updated_at
|
|
380
|
+
};
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
catch (err) {
|
|
384
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error searching customers ${err}`);
|
|
385
|
+
FieldPulseResponse.error = err;
|
|
386
|
+
}
|
|
387
|
+
return FieldPulseResponse;
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
getCustomerAddresses(id) {
|
|
391
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
392
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
393
|
+
try {
|
|
394
|
+
const config = {
|
|
395
|
+
method: "get",
|
|
396
|
+
url: `${base_url}locations?object_type=customer&object_id=${id}`,
|
|
397
|
+
headers: {
|
|
398
|
+
Accept: "application/json",
|
|
399
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
const response = yield (0, axios_1.default)(config);
|
|
403
|
+
FieldPulseResponse.status = "Success";
|
|
404
|
+
FieldPulseResponse.data = response.data;
|
|
405
|
+
}
|
|
406
|
+
catch (err) {
|
|
407
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error getting customer addresses ${err}`);
|
|
408
|
+
FieldPulseResponse.error = err;
|
|
409
|
+
}
|
|
410
|
+
return FieldPulseResponse;
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
addCustomer(customer) {
|
|
414
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
415
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
416
|
+
// Set Address
|
|
417
|
+
if (customer.address_1) {
|
|
418
|
+
customer.locations = [
|
|
419
|
+
{
|
|
420
|
+
title: customer.address_1,
|
|
421
|
+
address_1: customer.address_1,
|
|
422
|
+
city: customer.city,
|
|
423
|
+
state: customer.state,
|
|
424
|
+
zip_code: customer.zip_code,
|
|
425
|
+
is_main_location: true
|
|
426
|
+
}
|
|
427
|
+
];
|
|
428
|
+
customer.billing_address_1 = customer.address_1;
|
|
429
|
+
customer.billing_city = customer.city;
|
|
430
|
+
customer.billing_state = customer.state;
|
|
431
|
+
customer.billing_zip_code = customer.zip_code;
|
|
432
|
+
}
|
|
433
|
+
try {
|
|
434
|
+
const config = {
|
|
435
|
+
method: "post",
|
|
436
|
+
url: `${base_url}customers`,
|
|
437
|
+
headers: {
|
|
438
|
+
Accept: "application/json",
|
|
439
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`,
|
|
440
|
+
"Content-Type": "application/json"
|
|
441
|
+
},
|
|
442
|
+
data: JSON.stringify(customer)
|
|
443
|
+
};
|
|
444
|
+
const response = yield (0, axios_1.default)(config);
|
|
445
|
+
if (!response.data.error) {
|
|
446
|
+
FieldPulseResponse.status = "Success";
|
|
447
|
+
FieldPulseResponse.data = response.data;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
catch (err) {
|
|
451
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error adding customer ${err}`);
|
|
452
|
+
FieldPulseResponse.error = err;
|
|
453
|
+
}
|
|
454
|
+
return FieldPulseResponse;
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
updCustomer(customer) {
|
|
458
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
459
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
460
|
+
try {
|
|
461
|
+
customer.status = "current customer";
|
|
462
|
+
const config = {
|
|
463
|
+
method: "put",
|
|
464
|
+
url: `${base_url}customers/${customer.id}`,
|
|
465
|
+
headers: {
|
|
466
|
+
Accept: "application/json",
|
|
467
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`,
|
|
468
|
+
"Content-Type": "application/json"
|
|
469
|
+
},
|
|
470
|
+
data: JSON.stringify(customer)
|
|
471
|
+
};
|
|
472
|
+
const response = yield (0, axios_1.default)(config);
|
|
473
|
+
if (!response.data.error) {
|
|
474
|
+
FieldPulseResponse.status = "Success";
|
|
475
|
+
FieldPulseResponse.data = response.data;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
catch (err) {
|
|
479
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error updating customer ${err}`);
|
|
480
|
+
FieldPulseResponse.error = err;
|
|
481
|
+
}
|
|
482
|
+
return FieldPulseResponse;
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
getLeadSources() {
|
|
486
|
+
return __awaiter(this, arguments, void 0, function* (page = 1) {
|
|
487
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
488
|
+
try {
|
|
489
|
+
const config = {
|
|
490
|
+
method: "get",
|
|
491
|
+
url: `${base_url}lead_source?page=${page}`,
|
|
492
|
+
headers: {
|
|
493
|
+
Accept: "application/json",
|
|
494
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
const response = yield (0, axios_1.default)(config);
|
|
498
|
+
FieldPulseResponse.status = "Success";
|
|
499
|
+
FieldPulseResponse.data = response.data;
|
|
500
|
+
}
|
|
501
|
+
catch (err) {
|
|
502
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error getting lead sources ${err}`);
|
|
503
|
+
FieldPulseResponse.error = err;
|
|
504
|
+
}
|
|
505
|
+
return FieldPulseResponse;
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
getTags() {
|
|
509
|
+
return __awaiter(this, arguments, void 0, function* (page = 1) {
|
|
510
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
511
|
+
try {
|
|
512
|
+
const config = {
|
|
513
|
+
method: "get",
|
|
514
|
+
url: `${base_url}tags?page=${page}&limit=100`,
|
|
515
|
+
headers: {
|
|
516
|
+
Accept: "application/json",
|
|
517
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
const response = yield (0, axios_1.default)(config);
|
|
521
|
+
FieldPulseResponse.status = "Success";
|
|
522
|
+
FieldPulseResponse.data = response.data;
|
|
523
|
+
}
|
|
524
|
+
catch (err) {
|
|
525
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error getting tags ${err}`);
|
|
526
|
+
FieldPulseResponse.error = err;
|
|
527
|
+
}
|
|
528
|
+
return FieldPulseResponse;
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
getJobs(query_1) {
|
|
532
|
+
return __awaiter(this, arguments, void 0, function* (query, page = 1) {
|
|
533
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
534
|
+
try {
|
|
535
|
+
let url = `${base_url}jobs?page=${page}`;
|
|
536
|
+
// Filter by date?
|
|
537
|
+
if (query === null || query === void 0 ? void 0 : query.createdOnOrAfter) {
|
|
538
|
+
url += `&created_from=${query.createdOnOrAfter}`;
|
|
539
|
+
}
|
|
540
|
+
// Filter by search query?
|
|
541
|
+
if (query === null || query === void 0 ? void 0 : query.search) {
|
|
542
|
+
url += `&search=${query.search}`;
|
|
543
|
+
}
|
|
544
|
+
const config = {
|
|
545
|
+
method: "get",
|
|
546
|
+
url,
|
|
547
|
+
headers: {
|
|
548
|
+
Accept: "application/json",
|
|
549
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
const response = yield (0, axios_1.default)(config);
|
|
553
|
+
FieldPulseResponse.status = "Success";
|
|
554
|
+
FieldPulseResponse.data = response.data;
|
|
555
|
+
}
|
|
556
|
+
catch (err) {
|
|
557
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error getting jobs ${err}`);
|
|
558
|
+
FieldPulseResponse.error = err;
|
|
559
|
+
}
|
|
560
|
+
return FieldPulseResponse;
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
getEstimates() {
|
|
564
|
+
return __awaiter(this, arguments, void 0, function* (page = 1) {
|
|
565
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
566
|
+
try {
|
|
567
|
+
const config = {
|
|
568
|
+
method: "get",
|
|
569
|
+
url: `${base_url}estimates?page=${page}`,
|
|
570
|
+
headers: {
|
|
571
|
+
Accept: "application/json",
|
|
572
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
const response = yield (0, axios_1.default)(config);
|
|
576
|
+
FieldPulseResponse.status = "Success";
|
|
577
|
+
FieldPulseResponse.data = response.data;
|
|
578
|
+
}
|
|
579
|
+
catch (err) {
|
|
580
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error getting estimates ${err}`);
|
|
581
|
+
FieldPulseResponse.error = err;
|
|
582
|
+
}
|
|
583
|
+
return FieldPulseResponse;
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
getEmployees() {
|
|
587
|
+
return __awaiter(this, arguments, void 0, function* (page = 1) {
|
|
588
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
589
|
+
try {
|
|
590
|
+
const config = {
|
|
591
|
+
method: "get",
|
|
592
|
+
url: `${base_url}teams?page=${page}&limit=100`,
|
|
593
|
+
headers: {
|
|
594
|
+
Accept: "application/json",
|
|
595
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
const response = yield (0, axios_1.default)(config);
|
|
599
|
+
FieldPulseResponse.status = "Success";
|
|
600
|
+
FieldPulseResponse.data = response.data;
|
|
601
|
+
}
|
|
602
|
+
catch (err) {
|
|
603
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error getting employees ${err}`);
|
|
604
|
+
FieldPulseResponse.error = err;
|
|
605
|
+
}
|
|
606
|
+
return FieldPulseResponse;
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
addJob(job) {
|
|
610
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
611
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
612
|
+
try {
|
|
613
|
+
const config = {
|
|
614
|
+
method: "post",
|
|
615
|
+
url: `${base_url}jobs`,
|
|
616
|
+
headers: {
|
|
617
|
+
Accept: "application/json",
|
|
618
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`,
|
|
619
|
+
"Content-Type": "application/json"
|
|
620
|
+
},
|
|
621
|
+
data: JSON.stringify(job)
|
|
622
|
+
};
|
|
623
|
+
const response = yield (0, axios_1.default)(config);
|
|
624
|
+
FieldPulseResponse.status = "Success";
|
|
625
|
+
FieldPulseResponse.data = response.data;
|
|
626
|
+
}
|
|
627
|
+
catch (err) {
|
|
628
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error adding job ${err}`);
|
|
629
|
+
FieldPulseResponse.error = err;
|
|
630
|
+
}
|
|
631
|
+
return FieldPulseResponse;
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
addTag(tag) {
|
|
635
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
636
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
637
|
+
try {
|
|
638
|
+
if (!tag.color) {
|
|
639
|
+
tag.color = default_tag_color;
|
|
640
|
+
}
|
|
641
|
+
const config = {
|
|
642
|
+
method: "post",
|
|
643
|
+
url: `${base_url}tags`,
|
|
644
|
+
headers: {
|
|
645
|
+
Accept: "application/json",
|
|
646
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`,
|
|
647
|
+
"Content-Type": "application/json"
|
|
648
|
+
},
|
|
649
|
+
data: JSON.stringify(tag)
|
|
650
|
+
};
|
|
651
|
+
const response = yield (0, axios_1.default)(config);
|
|
652
|
+
FieldPulseResponse.status = "Success";
|
|
653
|
+
FieldPulseResponse.data = response.data;
|
|
654
|
+
}
|
|
655
|
+
catch (err) {
|
|
656
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error adding tag ${err}`);
|
|
657
|
+
FieldPulseResponse.error = err;
|
|
658
|
+
}
|
|
659
|
+
return FieldPulseResponse;
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
addLocation(address) {
|
|
663
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
664
|
+
const FieldPulseResponse = { status: "Failure" };
|
|
665
|
+
try {
|
|
666
|
+
const config = {
|
|
667
|
+
method: "post",
|
|
668
|
+
url: `${base_url}locations`,
|
|
669
|
+
headers: {
|
|
670
|
+
Accept: "application/json",
|
|
671
|
+
"x-api-key": `${(yield this.props.authenticate()).accessToken}`,
|
|
672
|
+
"Content-Type": "application/json"
|
|
673
|
+
},
|
|
674
|
+
data: JSON.stringify(address)
|
|
675
|
+
};
|
|
676
|
+
const response = yield (0, axios_1.default)(config);
|
|
677
|
+
FieldPulseResponse.status = "Success";
|
|
678
|
+
FieldPulseResponse.data = response.data;
|
|
679
|
+
}
|
|
680
|
+
catch (err) {
|
|
681
|
+
(0, stentor_logger_1.log)().error(`FieldPulse: Error adding customer address ${err}`);
|
|
682
|
+
FieldPulseResponse.error = err;
|
|
683
|
+
}
|
|
684
|
+
return FieldPulseResponse;
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
exports.FieldPulseService = FieldPulseService;
|
|
689
|
+
//# sourceMappingURL=FieldPulseService.js.map
|