@avakado.ai/schemas 1.0.0 → 1.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.
- package/README.md +43 -13
- package/package.json +1 -1
- package/src/index.js +1 -0
- package/src/models/Action.js +19 -0
- package/src/models/Agent.js +219 -0
- package/src/models/BillingLogs.js +131 -0
- package/src/models/CallSessions.js +34 -0
- package/src/models/Channels.js +268 -0
- package/src/models/Collection.js +189 -0
- package/src/models/Data.js +35 -0
- package/src/models/Demonstarations.js +23 -0
- package/src/models/Document.js +15 -0
- package/src/models/ExternalServiceProviders.js +104 -0
- package/src/models/InbuiltNodes.js +19 -0
- package/src/models/Integrations.js +36 -0
- package/src/models/Job.js +119 -0
- package/src/models/Leads.js +84 -0
- package/src/models/Log.js +32 -0
- package/src/models/Messages.js +46 -0
- package/src/models/Plans.js +37 -0
- package/src/models/Tickets.js +50 -0
- package/src/models/User.js +473 -0
- package/src/models/Workflow.js +44 -0
- package/src/models/WorkflowLogs.js +22 -0
- package/src/models/apiAuthenticator.js +197 -0
- package/src/models/index.js +24 -0
- package/src/models/market.js +66 -0
- package/src/models/notifications.js +15 -0
- package/src/runtime.js +4 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Schema } from "mongoose";
|
|
2
|
+
import { defineModel } from "../runtime.js";
|
|
3
|
+
|
|
4
|
+
const IntegrationSchema = new Schema({
|
|
5
|
+
business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
|
|
6
|
+
metaData: {
|
|
7
|
+
name: String,
|
|
8
|
+
description: String,
|
|
9
|
+
icon: String,
|
|
10
|
+
color: String,
|
|
11
|
+
purpose: Schema.Types.Mixed,
|
|
12
|
+
type: { type: String, enum: ['zoho', 'twilio', 'exotel','tataTele','whatsapp'], required: true },
|
|
13
|
+
},
|
|
14
|
+
secrets: {
|
|
15
|
+
tokenType: String,
|
|
16
|
+
accessToken: String,
|
|
17
|
+
refreshToken: String,
|
|
18
|
+
apiKey: String,
|
|
19
|
+
apiToken: String,
|
|
20
|
+
},
|
|
21
|
+
config: {
|
|
22
|
+
AccountSid: String,
|
|
23
|
+
state: String,
|
|
24
|
+
apiDomainUrl: String,
|
|
25
|
+
domain: String,
|
|
26
|
+
scope: String,
|
|
27
|
+
expiresAt: Date,
|
|
28
|
+
region:String
|
|
29
|
+
},
|
|
30
|
+
accountDetails: Schema.Types.Mixed,
|
|
31
|
+
isActive: { type: Boolean, default: true },
|
|
32
|
+
createdBy: { type: Schema.Types.ObjectId, ref: 'Users' },
|
|
33
|
+
}, {
|
|
34
|
+
timestamps: true
|
|
35
|
+
});
|
|
36
|
+
export const Integration = defineModel('Integration', IntegrationSchema, "Integration");
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Schema } from "mongoose";
|
|
2
|
+
import { defineModel } from "../runtime.js";
|
|
3
|
+
const jobStatusEnum = ["scheduled", "active", "completed", "failed", "canceled", "delayed", "waiting", "stalled"];
|
|
4
|
+
const backoff = new Schema({
|
|
5
|
+
type: { type: String, enum: ["exponential", "fixed"], required: true },
|
|
6
|
+
delay_ms: { type: Number, required: true },
|
|
7
|
+
attempts: { max: Number, made: Number, reason: String },
|
|
8
|
+
}, { _id: false })
|
|
9
|
+
|
|
10
|
+
const logEntry = new Schema({
|
|
11
|
+
level: { type: String, enum: ["info", "warn", "error", "debug"], required: true },
|
|
12
|
+
message: String,
|
|
13
|
+
timestamp: { type: Date, default: Date.now },
|
|
14
|
+
data: Schema.Types.Mixed
|
|
15
|
+
}, { _id: false });
|
|
16
|
+
/* ───────────────────────────── Base Job ───────────────────────────── */
|
|
17
|
+
const JobSchema = new Schema({
|
|
18
|
+
name: String,
|
|
19
|
+
campaign: { type: Schema.Types.ObjectId, ref: "Campaign" },
|
|
20
|
+
description: String,
|
|
21
|
+
bullMQJobId: String, // bullmq job id
|
|
22
|
+
status: { type: String, enum: jobStatusEnum, default: 'waiting' },
|
|
23
|
+
priority: Number, // 1 (highest) .. 10 (lowest)
|
|
24
|
+
schedule: {
|
|
25
|
+
type: { type: String, enum: ["once", "cron"], default: "once" },
|
|
26
|
+
run_at: Date, // for one-off
|
|
27
|
+
cron: String, // for recurring
|
|
28
|
+
timezone: String,
|
|
29
|
+
backoff: { type: backoff, default: undefined },
|
|
30
|
+
cancel_requested: { type: Boolean, default: false },
|
|
31
|
+
},
|
|
32
|
+
jobType: { type: String, enum: ["outboundCall"], default: "outboundCall" },
|
|
33
|
+
result_ref: Schema.Types.Mixed,
|
|
34
|
+
error_ref: Schema.Types.Mixed,
|
|
35
|
+
log: [logEntry],
|
|
36
|
+
tags: [String],
|
|
37
|
+
createdBy: { type: Schema.Types.ObjectId, ref: 'Users' },
|
|
38
|
+
business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
|
|
39
|
+
}, {
|
|
40
|
+
discriminatorKey: 'jobType', timestamps: true, index: [
|
|
41
|
+
{ status: 1, 'schedule.run_at': 1 },
|
|
42
|
+
{ business: 1, status: 1 },
|
|
43
|
+
{ 'schedule.type': 1, 'schedule.run_at': 1 },
|
|
44
|
+
{ bullMQJobId: 1 }
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
// Pre-save middleware for validation
|
|
48
|
+
JobSchema.pre('save', function (next) {
|
|
49
|
+
// Validate schedule based on type
|
|
50
|
+
if (this.schedule.type === 'once' && !this.schedule.run_at) {
|
|
51
|
+
return next(new Error('run_at is required for one-time jobs'));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (this.schedule.type === 'cron' && !this.schedule.cron) {
|
|
55
|
+
return next(new Error('cron expression is required for recurring jobs'));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Validate priority
|
|
59
|
+
if (this.priority < 1 || this.priority > 10) {
|
|
60
|
+
return next(new Error('Priority must be between 1 and 10'));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
next();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Instance methods
|
|
67
|
+
JobSchema.methods.addLog = function (level, message, data = {}) {
|
|
68
|
+
this.log.push({
|
|
69
|
+
level,
|
|
70
|
+
message,
|
|
71
|
+
data,
|
|
72
|
+
timestamp: new Date()
|
|
73
|
+
});
|
|
74
|
+
return this.save();
|
|
75
|
+
};
|
|
76
|
+
JobSchema.methods.markAsStarted = function () {
|
|
77
|
+
this.status = 'active';
|
|
78
|
+
this.lastExecutedAt = new Date();
|
|
79
|
+
this.executionCount += 1;
|
|
80
|
+
return this.save();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
JobSchema.methods.markAsCompleted = function (result = null, duration = null) {
|
|
84
|
+
this.status = 'completed';
|
|
85
|
+
this.result_ref = result;
|
|
86
|
+
if (duration) this.actualDuration = duration;
|
|
87
|
+
return this.save();
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
JobSchema.methods.markAsFailed = function (error, duration = null) {
|
|
91
|
+
this.status = 'failed';
|
|
92
|
+
this.error_ref = {
|
|
93
|
+
message: error.message,
|
|
94
|
+
stack: error.stack,
|
|
95
|
+
timestamp: new Date()
|
|
96
|
+
};
|
|
97
|
+
if (duration) this.actualDuration = duration;
|
|
98
|
+
return this.save();
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// if schedule is updated then trigger sync
|
|
102
|
+
|
|
103
|
+
// channelId, to, agentId, PreContext
|
|
104
|
+
|
|
105
|
+
export const Job = defineModel('Job', JobSchema, 'Job');
|
|
106
|
+
const outboundCallPayload = new Schema({
|
|
107
|
+
channel: { type: Schema.Types.ObjectId, ref: "Channel" },
|
|
108
|
+
agent: { type: Schema.Types.ObjectId, ref: "Agent" },
|
|
109
|
+
to: { type: String, required: true },
|
|
110
|
+
accessToken: { type: String, required: true },
|
|
111
|
+
PreContext: String,
|
|
112
|
+
expectedDuration: Number,
|
|
113
|
+
maxRetries: { type: Number, default: 3 },
|
|
114
|
+
callbackUrl: String,
|
|
115
|
+
cps: Number,
|
|
116
|
+
conversationId: { type: Schema.Types.ObjectId, ref: 'conversation' }
|
|
117
|
+
}, { _id: false })
|
|
118
|
+
/* ───────────────────────────── Outbound Call Job ──────────────────────────── */
|
|
119
|
+
Job.discriminator('outboundCall', new Schema({ payload: outboundCallPayload }, { timestamps: true, discriminatorKey: 'jobType' }));
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Schema } from "mongoose";
|
|
2
|
+
import { defineModel } from "../runtime.js";
|
|
3
|
+
const leadStatusEnum = ["new", "contacted", "qualified", "converted", "lost"];
|
|
4
|
+
const platformEntrySchema = new Schema({
|
|
5
|
+
platform: { type: String, required: true }, // Phone,'Twitter', 'Instagram', 'Whatsapp', etc.
|
|
6
|
+
handle: { type: String, trim: true },
|
|
7
|
+
label: { type: String, trim: true }, // 'work', 'personal', 'brand'
|
|
8
|
+
isPrimary: { type: Boolean, default: false },
|
|
9
|
+
metadata: { type: Schema.Types.Mixed, default: {} }
|
|
10
|
+
}, { _id: false });
|
|
11
|
+
const contactDetailsSchema = new Schema({
|
|
12
|
+
whatsapp: [platformEntrySchema],
|
|
13
|
+
telegram: [platformEntrySchema],
|
|
14
|
+
email: [platformEntrySchema], // multiple emails (work, personal)
|
|
15
|
+
phone: [platformEntrySchema],
|
|
16
|
+
twitter: [platformEntrySchema],
|
|
17
|
+
instagram: [platformEntrySchema],
|
|
18
|
+
facebook: [platformEntrySchema],
|
|
19
|
+
// tiktok: [platformEntrySchema],
|
|
20
|
+
// youtube: [platformEntrySchema],
|
|
21
|
+
// snapchat: [platformEntrySchema],
|
|
22
|
+
// pinterest: [platformEntrySchema],
|
|
23
|
+
// reddit: [platformEntrySchema],
|
|
24
|
+
// threads: [platformEntrySchema],
|
|
25
|
+
// bluesky: [platformEntrySchema],
|
|
26
|
+
// signal: [platformEntrySchema],
|
|
27
|
+
// wechat: [platformEntrySchema],
|
|
28
|
+
// line: [platformEntrySchema],
|
|
29
|
+
// viber: [platformEntrySchema],
|
|
30
|
+
// discord: [platformEntrySchema],
|
|
31
|
+
// slack: [platformEntrySchema],
|
|
32
|
+
// linkedin: [platformEntrySchema],
|
|
33
|
+
// github: [platformEntrySchema],
|
|
34
|
+
// behance: [platformEntrySchema],
|
|
35
|
+
// dribbble: [platformEntrySchema],
|
|
36
|
+
// medium: [platformEntrySchema],
|
|
37
|
+
// substack: [platformEntrySchema],
|
|
38
|
+
// producthunt: [platformEntrySchema]
|
|
39
|
+
}, { _id: false });
|
|
40
|
+
/* ───────────────────────────── Lead ───────────────────────────── */
|
|
41
|
+
const LeadSchema = new Schema({
|
|
42
|
+
template: { type: Schema.Types.ObjectId, ref: 'LeadTemplate' },
|
|
43
|
+
business: { type: Schema.Types.ObjectId, ref: 'Businesses', required: true },
|
|
44
|
+
createdBy: { type: Schema.Types.ObjectId, ref: 'Users' },
|
|
45
|
+
//identity
|
|
46
|
+
name: { type: String, trim: true },
|
|
47
|
+
contactDetails: { type: contactDetailsSchema, default: () => ({}) },
|
|
48
|
+
source: String, // Whatsapp-Inbound
|
|
49
|
+
tags: [String],
|
|
50
|
+
//evaluation
|
|
51
|
+
leadScore: { type: Number, default: 0 },
|
|
52
|
+
status: { type: String, enum: leadStatusEnum, default: 'new' },
|
|
53
|
+
notes: { type: [String], trim: true },
|
|
54
|
+
// operations
|
|
55
|
+
lastInteractedAt: Date,
|
|
56
|
+
nextFollowUpAt: Date,
|
|
57
|
+
pendingTasks: Schema.Types.Mixed,
|
|
58
|
+
data: { type: Schema.Types.Mixed, default: () => ({}) },
|
|
59
|
+
}, { timestamps: true });
|
|
60
|
+
|
|
61
|
+
/* ───────────────────────────── Lead Template ───────────────────────────── */
|
|
62
|
+
// const leadTemplateFieldTypeEnum = ["string", "number", "email", "phone", "date", "boolean", "url", "text"];
|
|
63
|
+
// const fieldSchema = new Schema({
|
|
64
|
+
// name: { type: String, required: true, trim: true },
|
|
65
|
+
// type: { type: String, enum: leadTemplateFieldTypeEnum, required: true },
|
|
66
|
+
// required: { type: Boolean, default: false },
|
|
67
|
+
// defaultValue: { type: Schema.Types.Mixed, default: null },
|
|
68
|
+
// validation: { minLength: Number, maxLength: Number, min: Number, max: Number, pattern: String },
|
|
69
|
+
// label: { type: String, required: true },
|
|
70
|
+
// placeholder: { type: String, trim: true },
|
|
71
|
+
// description: { type: String, trim: true }
|
|
72
|
+
// }, { _id: false });
|
|
73
|
+
|
|
74
|
+
const LeadTemplateSchema = new Schema({
|
|
75
|
+
business: { type: Schema.Types.ObjectId, ref: 'Businesses', required: true },
|
|
76
|
+
createdBy: { type: Schema.Types.ObjectId, ref: 'Users', required: true },
|
|
77
|
+
name: { type: String, required: true, trim: true, unique: true },
|
|
78
|
+
description: { type: String, trim: true },
|
|
79
|
+
fields: Schema.Types.Mixed,
|
|
80
|
+
isActive: { type: Boolean, default: true }
|
|
81
|
+
}, { timestamps: true });
|
|
82
|
+
|
|
83
|
+
export const Lead = defineModel('Lead', LeadSchema, 'Leads');
|
|
84
|
+
export const LeadTemplate = defineModel('LeadTemplate', LeadTemplateSchema, 'LeadTemplates');
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// mongodb schema for all types of logs
|
|
2
|
+
import { Schema } from "mongoose";
|
|
3
|
+
import { defineModel } from "../runtime.js";
|
|
4
|
+
const LogSchema = new Schema({
|
|
5
|
+
user: { type: Schema.Types.ObjectId, ref: 'User' },
|
|
6
|
+
business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
|
|
7
|
+
level: { type: String, enum: ['warn', 'error', 'info', 'debug'] },
|
|
8
|
+
event: { type: String },
|
|
9
|
+
category: { type: String, enum: ['AUTHENTICATION', 'PAYMENT', 'CREDIT', 'SUBSCRIPTION', 'API_ACCESS', 'WEBHOOK', 'ERROR', 'OTHER',] },
|
|
10
|
+
status: { type: String, enum: ['SUCCESS', 'FAILURE', 'PENDING'], default: 'SUCCESS', },
|
|
11
|
+
message: String,
|
|
12
|
+
service: { type: String }, // Identifies which microservice or backend component produced the log
|
|
13
|
+
environment: { type: String, enum: ['dev', 'staging', 'prod'] },
|
|
14
|
+
requestId: String,
|
|
15
|
+
meta: Schema.Types.Mixed, // ipAddress, userAgent, etc.
|
|
16
|
+
data: Schema.Types.Mixed,
|
|
17
|
+
error: Schema.Types.Mixed,
|
|
18
|
+
response: Schema.Types.Mixed,
|
|
19
|
+
}, {
|
|
20
|
+
timestamps: true
|
|
21
|
+
});
|
|
22
|
+
// add index to the log schema
|
|
23
|
+
LogSchema.index({ user: 1, createdAt: -1 });
|
|
24
|
+
LogSchema.index({ event: 1, createdAt: -1 });
|
|
25
|
+
LogSchema.index({ category: 1, createdAt: -1 });
|
|
26
|
+
LogSchema.index({ status: 1, createdAt: -1 });
|
|
27
|
+
LogSchema.index({ service: 1, createdAt: -1 });
|
|
28
|
+
LogSchema.index({ environment: 1, createdAt: -1 });
|
|
29
|
+
LogSchema.index({ requestId: 1, createdAt: -1 });
|
|
30
|
+
LogSchema.index({ createdAt: 1 }, { expireAfterSeconds: 60 * 60 * 24 * 30 }); // 30 days
|
|
31
|
+
LogSchema.index({ 'data.platformMessageId': 1 }, { unique: true, sparse: true });
|
|
32
|
+
export const Log = defineModel('Log', LogSchema, 'Logs');
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Schema } from "mongoose";
|
|
2
|
+
import { defineModel } from "../runtime.js";
|
|
3
|
+
const MessageSessionSchema = new Schema({
|
|
4
|
+
campaign: { type: Schema.Types.ObjectId, ref: 'Campaign' },
|
|
5
|
+
firstMessage: { type: Schema.Types.ObjectId, ref: 'Message' },
|
|
6
|
+
lastMessage: { type: Schema.Types.ObjectId, ref: 'Message' },
|
|
7
|
+
conversation: { type: Schema.Types.ObjectId, ref: 'Conversation' },
|
|
8
|
+
business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
|
|
9
|
+
})
|
|
10
|
+
const MessagesSchema = new Schema({
|
|
11
|
+
conversation: { type: Schema.Types.ObjectId, ref: 'Conversation' },
|
|
12
|
+
campaign: { type: Schema.Types.ObjectId, ref: 'Campaign' },
|
|
13
|
+
business: { type: Schema.Types.ObjectId, ref: 'Businesses' },
|
|
14
|
+
externalMessageId: String,
|
|
15
|
+
direction: String,
|
|
16
|
+
sender: {
|
|
17
|
+
type: { type: String, enum: ["Lead", "agent", "user", "system", "unknown"], default: "Lead" },
|
|
18
|
+
id: String,
|
|
19
|
+
name: String,
|
|
20
|
+
ref: { type: Schema.Types.ObjectId, refPath: "sender.refModel" },
|
|
21
|
+
refModel: { type: String, enum: ["Lead", "Agent", "Users"] },
|
|
22
|
+
},
|
|
23
|
+
type: {
|
|
24
|
+
type: String,
|
|
25
|
+
enum: ["text", "image", "audio", "voice", "video", "document", "file", "sticker",
|
|
26
|
+
"location", "contacts", "interactive", "button", "order", "unknown", "template"],
|
|
27
|
+
default: "text",
|
|
28
|
+
},
|
|
29
|
+
kind: { type: String, enum: ["message", "postback", "system"], default: "message" },
|
|
30
|
+
content: { type: Schema.Types.Mixed, default: {} }, // { body } | location | interactive | …
|
|
31
|
+
repliedTo: { type: Schema.Types.ObjectId, ref: "Message" },
|
|
32
|
+
reactions: { type: [{ emoji: String, by: String, at: Date }], default: [], _id: false },
|
|
33
|
+
statusTimeline: {
|
|
34
|
+
scheduled: Date, initiated: Date, sent: Date, delivered: Date, read: Date, failed: Date, stopped: Date
|
|
35
|
+
},
|
|
36
|
+
usage: { type: Schema.Types.Mixed, default: {} },
|
|
37
|
+
misc: { type: Schema.Types.Mixed, default: {} },
|
|
38
|
+
errors: [{ type: Schema.Types.Mixed, default: [] }],
|
|
39
|
+
isInternalNote: { type: Boolean, default: false },
|
|
40
|
+
isSummarized: { type: Boolean, default: false },
|
|
41
|
+
// readByContact: { type: Boolean, default: We false }
|
|
42
|
+
}, {
|
|
43
|
+
timestamps: true
|
|
44
|
+
});
|
|
45
|
+
export const Message = defineModel('Message', MessagesSchema, "Messages");
|
|
46
|
+
export const MessageSession = defineModel('MessageSession', MessageSessionSchema, "MessageSessions");
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Schema } from "mongoose";
|
|
2
|
+
import { defineModel } from "../runtime.js";
|
|
3
|
+
// const CreditSchema = new Schema(
|
|
4
|
+
// {
|
|
5
|
+
// llm: { type: , min: 0, default: 0 },
|
|
6
|
+
// knowledge: { type: Number, min: 0, default: 0 },
|
|
7
|
+
// miscellaneous: { type: Number, min: 0, default: 0 },
|
|
8
|
+
// },
|
|
9
|
+
// { _id: false }
|
|
10
|
+
// );
|
|
11
|
+
const AmountSchema = new Schema({
|
|
12
|
+
value: { type: Number, required: true }, // eg: 22000
|
|
13
|
+
currency: { type: String, default: "INR" }
|
|
14
|
+
}, { _id: false });
|
|
15
|
+
const PlanSchema = new Schema({
|
|
16
|
+
business: { type: Schema.Types.ObjectId, ref: "Businesses" },
|
|
17
|
+
code: { type: String, unique: true }, // ['FREE', 'BASE', 'GROWTH', 'BASE_TOPUP', 'GROWTH_TOPUP'],
|
|
18
|
+
public: { type: Boolean, default: false },
|
|
19
|
+
name: { type: String, required: true },
|
|
20
|
+
description: String,
|
|
21
|
+
amount: AmountSchema,
|
|
22
|
+
type: { type: String, enum: ['FREE', 'BASE', 'TOPUP', 'ENTERPRISE', 'TEST'], required: true, index: true, },
|
|
23
|
+
validity: { type: Number, default: 30 },// in days
|
|
24
|
+
credits: Number,
|
|
25
|
+
spendRatio: { type: Number, enum: [1080, 1666, 1583], default: 1583 },
|
|
26
|
+
status: { type: String, enum: ['active', 'inactive'], default: 'active' },
|
|
27
|
+
features: [String],
|
|
28
|
+
allowedTopUps: [{ type: Schema.Types.ObjectId, ref: 'Plans' }],
|
|
29
|
+
autoRenew: { type: Boolean, default: false },
|
|
30
|
+
paymentGateWay: {
|
|
31
|
+
razorpay: {
|
|
32
|
+
plan_id: String,
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
}, { timestamps: true });
|
|
36
|
+
export const Plan = defineModel('Plans', PlanSchema, "Plans");
|
|
37
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Schema, Types } from "mongoose";
|
|
2
|
+
import { defineModel } from "../runtime.js";
|
|
3
|
+
import { Notification } from "./notifications.js";
|
|
4
|
+
|
|
5
|
+
const TicketSchema = new Schema(
|
|
6
|
+
{
|
|
7
|
+
business: { type: Types.ObjectId, ref: 'Businesses' },
|
|
8
|
+
issueSummary: { type: String, required: true },
|
|
9
|
+
channel: { type: String, enum: ['telegram', 'whatsapp', 'web', 'phone', 'instagram', 'sms', 'email'], required: true, },
|
|
10
|
+
priority: { type: String, enum: ['low', 'medium', 'high'], default: 'medium', },
|
|
11
|
+
status: { type: String, enum: ['pending', 'responded', 'resolved'], default: 'pending' },
|
|
12
|
+
contactDetails: {
|
|
13
|
+
email: { type: String },
|
|
14
|
+
phone: { type: String },
|
|
15
|
+
telegramId: { type: String },
|
|
16
|
+
whatsappId: { type: String },
|
|
17
|
+
instagramId: { type: String },
|
|
18
|
+
},
|
|
19
|
+
notifierEmail: { type: String, required: true },
|
|
20
|
+
response: {
|
|
21
|
+
channelId: { type: Schema.Types.ObjectId, ref: "Channel" },
|
|
22
|
+
from: { type: String },
|
|
23
|
+
to: { type: String },
|
|
24
|
+
cc: { type: String },
|
|
25
|
+
subject: { type: String },
|
|
26
|
+
bcc: { type: String },
|
|
27
|
+
text: { type: String },
|
|
28
|
+
html: { type: String },
|
|
29
|
+
updatedAt: { type: Date },
|
|
30
|
+
sentAt: { type: Date },
|
|
31
|
+
resolvedAt: { type: Date },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{ timestamps: true }
|
|
35
|
+
);
|
|
36
|
+
TicketSchema.methods.markSent = function (response) {
|
|
37
|
+
this.status = 'responded';
|
|
38
|
+
this.response = response;
|
|
39
|
+
return this.save();
|
|
40
|
+
};
|
|
41
|
+
TicketSchema.methods.markResolved = function () {
|
|
42
|
+
this.status = 'resolved';
|
|
43
|
+
this.response.resolvedAt = new Date();
|
|
44
|
+
return this.save();
|
|
45
|
+
};
|
|
46
|
+
// on ticket creation, create a notification
|
|
47
|
+
TicketSchema.post('save', async function (doc) {
|
|
48
|
+
if (this.isNew) await Notification.create({ business: doc.business, head: `${doc.priority} Priority Ticket Created on ${doc.channel}`, body: doc.issueSummary, type: "ticket", attachments: { ticketId: doc._id } });
|
|
49
|
+
});
|
|
50
|
+
export const Ticket = defineModel('Ticket', TicketSchema, 'Ticket');
|