shuttlepro-shared 1.2.90 → 1.2.92
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/common/repositories/customerProfile.repository.js +147 -0
- package/models/CustomerProfile.js +22 -0
- package/models/Order.js +107 -9
- package/models.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const { getRedisData, setRedisData } = require("../../config/redis");
|
|
2
|
+
const CustomerProfile = require("../../models/CustomerProfile");
|
|
3
|
+
|
|
4
|
+
const CACHE_KEY_ALL = "customer_profiles_all";
|
|
5
|
+
|
|
6
|
+
const getCachedAllCustomerProfiles = async () => {
|
|
7
|
+
let profiles = await getRedisData(CACHE_KEY_ALL);
|
|
8
|
+
if (!profiles) {
|
|
9
|
+
profiles = await CustomerProfile.find({}).lean().exec();
|
|
10
|
+
await setRedisData(CACHE_KEY_ALL, profiles);
|
|
11
|
+
}
|
|
12
|
+
return profiles;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const updateCachedAllCustomerProfiles = async () => {
|
|
16
|
+
const profiles = await CustomerProfile.find({}).lean().exec();
|
|
17
|
+
await setRedisData(CACHE_KEY_ALL, profiles);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const getCachedCustomerProfiles = async (workspaceId) => {
|
|
21
|
+
const allProfiles = await getCachedAllCustomerProfiles();
|
|
22
|
+
return allProfiles.filter((profile) => profile.workspaceId === workspaceId);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const createCustomerProfile = async (data) => {
|
|
26
|
+
const newProfile = new CustomerProfile(data);
|
|
27
|
+
const savedProfile = await newProfile.save();
|
|
28
|
+
|
|
29
|
+
updateCachedAllCustomerProfiles();
|
|
30
|
+
return savedProfile;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const findCustomerProfilesByWorkspaceId = async (workspaceId) => {
|
|
34
|
+
return await getCachedCustomerProfiles(workspaceId);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const findCustomerProfilesByWorkspace = async (workspaceId, filter = {}) => {
|
|
38
|
+
const profiles = await getCachedCustomerProfiles(workspaceId);
|
|
39
|
+
return profiles.filter((profile) =>
|
|
40
|
+
Object.entries(filter).every(([key, value]) => profile[key] === value)
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const findCustomerProfileByFilter = async (
|
|
45
|
+
filter = {},
|
|
46
|
+
bodyFilter = {},
|
|
47
|
+
workspaceId = null
|
|
48
|
+
) => {
|
|
49
|
+
const allProfiles = await getCachedAllCustomerProfiles();
|
|
50
|
+
|
|
51
|
+
const filtered = workspaceId
|
|
52
|
+
? allProfiles.filter((p) => p.workspaceId === workspaceId)
|
|
53
|
+
: allProfiles;
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
filtered.find(
|
|
57
|
+
(profile) =>
|
|
58
|
+
Object.entries(filter).every(
|
|
59
|
+
([key, value]) => profile[key] === value
|
|
60
|
+
) &&
|
|
61
|
+
Object.entries(bodyFilter).every(
|
|
62
|
+
([key, value]) => profile.body?.[key] === value
|
|
63
|
+
)
|
|
64
|
+
) || null
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const findAllCustomerProfilesByFilter = async (
|
|
69
|
+
filter = {},
|
|
70
|
+
bodyFilter = {},
|
|
71
|
+
workspaceId = null
|
|
72
|
+
) => {
|
|
73
|
+
const allProfiles = await getCachedAllCustomerProfiles();
|
|
74
|
+
|
|
75
|
+
const filtered = workspaceId
|
|
76
|
+
? allProfiles.filter((p) => p.workspaceId === workspaceId)
|
|
77
|
+
: allProfiles;
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
filtered.filter(
|
|
81
|
+
(profile) =>
|
|
82
|
+
Object.entries(filter).every(
|
|
83
|
+
([key, value]) => profile[key] === value
|
|
84
|
+
) &&
|
|
85
|
+
Object.entries(bodyFilter).every(
|
|
86
|
+
([key, value]) => profile.body?.[key] === value
|
|
87
|
+
)
|
|
88
|
+
) || []
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const updateCustomerProfile = async (id, data) => {
|
|
93
|
+
const updated = await CustomerProfile.findByIdAndUpdate(id, data, {
|
|
94
|
+
new: true,
|
|
95
|
+
}).exec();
|
|
96
|
+
|
|
97
|
+
if (updated) {
|
|
98
|
+
updateCachedAllCustomerProfiles();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return updated;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const updateCustomerProfileByFilter = async (
|
|
105
|
+
filter,
|
|
106
|
+
data,
|
|
107
|
+
workspaceId = null
|
|
108
|
+
) => {
|
|
109
|
+
const query = workspaceId ? { ...filter, workspaceId } : filter;
|
|
110
|
+
|
|
111
|
+
const updated = await CustomerProfile.findOneAndUpdate(query, data, {
|
|
112
|
+
new: true,
|
|
113
|
+
}).exec();
|
|
114
|
+
|
|
115
|
+
if (updated) {
|
|
116
|
+
updateCachedAllCustomerProfiles();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return updated;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const deleteCustomerProfile = async (id) => {
|
|
123
|
+
const deleted = await CustomerProfile.findByIdAndDelete(id).exec();
|
|
124
|
+
|
|
125
|
+
if (deleted) {
|
|
126
|
+
updateCachedAllCustomerProfiles();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return deleted;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const deleteAllCustomerProfilesByWorkspace = async (workspaceId) => {
|
|
133
|
+
await CustomerProfile.deleteMany({ workspaceId }).exec();
|
|
134
|
+
await updateCachedAllCustomerProfiles();
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
module.exports = {
|
|
138
|
+
createCustomerProfile,
|
|
139
|
+
findCustomerProfilesByWorkspaceId,
|
|
140
|
+
findCustomerProfilesByWorkspace,
|
|
141
|
+
findCustomerProfileByFilter,
|
|
142
|
+
updateCustomerProfile,
|
|
143
|
+
updateCustomerProfileByFilter,
|
|
144
|
+
deleteCustomerProfile,
|
|
145
|
+
deleteAllCustomerProfilesByWorkspace,
|
|
146
|
+
findAllCustomerProfilesByFilter,
|
|
147
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const mongoose = require("mongoose");
|
|
2
|
+
const { Schema } = mongoose;
|
|
3
|
+
const CustomerProfileSchema = new Schema(
|
|
4
|
+
{
|
|
5
|
+
name: { type: String, default: "" },
|
|
6
|
+
email: { type: String, default: "" },
|
|
7
|
+
contact: { type: String, default: "" },
|
|
8
|
+
picture: { type: String, default: "" },
|
|
9
|
+
fbId: { type: String, default: "" },
|
|
10
|
+
igId: { type: String, default: "" },
|
|
11
|
+
blackList: { type: Boolean, default: false },
|
|
12
|
+
mergedId: {
|
|
13
|
+
type: Schema.Types.ObjectId,
|
|
14
|
+
ref: "CustomerProfile",
|
|
15
|
+
default: null,
|
|
16
|
+
},
|
|
17
|
+
body: {},
|
|
18
|
+
},
|
|
19
|
+
{ timestamps: true, toJSON: { virtuals: true }, toObject: { virtuals: true } }
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
module.exports = mongoose.model("CustomerProfile", CustomerProfileSchema);
|
package/models/Order.js
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
const mongoose = require("mongoose");
|
|
2
2
|
const { Schema } = mongoose;
|
|
3
|
+
const normalizePhoneNumber = (phone) => {
|
|
4
|
+
let normalized = phone.replace(/[^\d]/g, "");
|
|
5
|
+
if (normalized.startsWith("92")) {
|
|
6
|
+
normalized = normalized.replace(/^92/, "");
|
|
7
|
+
}
|
|
8
|
+
if (normalized.startsWith("0")) {
|
|
9
|
+
normalized = normalized.substring(1);
|
|
10
|
+
}
|
|
11
|
+
return normalized;
|
|
12
|
+
};
|
|
13
|
+
const getPhoneRegex = (phone) => {
|
|
14
|
+
const normalizedPhone = normalizePhoneNumber(phone);
|
|
15
|
+
return new RegExp(
|
|
16
|
+
`^0?${normalizedPhone}$|^\\+92${normalizedPhone}$|^${normalizedPhone}$`,
|
|
17
|
+
"i"
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
const _ = require("lodash");
|
|
3
21
|
|
|
4
22
|
const ShipperInformation = new Schema({
|
|
5
23
|
_id: false,
|
|
@@ -12,6 +30,7 @@ const ShipperInformation = new Schema({
|
|
|
12
30
|
originCityName: { type: String, default: "" }, //M&P, TRAX, INSTA, RIDER, TCS, CC
|
|
13
31
|
remarks: { type: String, default: "" },
|
|
14
32
|
customer_note: { type: String, default: "" },
|
|
33
|
+
orderId: { type: Schema.Types.ObjectId, ref: "Order", default: null },
|
|
15
34
|
return_branch: { type: String, default: "" },
|
|
16
35
|
cityData: { type: String, default: "" }, //M&P, TRAX, INSTA, RIDER, TCS, CC
|
|
17
36
|
//TRAX
|
|
@@ -33,11 +52,18 @@ const ShipperInformation = new Schema({
|
|
|
33
52
|
|
|
34
53
|
const OrderSchema = new Schema(
|
|
35
54
|
{
|
|
55
|
+
webOrderId: { type: String, default: "" },
|
|
56
|
+
webOrderNumber: { type: String, default: "" },
|
|
57
|
+
orderNumber: { type: String, default: "" },
|
|
36
58
|
customerId: { type: Schema.Types.ObjectId, ref: "Customer", default: null },
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
59
|
+
customerName: { type: String, default: "" },
|
|
60
|
+
customerPhone: { type: String, default: "" },
|
|
61
|
+
customerAddress: { type: String, default: "" },
|
|
40
62
|
cityName: { type: String, default: "" },
|
|
63
|
+
trackingId: { type: String, default: "" },
|
|
64
|
+
shipperInformation: ShipperInformation,
|
|
65
|
+
isCnGenerated: { type: Boolean, default: false },
|
|
66
|
+
swap: { type: String, default: "" },
|
|
41
67
|
status: { type: String, default: "" },
|
|
42
68
|
lastStatusTime: { type: String, default: "" },
|
|
43
69
|
statusType: { type: String, default: "" },
|
|
@@ -60,16 +86,15 @@ const OrderSchema = new Schema(
|
|
|
60
86
|
payableAmount: { type: Number, default: 0 },
|
|
61
87
|
parcelValue: { type: Number, default: 0 },
|
|
62
88
|
payableAmount: { type: Number, default: 0 },
|
|
63
|
-
customerName: { type: String, default: "" },
|
|
64
|
-
customerPhone: { type: String, default: "" },
|
|
65
|
-
customerAddress: { type: String, default: "" },
|
|
66
89
|
discountPercentage: { type: Number, default: 0 },
|
|
67
90
|
discountValue: { type: Number, default: 0 },
|
|
68
91
|
productDetails: { type: String, default: "" },
|
|
69
92
|
webOrderId: { type: String, default: "" },
|
|
93
|
+
parentOrderId: { type: Schema.Types.ObjectId, ref: "Order", default: null },
|
|
70
94
|
webOrderNumber: { type: String, default: "" },
|
|
71
95
|
fulfillmentStatus: { type: String, default: "" },
|
|
72
96
|
webFulfillmentId: { type: String, default: "" },
|
|
97
|
+
platformFinancialStatus: { type: String, default: "pending" },
|
|
73
98
|
pinLocation: { type: String, default: "" },
|
|
74
99
|
deliveryCharges: { type: Number, default: 0 },
|
|
75
100
|
tax: { type: Number, default: 0 },
|
|
@@ -83,7 +108,6 @@ const OrderSchema = new Schema(
|
|
|
83
108
|
quantity: { type: Number, default: 0 },
|
|
84
109
|
assignTo: { type: Schema.Types.ObjectId, ref: "User", default: null },
|
|
85
110
|
isLoadSheetGenerated: { type: Boolean, default: false },
|
|
86
|
-
orderNumber: { type: String, default: "" },
|
|
87
111
|
orderDate: { type: String, default: "" },
|
|
88
112
|
returnDate: { type: String, default: "" },
|
|
89
113
|
receivedDate: { type: String, default: "" },
|
|
@@ -98,8 +122,8 @@ const OrderSchema = new Schema(
|
|
|
98
122
|
invalidCredentials: { type: Boolean, default: false },
|
|
99
123
|
isConfirmed: { type: Boolean, default: false },
|
|
100
124
|
confirmedBy: { type: Schema.Types.ObjectId, ref: "User", default: null },
|
|
101
|
-
isBulk: { type: String, default: "" },
|
|
102
125
|
priority: { type: String, default: "" },
|
|
126
|
+
isBulk: { type: String, default: "" },
|
|
103
127
|
conversationId: { type: String, default: "" },
|
|
104
128
|
createdBy: { type: Schema.Types.ObjectId, ref: "User", default: null },
|
|
105
129
|
updatedBy: { type: Schema.Types.ObjectId, ref: "User", default: null },
|
|
@@ -107,13 +131,13 @@ const OrderSchema = new Schema(
|
|
|
107
131
|
isDuplicate: { type: Boolean, default: false },
|
|
108
132
|
ivrGenerated: { type: Boolean, default: false },
|
|
109
133
|
isActivityGenerated: { type: Boolean, default: false },
|
|
110
|
-
platformFinancialStatus: { type: String, default: "pending" },
|
|
111
134
|
payment: {
|
|
112
135
|
isPaid: { type: Boolean, default: false },
|
|
113
136
|
paymentDate: { type: String, default: "" },
|
|
114
137
|
paymentDetails: {},
|
|
115
138
|
},
|
|
116
139
|
credentials: {},
|
|
140
|
+
ticketId: { type: String, default: "" },
|
|
117
141
|
sender: { type: String, default: "" },
|
|
118
142
|
orderName: { type: String, default: "" },
|
|
119
143
|
totalWeight: { type: String, default: "" },
|
|
@@ -133,6 +157,80 @@ OrderSchema.virtual("orderProducts", {
|
|
|
133
157
|
foreignField: "orderId",
|
|
134
158
|
});
|
|
135
159
|
|
|
160
|
+
OrderSchema.post("save", async function (doc) {
|
|
161
|
+
try {
|
|
162
|
+
if (doc) {
|
|
163
|
+
markOrUnMarkOrderAsDuplicate(doc);
|
|
164
|
+
}
|
|
165
|
+
return { code: 200 };
|
|
166
|
+
} catch (err) {
|
|
167
|
+
console.log("err", err);
|
|
168
|
+
return { code: 400 };
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
OrderSchema.post("findOneAndUpdate", async function (doc) {
|
|
173
|
+
try {
|
|
174
|
+
if (doc) {
|
|
175
|
+
markOrUnMarkOrderAsDuplicate(doc);
|
|
176
|
+
}
|
|
177
|
+
return { code: 200 };
|
|
178
|
+
} catch (err) {
|
|
179
|
+
console.log("err", err);
|
|
180
|
+
return { code: 400 };
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const markOrUnMarkOrderAsDuplicate = async (doc) => {
|
|
185
|
+
try {
|
|
186
|
+
if (["pending", "cancelled", "published"].includes(doc?.statusType)) {
|
|
187
|
+
if (["cancelled"].includes(doc?.statusType)) {
|
|
188
|
+
await Order.updateOne(
|
|
189
|
+
{ _id: doc?._id },
|
|
190
|
+
{ $set: { isDuplicate: false } }
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
const phoneRegex = getPhoneRegex(doc?.customerPhone);
|
|
194
|
+
let orders = await Order.find({
|
|
195
|
+
workspaceId: doc?.workspaceId,
|
|
196
|
+
isDeleted: false,
|
|
197
|
+
statusType: "pending",
|
|
198
|
+
customerPhone: phoneRegex,
|
|
199
|
+
})
|
|
200
|
+
.lean()
|
|
201
|
+
.exec();
|
|
202
|
+
if (orders?.length > 1) {
|
|
203
|
+
const ordersByCity = _.groupBy(orders, "cityName");
|
|
204
|
+
const bulkOps = [];
|
|
205
|
+
for (const cityName in ordersByCity) {
|
|
206
|
+
const cityOrders = ordersByCity[cityName];
|
|
207
|
+
const isDuplicate = cityOrders.length > 1;
|
|
208
|
+
const orderIds = cityOrders.map((order) => order?._id);
|
|
209
|
+
bulkOps.push({
|
|
210
|
+
updateMany: {
|
|
211
|
+
filter: { _id: { $in: orderIds } },
|
|
212
|
+
update: { $set: { isDuplicate } },
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
if (bulkOps.length > 0) {
|
|
217
|
+
await Order.bulkWrite(bulkOps);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
await Order.updateMany(
|
|
221
|
+
{ _id: { $in: orders.map((d) => d?._id?.toString()) } },
|
|
222
|
+
{ $set: { isDuplicate: false } }
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
return { code: 200 };
|
|
226
|
+
}
|
|
227
|
+
return { code: 200 };
|
|
228
|
+
} catch (err) {
|
|
229
|
+
console.log("err", err);
|
|
230
|
+
return { code: 400 };
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
136
234
|
const Order = mongoose.model("Order", OrderSchema);
|
|
137
235
|
|
|
138
236
|
module.exports = Order;
|
package/models.js
CHANGED
|
@@ -41,6 +41,7 @@ const Role = require("./models/Role");
|
|
|
41
41
|
const NewProduct = require("./models/NewProduct");
|
|
42
42
|
const NotificationSettings = require("./models/NotificationSettings");
|
|
43
43
|
const UserWorkflow = require("./models/UserWorkflow");
|
|
44
|
+
const Setting = require("./models/Setting");
|
|
44
45
|
module.exports = {
|
|
45
46
|
Website,
|
|
46
47
|
ProductQueue,
|
|
@@ -85,4 +86,5 @@ module.exports = {
|
|
|
85
86
|
NewProduct,
|
|
86
87
|
NotificationSettings,
|
|
87
88
|
UserWorkflow,
|
|
89
|
+
Setting,
|
|
88
90
|
};
|