@kanvas/openclaw-plugin 0.1.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.
@@ -0,0 +1,590 @@
1
+ import { postGraphQLMultipart } from "../../client/multipart.js";
2
+ export class CrmService {
3
+ client;
4
+ constructor(client) {
5
+ this.client = client;
6
+ }
7
+ async searchLeads(search, first = 10) {
8
+ const query = `
9
+ query SearchLeads($first: Int, $search: String) {
10
+ leads(first: $first, search: $search) {
11
+ data {
12
+ id
13
+ uuid
14
+ firstname
15
+ lastname
16
+ email
17
+ phone
18
+ created_at
19
+ status { id name }
20
+ type { id name }
21
+ source { id name }
22
+ }
23
+ }
24
+ }
25
+ `;
26
+ return this.client.query(query, { first, search });
27
+ }
28
+ async getLead(id) {
29
+ const query = `
30
+ query GetLead($first: Int!, $where: QueryLeadsWhereWhereConditions) {
31
+ leads(first: $first, where: $where) {
32
+ data {
33
+ id
34
+ uuid
35
+ firstname
36
+ lastname
37
+ email
38
+ phone
39
+ description
40
+ branch { id }
41
+ people { id uuid firstname lastname }
42
+ status { id name }
43
+ stage { id name }
44
+ pipeline { id name }
45
+ owner { id uuid displayname }
46
+ receiver { id name uuid }
47
+ followers(first: 25) {
48
+ data {
49
+ id
50
+ uuid
51
+ displayname
52
+ }
53
+ }
54
+ channel_files(includeParticipants: true, groupByAction: true) {
55
+ total_groups
56
+ groups {
57
+ id
58
+ uuid
59
+ action
60
+ verb
61
+ status
62
+ participant_name
63
+ created_at
64
+ last_message_at
65
+ files {
66
+ id
67
+ name
68
+ url
69
+ file_type
70
+ size
71
+ verification_status
72
+ verification_message
73
+ }
74
+ }
75
+ }
76
+ channels {
77
+ id
78
+ name
79
+ slug
80
+ uuid
81
+ entity_id
82
+ entity_namespace
83
+ }
84
+ participants {
85
+ people {
86
+ id
87
+ uuid
88
+ name
89
+ }
90
+ relationship {
91
+ id
92
+ name
93
+ }
94
+ }
95
+ events {
96
+ id
97
+ uuid
98
+ name
99
+ description
100
+ created_at
101
+ type { name }
102
+ eventStatus { name }
103
+ versions {
104
+ data {
105
+ id
106
+ name
107
+ version_number
108
+ start_at
109
+ end_at
110
+ dates {
111
+ id
112
+ date
113
+ start_time
114
+ end_time
115
+ }
116
+ }
117
+ }
118
+ }
119
+ files {
120
+ data {
121
+ id
122
+ uuid
123
+ name
124
+ url
125
+ type
126
+ created_at
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ `;
133
+ return this.client.query(query, {
134
+ first: 1,
135
+ where: [{ column: "ID", operator: "EQ", value: id }],
136
+ });
137
+ }
138
+ async createLead(input) {
139
+ const mutation = `
140
+ mutation CreateLead($input: LeadInput!) {
141
+ createLead(input: $input) {
142
+ id
143
+ uuid
144
+ title
145
+ firstname
146
+ lastname
147
+ email
148
+ phone
149
+ description
150
+ branch { id }
151
+ status { id name }
152
+ type { id name }
153
+ source { id name }
154
+ pipeline { id name }
155
+ stage { id name }
156
+ people { id uuid firstname lastname }
157
+ organization { name }
158
+ created_at
159
+ }
160
+ }
161
+ `;
162
+ return this.client.query(mutation, { input });
163
+ }
164
+ async updateLead(id, input) {
165
+ const mutation = `
166
+ mutation UpdateLead($id: ID!, $input: LeadUpdateInput!) {
167
+ updateLead(id: $id, input: $input) {
168
+ id
169
+ uuid
170
+ title
171
+ description
172
+ status { id name }
173
+ stage { id name }
174
+ pipeline { id name }
175
+ owner { id uuid displayname }
176
+ receiver { id uuid name }
177
+ updated_at
178
+ }
179
+ }
180
+ `;
181
+ return this.client.query(mutation, { id, input });
182
+ }
183
+ async changeLeadOwner(input) {
184
+ return this.updateLead(String(input.leadId), {
185
+ branch_id: input.branch_id,
186
+ people_id: input.people_id,
187
+ title: input.title,
188
+ description: input.description,
189
+ leads_owner_id: input.leads_owner_id,
190
+ });
191
+ }
192
+ async changeLeadReceiver(input) {
193
+ return this.updateLead(String(input.leadId), {
194
+ branch_id: input.branch_id,
195
+ people_id: input.people_id,
196
+ title: input.title,
197
+ description: input.description,
198
+ receiver_id: input.receiver_id,
199
+ });
200
+ }
201
+ async addLeadParticipant(input) {
202
+ const mutation = `
203
+ mutation AddLeadParticipant($input: LeadsParticipantsInput!) {
204
+ addLeadParticipant(input: $input)
205
+ }
206
+ `;
207
+ return this.client.query(mutation, { input });
208
+ }
209
+ async removeLeadParticipant(input) {
210
+ const mutation = `
211
+ mutation RemoveLeadParticipant($input: LeadsParticipantsInput!) {
212
+ removeLeadParticipant(input: $input)
213
+ }
214
+ `;
215
+ return this.client.query(mutation, { input });
216
+ }
217
+ async followLead(input) {
218
+ const mutation = `
219
+ mutation FollowLead($input: FollowInput!) {
220
+ followLead(input: $input)
221
+ }
222
+ `;
223
+ return this.client.query(mutation, { input });
224
+ }
225
+ async unFollowLead(input) {
226
+ const mutation = `
227
+ mutation UnFollowLead($input: FollowInput!) {
228
+ unFollowLead(input: $input)
229
+ }
230
+ `;
231
+ return this.client.query(mutation, { input });
232
+ }
233
+ async deleteLead(id) {
234
+ const mutation = `
235
+ mutation DeleteLead($id: ID!) {
236
+ deleteLead(id: $id)
237
+ }
238
+ `;
239
+ return this.client.query(mutation, { id });
240
+ }
241
+ async restoreLead(id) {
242
+ const mutation = `
243
+ mutation RestoreLead($id: ID!) {
244
+ restoreLead(id: $id)
245
+ }
246
+ `;
247
+ return this.client.query(mutation, { id });
248
+ }
249
+ async markLeadOutcome(id, status, reason_lost) {
250
+ const mutation = `
251
+ mutation LeadWonOrLost($id: ID!, $status: LeadStatusEnum!, $reason_lost: String) {
252
+ leadWonOrLost(id: $id, status: $status, reason_lost: $reason_lost) {
253
+ id
254
+ uuid
255
+ title
256
+ reason_lost
257
+ status { id name }
258
+ updated_at
259
+ }
260
+ }
261
+ `;
262
+ return this.client.query(mutation, { id, status, reason_lost });
263
+ }
264
+ async createLeadAppointment(input) {
265
+ const mutation = `
266
+ mutation CreateEvent($input: EventInput!) {
267
+ createEvent(input: $input) {
268
+ id
269
+ uuid
270
+ name
271
+ description
272
+ start_at
273
+ end_at
274
+ created_at
275
+ resources {
276
+ id
277
+ resources_id
278
+ resources_type
279
+ }
280
+ versions {
281
+ data {
282
+ id
283
+ start_at
284
+ end_at
285
+ dates {
286
+ id
287
+ date
288
+ start_time
289
+ end_time
290
+ }
291
+ }
292
+ }
293
+ }
294
+ }
295
+ `;
296
+ return this.client.query(mutation, { input });
297
+ }
298
+ async addLeadMessage(input) {
299
+ const mutation = `
300
+ mutation CreateMessage($input: MessageInput!) {
301
+ createMessage(input: $input) {
302
+ id
303
+ uuid
304
+ slug
305
+ message
306
+ created_at
307
+ messageType {
308
+ name
309
+ }
310
+ channels {
311
+ id
312
+ slug
313
+ name
314
+ }
315
+ }
316
+ }
317
+ `;
318
+ return this.client.query(mutation, {
319
+ input: {
320
+ message: input.message,
321
+ message_verb: "comment",
322
+ channel_slug: input.channel_slug,
323
+ parent_id: input.parent_id,
324
+ is_public: input.is_public,
325
+ custom_fields: input.custom_fields,
326
+ },
327
+ });
328
+ }
329
+ async addLeadMessageByLeadId(input) {
330
+ const channelSlug = await this.getLeadPrimaryChannelSlug(String(input.leadId));
331
+ if (!channelSlug) {
332
+ throw new Error(`No lead channel found for lead ${input.leadId}`);
333
+ }
334
+ const created = await this.addLeadMessage({
335
+ channel_slug: channelSlug,
336
+ message: input.message,
337
+ parent_id: input.parent_id,
338
+ is_public: input.is_public,
339
+ custom_fields: input.custom_fields,
340
+ });
341
+ if (!input.attachments?.length) {
342
+ return created;
343
+ }
344
+ const messageId = created.data?.createMessage?.id;
345
+ if (!messageId) {
346
+ throw new Error("Lead message created but message id was missing for attachment upload");
347
+ }
348
+ const attachmentResult = await this.attachFilesToMessage(messageId, input.attachments);
349
+ return {
350
+ ...created,
351
+ attachments: attachmentResult,
352
+ };
353
+ }
354
+ async listLeadMessages(channelSlug, first = 50, page = 1) {
355
+ const query = `
356
+ query LeadMessages($first: Int, $page: Int, $channelSlug: String!) {
357
+ messages(
358
+ first: $first
359
+ page: $page
360
+ orderBy: [{ column: CREATED_AT, order: DESC }]
361
+ hasChannel: { column: SLUG, operator: EQ, value: $channelSlug }
362
+ ) {
363
+ data {
364
+ id
365
+ uuid
366
+ slug
367
+ message
368
+ is_public
369
+ created_at
370
+ user {
371
+ id
372
+ uuid
373
+ firstname
374
+ lastname
375
+ displayname
376
+ }
377
+ messageType {
378
+ name
379
+ }
380
+ files {
381
+ data {
382
+ id
383
+ uuid
384
+ name
385
+ url
386
+ type
387
+ }
388
+ }
389
+ children(first: 10) {
390
+ data {
391
+ id
392
+ uuid
393
+ message
394
+ created_at
395
+ }
396
+ }
397
+ }
398
+ }
399
+ }
400
+ `;
401
+ return this.client.query(query, { first, page, channelSlug });
402
+ }
403
+ async getLeadPrimaryChannelSlug(leadId) {
404
+ const response = await this.client.query(`
405
+ query LeadChannels($first: Int!, $where: QueryLeadsWhereWhereConditions) {
406
+ leads(first: $first, where: $where) {
407
+ data {
408
+ channels {
409
+ id
410
+ slug
411
+ name
412
+ }
413
+ }
414
+ }
415
+ }
416
+ `, {
417
+ first: 1,
418
+ where: [{ column: "ID", operator: "EQ", value: leadId }],
419
+ });
420
+ return response.data?.leads?.data?.[0]?.channels?.[0]?.slug ?? null;
421
+ }
422
+ async attachFileToLead(input) {
423
+ const query = `
424
+ mutation AttachFileToLead($id: ID!, $file: Upload!, $params: Mixed) {
425
+ attachFileToLead(id: $id, file: $file, params: $params) {
426
+ id
427
+ uuid
428
+ title
429
+ files {
430
+ data {
431
+ id
432
+ uuid
433
+ name
434
+ url
435
+ type
436
+ }
437
+ }
438
+ }
439
+ }
440
+ `;
441
+ return postGraphQLMultipart({
442
+ config: this.client.getConfig(),
443
+ query,
444
+ variables: {
445
+ id: input.leadId,
446
+ file: null,
447
+ params: input.params ?? null,
448
+ },
449
+ files: [
450
+ {
451
+ key: "variables.file",
452
+ fileName: input.fileName,
453
+ contentType: input.contentType,
454
+ content: input.content,
455
+ },
456
+ ],
457
+ });
458
+ }
459
+ async attachFilesToLead(input) {
460
+ const query = `
461
+ mutation AttachFilesToLead($id: ID!, $file: [Upload!]!, $params: Mixed) {
462
+ attachFilesToLead(id: $id, file: $file, params: $params) {
463
+ id
464
+ uuid
465
+ title
466
+ files {
467
+ data {
468
+ id
469
+ uuid
470
+ name
471
+ url
472
+ type
473
+ }
474
+ }
475
+ }
476
+ }
477
+ `;
478
+ return postGraphQLMultipart({
479
+ config: this.client.getConfig(),
480
+ query,
481
+ variables: {
482
+ id: input.leadId,
483
+ file: new Array(input.files.length).fill(null),
484
+ params: input.params ?? null,
485
+ },
486
+ files: input.files.map((file, index) => ({
487
+ key: `variables.file.${index}`,
488
+ fileName: file.fileName,
489
+ contentType: file.contentType,
490
+ content: file.content,
491
+ })),
492
+ });
493
+ }
494
+ async attachFileToMessage(messageId, file, fileName, contentType) {
495
+ const query = `
496
+ mutation AttachFileToMessage($message_id: ID!, $file: Upload!) {
497
+ attachFileToMessage(message_id: $message_id, file: $file) {
498
+ id
499
+ uuid
500
+ message
501
+ files {
502
+ data {
503
+ id
504
+ uuid
505
+ name
506
+ url
507
+ type
508
+ }
509
+ }
510
+ }
511
+ }
512
+ `;
513
+ return postGraphQLMultipart({
514
+ config: this.client.getConfig(),
515
+ query,
516
+ variables: {
517
+ message_id: messageId,
518
+ file: null,
519
+ },
520
+ files: [
521
+ {
522
+ key: "variables.file",
523
+ fileName,
524
+ contentType,
525
+ content: file,
526
+ },
527
+ ],
528
+ });
529
+ }
530
+ async attachFilesToMessage(messageId, files) {
531
+ return Promise.all(files.map((file) => this.attachFileToMessage(messageId, file.content, file.fileName, file.contentType)));
532
+ }
533
+ async listLeadStatuses(first = 50) {
534
+ const query = `
535
+ query LeadStatuses($first: Int) {
536
+ leadStatuses(first: $first) {
537
+ data {
538
+ id
539
+ name
540
+ is_default
541
+ }
542
+ }
543
+ }
544
+ `;
545
+ return this.client.query(query, { first });
546
+ }
547
+ async listLeadSources(first = 50) {
548
+ const query = `
549
+ query LeadSources($first: Int) {
550
+ leadSources(first: $first) {
551
+ data {
552
+ id
553
+ name
554
+ }
555
+ }
556
+ }
557
+ `;
558
+ return this.client.query(query, { first });
559
+ }
560
+ async listLeadTypes(first = 50) {
561
+ const query = `
562
+ query LeadTypes($first: Int) {
563
+ leadTypes(first: $first) {
564
+ data {
565
+ id
566
+ name
567
+ }
568
+ }
569
+ }
570
+ `;
571
+ return this.client.query(query, { first });
572
+ }
573
+ async listPipelines(first = 50) {
574
+ const query = `
575
+ query Pipelines($first: Int) {
576
+ pipelines(first: $first) {
577
+ data {
578
+ id
579
+ name
580
+ stages {
581
+ id
582
+ name
583
+ }
584
+ }
585
+ }
586
+ }
587
+ `;
588
+ return this.client.query(query, { first });
589
+ }
590
+ }
@@ -0,0 +1 @@
1
+ export {};