Spaces:
Running
Running
File size: 8,802 Bytes
3ab344a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | const Provider = require('../models/providerModel');
const User = require('../models/userModel');
const Product = require('../models/productModel');
const Order = require('../models/orderModel');
const { deleteImage, getPublicIdFromUrl } = require('../config/cloudinary');
// Get all providers
exports.getAllProviders = async (req, res) => {
try {
const providers = await Provider.find().populate('user', 'email');
// Calculate stats for each provider
const providersWithStats = await Promise.all(
providers.map(async (provider) => {
const providerData = provider.toObject();
// Add email from user
if (provider.user) {
providerData.email = provider.user.email;
}
// Count total products for this provider
const totalProducts = await Product.countDocuments({
provider: provider._id,
});
// Get all products for this provider
const products = await Product.find({ provider: provider._id }).select(
'_id',
);
const productIds = products.map((p) => p._id);
// Calculate total sales and order count from COMPLETED orders only
const orders = await Order.find({
'items.product': { $in: productIds },
orderStatus: 'completed', // Only count delivered orders
});
let totalSales = 0;
const orderSet = new Set();
orders.forEach((order) => {
orderSet.add(order._id.toString());
// Sum up sales for this provider's products in each order
order.items.forEach((item) => {
if (productIds.some((id) => id.equals(item.product))) {
totalSales += item.quantity * item.unitPrice;
}
});
});
providerData.totalProducts = totalProducts;
providerData.totalSales = totalSales;
providerData.orderCount = orderSet.size;
return providerData;
}),
);
res.status(200).json({
status: 'success',
results: providersWithStats.length,
data: {
providers: providersWithStats,
},
});
} catch (err) {
res.status(500).json({
status: 'fail',
message: err.message,
});
}
};
// Get single provider
exports.getProvider = async (req, res) => {
try {
const provider = await Provider.findById(req.params.id).populate(
'user',
'email',
);
if (!provider) {
return res.status(404).json({
status: 'fail',
message: 'No provider found with that ID',
});
}
// Include email from user in response
const providerData = provider.toObject();
if (provider.user) {
providerData.email = provider.user.email;
}
res.status(200).json({
status: 'success',
data: { provider: providerData },
});
} catch (err) {
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
// Create a new provider
exports.createProvider = async (req, res) => {
try {
const { email, password, name, storeName, phoneNumber, address } = req.body;
// 1. Check if email or phone already exists in User collection
const existingUser = await User.findOne({
$or: [{ email }, { phone: phoneNumber }],
});
if (existingUser) {
const field =
existingUser.email === email ? 'البريد الإلكتروني' : 'رقم الهاتف';
return res.status(400).json({
status: 'fail',
message: `${field} مسجل بالفعل لمستخدم آخر`,
});
}
// 2. Get next provider ID
const lastProvider = await Provider.findOne().sort({ id: -1 });
const nextId = lastProvider ? lastProvider.id + 1 : 1;
const providerData = {
name,
storeName,
phoneNumber,
address,
id: nextId,
};
if (req.file) {
providerData.logo = req.file.path;
}
// 3. Create Provider document first
let newProvider;
try {
newProvider = await Provider.create(providerData);
} catch (err) {
if (err.code === 11000) {
const field = Object.keys(err.keyPattern)[0];
const message =
field === 'storeName'
? 'اسم المتجر مسجل بالفعل'
: 'رقم الهاتف مسجل بالفعل في قائمة الموردين';
return res.status(400).json({ status: 'fail', message });
}
throw err;
}
// 4. Create User account for vendor
try {
const vendorUser = await User.create({
name,
email,
phone: phoneNumber,
password,
role: 'vendor',
provider: newProvider._id,
});
// 5. Update provider with user reference
newProvider.user = vendorUser._id;
await newProvider.save();
res.status(201).json({
status: 'success',
data: { provider: newProvider },
});
} catch (err) {
// Rollback: Delete the created provider if user creation fails
await Provider.findByIdAndDelete(newProvider._id);
throw err;
}
} catch (err) {
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
// Update a provider
exports.updateProvider = async (req, res) => {
try {
const providerId = req.params.id;
const oldProvider = await Provider.findById(providerId);
if (!oldProvider) {
return res.status(404).json({
status: 'fail',
message: 'No provider found with that ID',
});
}
const updateData = { ...req.body };
// Handle logo update or deletion
if (req.file) {
// New logo uploaded
updateData.logo = req.file.path;
// Delete old logo from Cloudinary if it exists
if (oldProvider.logo) {
const publicId = getPublicIdFromUrl(oldProvider.logo);
if (publicId) {
await deleteImage(publicId).catch((err) =>
console.error('Cloudinary delete error:', err),
);
}
}
} else if (req.body.logo === '') {
// Logo explicitly removed
updateData.logo = '';
// Delete old logo from Cloudinary if it exists
if (oldProvider.logo) {
const publicId = getPublicIdFromUrl(oldProvider.logo);
if (publicId) {
await deleteImage(publicId).catch((err) =>
console.error('Cloudinary delete error:', err),
);
}
}
} else {
// Keep existing logo - remove it from updateData so it doesn't try to update with a string/URL
delete updateData.logo;
}
const updatedProvider = await Provider.findByIdAndUpdate(
providerId,
updateData,
{ new: true, runValidators: true },
);
if (!updatedProvider) {
return res.status(404).json({
status: 'fail',
message: 'No provider found with that ID',
});
}
// Also update the associated User's email, phone, and password if they changed
if (
updatedProvider.user &&
(req.body.email || req.body.phoneNumber || req.body.password)
) {
const user = await User.findById(updatedProvider.user);
if (user) {
if (req.body.email) user.email = req.body.email;
if (req.body.phoneNumber) user.phone = req.body.phoneNumber;
if (req.body.password) user.password = req.body.password;
await user.save();
}
}
res.status(200).json({
status: 'success',
data: { provider: updatedProvider },
});
} catch (err) {
if (err.code === 11000) {
const field = Object.keys(err.keyPattern)[0];
const message =
field === 'storeName'
? 'اسم المتجر مسجل بالفعل'
: 'رقم الهاتف أو البريد الإلكتروني مسجل بالفعل';
return res.status(400).json({ status: 'fail', message });
}
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
// Delete a provider
exports.deleteProvider = async (req, res) => {
try {
const provider = await Provider.findById(req.params.id);
if (!provider) {
return res.status(404).json({
status: 'fail',
message: 'No provider found with that ID',
});
}
// Delete associated user
if (provider.user) {
await User.findByIdAndDelete(provider.user);
}
// Delete logo from Cloudinary if it exists
if (provider.logo) {
const publicId = getPublicIdFromUrl(provider.logo);
if (publicId) await deleteImage(publicId);
}
await Provider.findByIdAndDelete(req.params.id);
res.status(204).json({
status: 'success',
data: null,
});
} catch (err) {
res.status(400).json({
status: 'fail',
message: err.message,
});
}
};
|