@tiledesk/tiledesk-server 2.7.25 → 2.7.27
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +8 -0
- package/app.js +1 -1
- package/config/labels/widget.json +31 -0
- package/event/emailEvent.js +58 -2
- package/models/faq.js +5 -0
- package/models/kb_setting.js +38 -3
- package/package.json +4 -3
- package/pubmodules/s/index.js +2 -2
- package/pubmodules/s/models/subscription-payment.js +2 -2
- package/pubmodules/s/stripe/index.js +2 -2
- package/routes/kb.js +952 -542
- package/routes/openai.js +3 -3
- package/routes/project.js +21 -6
- package/routes/quotes.js +13 -4
- package/services/QuoteManager.js +163 -16
- package/services/emailService.js +53 -1
- package/services/requestService.js +16 -5
- package/template/email/beenInvitedNewUser.html +221 -216
- package/template/email/checkpointReachedEmail.html +92 -0
- package/test/kbRoute.js +1186 -311
- package/test/mock/projectMock.js +2 -3
- package/test/openaiRoute.js +3 -0
- package/test/requestService.js +3 -0
- package/utils/aiUtils.js +41 -5
package/routes/openai.js
CHANGED
@@ -4,7 +4,7 @@ var { KBSettings } = require('../models/kb_setting');
|
|
4
4
|
var openaiService = require('../services/openaiService');
|
5
5
|
var winston = require('../config/winston');
|
6
6
|
const { QuoteManager } = require('../services/QuoteManager');
|
7
|
-
const {
|
7
|
+
const { MODELS_MULTIPLIER } = require('../utils/aiUtils');
|
8
8
|
|
9
9
|
router.post('/', async (req, res) => {
|
10
10
|
|
@@ -37,7 +37,7 @@ router.post('/', async (req, res) => {
|
|
37
37
|
if (usePublicKey === true) {
|
38
38
|
let isAvailable = await quoteManager.checkQuote(req.project, obj, 'tokens');
|
39
39
|
if (isAvailable === false) {
|
40
|
-
return res.status(403).send("Tokens quota exceeded")
|
40
|
+
return res.status(403).send({ success: false, message: "Tokens quota exceeded", error_code: 13001})
|
41
41
|
}
|
42
42
|
}
|
43
43
|
|
@@ -61,7 +61,7 @@ router.post('/', async (req, res) => {
|
|
61
61
|
json.messages.unshift(message);
|
62
62
|
}
|
63
63
|
|
64
|
-
let multiplier =
|
64
|
+
let multiplier = MODELS_MULTIPLIER[json.model];
|
65
65
|
if (!multiplier) {
|
66
66
|
multiplier = 1;
|
67
67
|
winston.info("No multiplier found for AI model")
|
package/routes/project.js
CHANGED
@@ -239,6 +239,7 @@ router.put('/:projectid', [passport.authenticate(['basic', 'jwt'], { session: fa
|
|
239
239
|
winston.debug('UPDATE PROJECT REQ BODY ', req.body);
|
240
240
|
|
241
241
|
var update = {};
|
242
|
+
let updating_quotes = false;
|
242
243
|
|
243
244
|
if (req.body.profile) {
|
244
245
|
|
@@ -248,14 +249,22 @@ router.put('/:projectid', [passport.authenticate(['basic', 'jwt'], { session: fa
|
|
248
249
|
|
249
250
|
winston.debug("Superadmin can modify the project profile")
|
250
251
|
update.profile = req.body.profile;
|
252
|
+
if (req.body.profile.quotes) {
|
253
|
+
updating_quotes = true;
|
254
|
+
}
|
251
255
|
|
252
|
-
|
253
|
-
|
256
|
+
/**
|
257
|
+
* Possibile Miglioramento
|
258
|
+
* Eliminare solo le chiavi di redis di notify solo per le quote che si stanno modificando.
|
259
|
+
* Per farlo è necessario permettere la modifica puntuale del project profile, attualmente non disponibile.
|
260
|
+
*/
|
254
261
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
262
|
+
delete req.user.attributes.isSuperadmin;
|
263
|
+
}
|
264
|
+
else {
|
265
|
+
winston.verbose("Project profile can't be modified by the current user " + req.user._id);
|
266
|
+
return res.status(403).send({ success: false, error: "You don't have the permission required to modify the project profile"});
|
267
|
+
}
|
259
268
|
|
260
269
|
// check if super admin
|
261
270
|
// let token = req.headers.authorization
|
@@ -457,6 +466,12 @@ router.put('/:projectid', [passport.authenticate(['basic', 'jwt'], { session: fa
|
|
457
466
|
return res.status(500).send({ success: false, msg: 'Error updating object.' });
|
458
467
|
}
|
459
468
|
projectEvent.emit('project.update', updatedProject );
|
469
|
+
|
470
|
+
if (updating_quotes == true) {
|
471
|
+
let obj = { createdAt: new Date() };
|
472
|
+
let quoteManager = req.app.get('quote_manager');
|
473
|
+
quoteManager.invalidateCheckpointKeys(updatedProject, obj);
|
474
|
+
}
|
460
475
|
res.json(updatedProject);
|
461
476
|
});
|
462
477
|
});
|
package/routes/quotes.js
CHANGED
@@ -2,6 +2,7 @@ var express = require('express');
|
|
2
2
|
var router = express.Router();
|
3
3
|
const { QuoteManager } = require('../services/QuoteManager');
|
4
4
|
let winston = require('../config/winston');
|
5
|
+
const { MODELS_MULTIPLIER } = require('../utils/aiUtils');
|
5
6
|
|
6
7
|
|
7
8
|
router.post('/', async (req, res) => {
|
@@ -39,12 +40,20 @@ router.get('/:type', async (req, res) => {
|
|
39
40
|
router.post('/incr/:type', async (req, res) => {
|
40
41
|
|
41
42
|
let type = req.params.type;
|
42
|
-
let
|
43
|
-
body.createdAt = new Date();
|
43
|
+
let data = req.body;
|
44
44
|
|
45
45
|
let quoteManager = req.app.get('quote_manager');
|
46
|
-
|
47
|
-
let
|
46
|
+
|
47
|
+
let multiplier = MODELS_MULTIPLIER[data.model];
|
48
|
+
if (!multiplier) {
|
49
|
+
multiplier = 1;
|
50
|
+
winston.info("No multiplier found for AI model")
|
51
|
+
}
|
52
|
+
data.multiplier = multiplier;
|
53
|
+
data.createdAt = new Date();
|
54
|
+
|
55
|
+
let incremented_key = await quoteManager.incrementTokenCount(req.project, data);
|
56
|
+
let quote = await quoteManager.getCurrentQuote(req.project, data, type);
|
48
57
|
|
49
58
|
res.status(200).send({ message: "value incremented for key " + incremented_key, key: incremented_key, currentQuote: quote });
|
50
59
|
})
|
package/services/QuoteManager.js
CHANGED
@@ -4,12 +4,21 @@ const requestEvent = require('../event/requestEvent');
|
|
4
4
|
const messageEvent = require('../event/messageEvent');
|
5
5
|
const emailEvent = require('../event/emailEvent');
|
6
6
|
|
7
|
+
// NEW
|
8
|
+
// const PLANS_LIST = {
|
9
|
+
// FREE_TRIAL: { requests: 3000, messages: 0, tokens: 250000, email: 200, chatbots: 20, kbs: 50 }, // same as PREMIUM
|
10
|
+
// SANDBOX: { requests: 200, messages: 0, tokens: 100000, email: 200, chatbots: 2, kbs: 50 },
|
11
|
+
// BASIC: { requests: 1000, messages: 0, tokens: 2000000, email: 200, chatbots: 10, kbs: 200},
|
12
|
+
// PREMIUM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, kbs: 500},
|
13
|
+
// CUSTOM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, kbs: 500}
|
14
|
+
// }
|
15
|
+
|
7
16
|
const PLANS_LIST = {
|
8
|
-
FREE_TRIAL: { requests: 3000, messages: 0, tokens:
|
9
|
-
SANDBOX: { requests: 200, messages: 0, tokens:
|
10
|
-
BASIC: { requests: 800, messages: 0, tokens:
|
11
|
-
PREMIUM: { requests: 3000, messages: 0, tokens:
|
12
|
-
CUSTOM: { requests: 3000, messages: 0, tokens:
|
17
|
+
FREE_TRIAL: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, kbs: 50 }, // same as PREMIUM
|
18
|
+
SANDBOX: { requests: 200, messages: 0, tokens: 100000, email: 200, chatbots: 2, kbs: 50 },
|
19
|
+
BASIC: { requests: 800, messages: 0, tokens: 2000000, email: 200, chatbots: 5, kbs: 150},
|
20
|
+
PREMIUM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, kbs: 300},
|
21
|
+
CUSTOM: { requests: 3000, messages: 0, tokens: 5000000, email: 200, chatbots: 20, kbs: 1000}
|
13
22
|
}
|
14
23
|
|
15
24
|
const typesList = ['requests', 'messages', 'email', 'tokens', 'chatbots', 'kbs']
|
@@ -41,6 +50,7 @@ class QuoteManager {
|
|
41
50
|
winston.verbose("[QuoteManager] incrementRequestsCount key: " + key);
|
42
51
|
|
43
52
|
await this.tdCache.incr(key)
|
53
|
+
this.sendEmailIfQuotaExceeded(project, request, 'requests', key);
|
44
54
|
return key;
|
45
55
|
}
|
46
56
|
|
@@ -61,6 +71,7 @@ class QuoteManager {
|
|
61
71
|
winston.verbose("[QuoteManager] incrementEmailCount key: " + key);
|
62
72
|
|
63
73
|
await this.tdCache.incr(key)
|
74
|
+
this.sendEmailIfQuotaExceeded(project, email, 'email', key);
|
64
75
|
return key;
|
65
76
|
}
|
66
77
|
|
@@ -78,7 +89,7 @@ class QuoteManager {
|
|
78
89
|
let tokens = data.tokens * data.multiplier;
|
79
90
|
await this.tdCache.incrbyfloat(key, tokens);
|
80
91
|
// await this.tdCache.incrby(key, tokens);
|
81
|
-
|
92
|
+
this.sendEmailIfQuotaExceeded(project, data, 'tokens', key);
|
82
93
|
return key;
|
83
94
|
}
|
84
95
|
// INCREMENT KEY SECTION - END
|
@@ -89,11 +100,22 @@ class QuoteManager {
|
|
89
100
|
winston.debug("generateKey object ", object)
|
90
101
|
winston.debug("generateKey type " + type)
|
91
102
|
let subscriptionDate;
|
92
|
-
|
93
|
-
|
103
|
+
|
104
|
+
if (this.project.isActiveSubscription === true) {
|
105
|
+
if (this.project.profile.subStart) {
|
106
|
+
subscriptionDate = this.project.profile.subStart;
|
107
|
+
} else {
|
108
|
+
// it should never happen
|
109
|
+
winston.error("Error: quote manager - isActiveSubscription is true but subStart does not exists.")
|
110
|
+
}
|
94
111
|
} else {
|
95
|
-
|
112
|
+
if (this.project.profile.subEnd) {
|
113
|
+
subscriptionDate = this.project.profile.subEnd;
|
114
|
+
} else {
|
115
|
+
subscriptionDate = this.project.createdAt;
|
116
|
+
}
|
96
117
|
}
|
118
|
+
|
97
119
|
let objectDate = object.createdAt;
|
98
120
|
winston.debug("objectDate " + objectDate);
|
99
121
|
|
@@ -124,7 +146,7 @@ class QuoteManager {
|
|
124
146
|
}
|
125
147
|
|
126
148
|
/**
|
127
|
-
* Get quotes for
|
149
|
+
* Get quotes for all types (tokens and request and ...)
|
128
150
|
*/
|
129
151
|
async getAllQuotes(project, obj) {
|
130
152
|
|
@@ -174,6 +196,124 @@ class QuoteManager {
|
|
174
196
|
}
|
175
197
|
}
|
176
198
|
|
199
|
+
async checkQuoteForAlert(project, object, type) {
|
200
|
+
|
201
|
+
if (quotes_enabled === false) {
|
202
|
+
winston.verbose("QUOTES DISABLED - checkQuote for type " + type);
|
203
|
+
return (null, null);
|
204
|
+
}
|
205
|
+
|
206
|
+
this.project = project;
|
207
|
+
let limits = await this.getPlanLimits();
|
208
|
+
winston.verbose("limits for current plan: ", limits)
|
209
|
+
|
210
|
+
let quote = await this.getCurrentQuote(project, object, type);
|
211
|
+
winston.verbose("getCurrentQuote resp: ", quote)
|
212
|
+
|
213
|
+
let data = {
|
214
|
+
limits: limits,
|
215
|
+
quote: quote
|
216
|
+
}
|
217
|
+
|
218
|
+
return data;
|
219
|
+
}
|
220
|
+
|
221
|
+
async sendEmailIfQuotaExceeded(project, object, type, key) {
|
222
|
+
|
223
|
+
let data = await this.checkQuoteForAlert(project, object, type);
|
224
|
+
let limits = data.limits;
|
225
|
+
let limit = data.limits[type];
|
226
|
+
let quote = data.quote;
|
227
|
+
|
228
|
+
const checkpoint = await this.percentageCalculator(limit, quote);
|
229
|
+
if (checkpoint == 0) {
|
230
|
+
return;
|
231
|
+
}
|
232
|
+
winston.verbose("checkpoint perc: ", checkpoint);
|
233
|
+
|
234
|
+
// Generate redis key
|
235
|
+
let nKey = key + ":notify:" + checkpoint;
|
236
|
+
let result = await this.tdCache.get(nKey);
|
237
|
+
if (!result) {
|
238
|
+
|
239
|
+
let allQuotes = await this.getAllQuotes(project, object);
|
240
|
+
let quotes = await this.generateQuotesObject(allQuotes, limits);
|
241
|
+
|
242
|
+
let data = {
|
243
|
+
id_project: project._id,
|
244
|
+
project_name: project.name,
|
245
|
+
type: type,
|
246
|
+
checkpoint: checkpoint,
|
247
|
+
quotes: quotes
|
248
|
+
}
|
249
|
+
|
250
|
+
emailEvent.emit('email.send.quote.checkpoint', data);
|
251
|
+
await this.tdCache.set(nKey, 'true', {EX: 2592000}); //seconds in one month = 2592000
|
252
|
+
} else {
|
253
|
+
winston.verbose("Quota checkpoint reached email already sent.")
|
254
|
+
}
|
255
|
+
|
256
|
+
}
|
257
|
+
|
258
|
+
async percentageCalculator(limit, quote) {
|
259
|
+
|
260
|
+
let p = (quote / limit) * 100;
|
261
|
+
|
262
|
+
if (p >= 100) { return 100; }
|
263
|
+
if (p >= 95) { return 95; }
|
264
|
+
if (p >= 75) { return 75; }
|
265
|
+
if (p >= 50) { return 50; }
|
266
|
+
|
267
|
+
return 0;
|
268
|
+
|
269
|
+
}
|
270
|
+
|
271
|
+
async invalidateCheckpointKeys(project, obj) {
|
272
|
+
|
273
|
+
this.project = project;
|
274
|
+
winston.verbose("invalidateCheckpointKeys project " + project._id);
|
275
|
+
let requests_key = await this.generateKey(obj, 'requests');
|
276
|
+
let tokens_key = await this.generateKey(obj, 'tokens');
|
277
|
+
let email_key = await this.generateKey(obj, 'email');
|
278
|
+
|
279
|
+
let checkpoints = ['50', '75', '95', '100']
|
280
|
+
|
281
|
+
checkpoints.forEach( async (checkpoint) => {
|
282
|
+
let nrequests_key = requests_key + ":notify:" + checkpoint;
|
283
|
+
let ntokens_key = tokens_key + ":notify:" + checkpoint;
|
284
|
+
let nemail_key = email_key + ":notify:" + checkpoint;
|
285
|
+
|
286
|
+
winston.verbose("invalidateCheckpointKeys nrequests_key: " + nrequests_key);
|
287
|
+
winston.verbose("invalidateCheckpointKeys ntokens_key: " + ntokens_key);
|
288
|
+
winston.verbose("invalidateCheckpointKeys nemail_key: " + nemail_key);
|
289
|
+
|
290
|
+
this.tdCache.del(nrequests_key);
|
291
|
+
this.tdCache.del(ntokens_key);
|
292
|
+
this.tdCache.del(nemail_key);
|
293
|
+
|
294
|
+
return true;
|
295
|
+
})
|
296
|
+
|
297
|
+
}
|
298
|
+
|
299
|
+
async generateQuotesObject(quotes, limits) {
|
300
|
+
let quotes_obj = {
|
301
|
+
requests: {
|
302
|
+
quote: quotes.requests.quote,
|
303
|
+
perc: ((quotes.requests.quote / limits['requests']) * 100).toFixed(1)
|
304
|
+
},
|
305
|
+
tokens: {
|
306
|
+
quote: quotes.tokens.quote,
|
307
|
+
perc: ((quotes.tokens.quote / limits['tokens']) * 100).toFixed(1)
|
308
|
+
},
|
309
|
+
email: {
|
310
|
+
quote: quotes.email.quote,
|
311
|
+
perc: ((quotes.email.quote / limits['email']) * 100).toFixed(1)
|
312
|
+
}
|
313
|
+
}
|
314
|
+
return quotes_obj
|
315
|
+
}
|
316
|
+
|
177
317
|
|
178
318
|
async getPlanLimits(project) {
|
179
319
|
|
@@ -182,13 +322,11 @@ class QuoteManager {
|
|
182
322
|
};
|
183
323
|
|
184
324
|
let limits;
|
325
|
+
const plan = this.project.profile.name;
|
326
|
+
|
185
327
|
if (this.project.profile.type === 'payment') {
|
186
328
|
|
187
|
-
const plan = this.project.profile.name;
|
188
329
|
switch (plan) {
|
189
|
-
case 'Sandbox':
|
190
|
-
limits = PLANS_LIST.SANDBOX;
|
191
|
-
break;
|
192
330
|
case 'Basic':
|
193
331
|
limits = PLANS_LIST.BASIC;
|
194
332
|
break;
|
@@ -211,14 +349,21 @@ class QuoteManager {
|
|
211
349
|
limits = PLANS_LIST.FREE_TRIAL;
|
212
350
|
}
|
213
351
|
} else {
|
214
|
-
limits = PLANS_LIST.FREE_TRIAL;
|
215
|
-
}
|
216
352
|
|
353
|
+
if (this.project.trialExpired === false) {
|
354
|
+
limits = PLANS_LIST.FREE_TRIAL
|
355
|
+
} else {
|
356
|
+
limits = PLANS_LIST.SANDBOX;
|
357
|
+
}
|
358
|
+
|
359
|
+
}
|
217
360
|
if (this.project?.profile?.quotes) {
|
218
361
|
let profile_quotes = this.project?.profile?.quotes;
|
219
362
|
const merged_quotes = Object.assign({}, limits, profile_quotes);
|
363
|
+
winston.verbose("Custom Limits: ", limits)
|
220
364
|
return merged_quotes;
|
221
365
|
} else {
|
366
|
+
winston.verbose("Default Limits: ", limits)
|
222
367
|
return limits;
|
223
368
|
}
|
224
369
|
}
|
@@ -256,6 +401,8 @@ class QuoteManager {
|
|
256
401
|
if (quotes_enabled === true) {
|
257
402
|
winston.verbose("request.create.quote event catched");
|
258
403
|
let result = await this.incrementRequestsCount(payload.project, payload.request);
|
404
|
+
|
405
|
+
|
259
406
|
return result;
|
260
407
|
} else {
|
261
408
|
winston.verbose("QUOTES DISABLED - request.create.quote event")
|
package/services/emailService.js
CHANGED
@@ -149,7 +149,6 @@ class EmailService {
|
|
149
149
|
var that = this;
|
150
150
|
winston.debug('EmailService readTemplate: ' + templateName + ' environmentVariableKey: ' + environmentVariableKey + ' setting ' + JSON.stringify(settings));
|
151
151
|
|
152
|
-
|
153
152
|
if (settings && settings.email && settings.email.templates) {
|
154
153
|
|
155
154
|
var templates = settings.email.templates;
|
@@ -168,6 +167,21 @@ class EmailService {
|
|
168
167
|
return resolve(template);
|
169
168
|
});
|
170
169
|
}
|
170
|
+
else {
|
171
|
+
var envTemplate = process.env[environmentVariableKey];
|
172
|
+
winston.debug('EmailService envTemplate: ' + envTemplate);
|
173
|
+
|
174
|
+
if (envTemplate) {
|
175
|
+
winston.debug('EmailService return envTemplate: ' + envTemplate);
|
176
|
+
|
177
|
+
return envTemplate;
|
178
|
+
} else {
|
179
|
+
winston.debug('EmailService return file: ' + templateName);
|
180
|
+
|
181
|
+
return that.readTemplateFile(templateName);
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
171
185
|
// else {
|
172
186
|
// return that.readTemplateFile(templateName);
|
173
187
|
// }
|
@@ -1816,6 +1830,44 @@ class EmailService {
|
|
1816
1830
|
|
1817
1831
|
}
|
1818
1832
|
|
1833
|
+
async sendEmailQuotaCheckpointReached(to, firstname, project_name, resource_name, checkpoint, quotes) {
|
1834
|
+
|
1835
|
+
winston.info("sendEmailQuotaCheckpointReached: " + to);
|
1836
|
+
|
1837
|
+
var that = this;
|
1838
|
+
|
1839
|
+
let html = await this.readTemplate('checkpointReachedEmail.html', undefined, "EMAIL_QUOTA_CHECKPOINT_REACHED");
|
1840
|
+
winston.debug("html: " + html);
|
1841
|
+
|
1842
|
+
let template = handlebars.compile(html);
|
1843
|
+
|
1844
|
+
let requests_quote = quotes.requests.quote;
|
1845
|
+
let requests_perc = quotes.requests.perc;
|
1846
|
+
|
1847
|
+
let tokens_quote = quotes.tokens.quote;
|
1848
|
+
let tokens_perc = quotes.tokens.perc;
|
1849
|
+
|
1850
|
+
let email_quote = quotes.email.quote;
|
1851
|
+
let email_perc = quotes.email.perc;
|
1852
|
+
|
1853
|
+
let replacements = {
|
1854
|
+
firstname: firstname,
|
1855
|
+
project_name: project_name,
|
1856
|
+
resource_name: resource_name,
|
1857
|
+
checkpoint: checkpoint,
|
1858
|
+
requests_quote: requests_quote,
|
1859
|
+
requests_perc: requests_perc,
|
1860
|
+
tokens_quote: tokens_quote,
|
1861
|
+
tokens_perc: tokens_perc,
|
1862
|
+
email_quote: email_quote,
|
1863
|
+
email_perc: email_perc
|
1864
|
+
}
|
1865
|
+
|
1866
|
+
html = template(replacements);
|
1867
|
+
|
1868
|
+
that.send({ to: to, subject: "Update on resources usage", html: html });
|
1869
|
+
}
|
1870
|
+
|
1819
1871
|
parseText(text, payload) {
|
1820
1872
|
|
1821
1873
|
|
@@ -525,6 +525,8 @@ class RequestService {
|
|
525
525
|
|
526
526
|
}
|
527
527
|
|
528
|
+
let isTestConversation = false;
|
529
|
+
|
528
530
|
var that = this;
|
529
531
|
|
530
532
|
return new Promise(async (resolve, reject) => {
|
@@ -548,10 +550,16 @@ class RequestService {
|
|
548
550
|
request: request
|
549
551
|
}
|
550
552
|
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
553
|
+
if (attributes && attributes.sourcePage && (attributes.sourcePage.indexOf("td_draft=true") > -1)) {
|
554
|
+
winston.verbose("is a test conversation --> skip quote availability check")
|
555
|
+
isTestConversation = true;
|
556
|
+
}
|
557
|
+
else {
|
558
|
+
let available = await qm.checkQuote(p, request, 'requests');
|
559
|
+
if (available === false) {
|
560
|
+
winston.info("Requests limits reached for project " + p._id)
|
561
|
+
return false;
|
562
|
+
}
|
555
563
|
}
|
556
564
|
|
557
565
|
|
@@ -717,7 +725,10 @@ class RequestService {
|
|
717
725
|
winston.verbose("Performance Request created in millis: " + endDate - startDate);
|
718
726
|
|
719
727
|
requestEvent.emit('request.create.simple', savedRequest);
|
720
|
-
|
728
|
+
|
729
|
+
if (!isTestConversation) {
|
730
|
+
requestEvent.emit('request.create.quote', payload);;
|
731
|
+
}
|
721
732
|
|
722
733
|
return resolve(savedRequest);
|
723
734
|
|