1929 lines
62 KiB
JavaScript
1929 lines
62 KiB
JavaScript
const CartItem = require("../models/CartItem");
|
|
const Order = require("../models/Order");
|
|
const User = require("../models/User");
|
|
const Food = require("../models/Food");
|
|
const Payment = require("../models/Payment");
|
|
const DiscountCode = require("../models/DiscountCode");
|
|
const StoreInfo = require("../models/StoreInfo");
|
|
const { body, validationResult } = require("express-validator");
|
|
const { res404, res500, checkValidations } = require("../plugins/controllersHelperFunctions");
|
|
const { _sr } = require("../plugins/serverResponses");
|
|
const axios = require("axios");
|
|
const zarinpal = require("./../zarinpal");
|
|
const { sendSingle, sendMulti } = require("./../plugins/pushNotif").notification;
|
|
const { sendNotifyOrder } = require("./../socket/adminNotify");
|
|
const moment = require("moment-jalaali");
|
|
const { sms } = require("./../SMSModule");
|
|
const CronJob = require("cron").CronJob;
|
|
|
|
/////////// variables
|
|
const apiKey =
|
|
"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImRiYjIwMmRhYzAxYzFjNzgwYjgxNWQyZDgyMWNmNmY1Njk0MThhMGE3N2Q1M2Y0OTZkYzQzYTgxMmNmN2U3ZWJjNzI5MjY5YjkxMjA4MTYyIn0.eyJhdWQiOiIxNDk3OSIsImp0aSI6ImRiYjIwMmRhYzAxYzFjNzgwYjgxNWQyZDgyMWNmNmY1Njk0MThhMGE3N2Q1M2Y0OTZkYzQzYTgxMmNmN2U3ZWJjNzI5MjY5YjkxMjA4MTYyIiwiaWF0IjoxNjI3MzI2Mzc0LCJuYmYiOjE2MjczMjYzNzQsImV4cCI6MTYyOTkxODM3NCwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.hyKNSy4fmPps6yIdm33Wof-mES9ujh5lmI3VFWyecbkNCm9ATPwsZ9s53A3a1wPJmHfLBXpCcob5NGL-GjZlVfqfRBiReRMr_iniCjUOnqENfFwVEJutxI-xrzVe7PZzOgx1Vr6WwSUHvQ36eJSS1lBlHlqCgwRbkG0hs4YdZsKhzhfYdlAluNw9djjUAMbRWZVL0EluP9CYko4w8tB0KHUZMZYGQcevCfb_3OU9ygHo7B--Z5aTPfm7IK4eP0gHsZ_t857B3tu3ZJB1mkgxc2R9gZUflKqj1ZqkYiR0uMGP-571enXh6pYQLXL2k-gOxLIedCaE6XytxVXhENnotA";
|
|
const limit = 20;
|
|
const zarinUrl = "https://www.zarinpal.com/pg/StartPay";
|
|
const timeToStart = 1800000;
|
|
// const timeToStart = 1800000
|
|
|
|
////////// functions
|
|
const deg2rad = (deg) => {
|
|
return deg * (Math.PI / 180);
|
|
};
|
|
|
|
const _computeShippingCost = async (addresses, location) => {
|
|
try {
|
|
if (addresses.length && location) {
|
|
const address = addresses[0];
|
|
|
|
const R = 6371; // Radius of the earth in km
|
|
const dLat = deg2rad(address.location.coordinates[1] - location.coordinates[1]); // deg2rad below
|
|
const dLon = deg2rad(address.location.coordinates[0] - location.coordinates[0]);
|
|
const a =
|
|
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
|
Math.cos(deg2rad(address.location.coordinates[1])) *
|
|
Math.cos(deg2rad(location.coordinates[1])) *
|
|
Math.sin(dLon / 2) *
|
|
Math.sin(dLon / 2);
|
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
// Distance in km
|
|
return R * c;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} catch (error) {
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
const _computeShippingCostByRoad = async (addresses, storeLocation) => {
|
|
try {
|
|
if (addresses.length && storeLocation) {
|
|
const address = addresses.find((item2) => item2.used === true);
|
|
const lng = address.location.coordinates[0];
|
|
const lat = address.location.coordinates[1];
|
|
|
|
const storeLng = storeLocation.coordinates[0];
|
|
const storeLat = storeLocation.coordinates[1];
|
|
|
|
const getDistance = await axios.get(`https://map.ir/routes/route/v1/driving/${lng},${lat};${storeLng},${storeLat}`, {
|
|
headers: {
|
|
"x-api-key": apiKey,
|
|
},
|
|
});
|
|
|
|
if (getDistance.data.code !== "Ok") return new Error(_sr["fa"].response.unknownError);
|
|
|
|
//@todo if distance under 1000 meter equal to 0
|
|
return getDistance.data.routes[0].distance <= 1000 ? 0 : Math.round(getDistance.data.routes[0].distance / 1000);
|
|
} else {
|
|
return 0;
|
|
}
|
|
} catch (error) {
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
const getMinutes = (str) => {
|
|
var time = str.split(":");
|
|
return time[0] * 60 + time[1] * 1;
|
|
};
|
|
|
|
const getMinutesNow = (timezone) => {
|
|
var timeNow = new Date();
|
|
return timeNow.getUTCHours() * 60 + timeNow.getUTCMinutes();
|
|
};
|
|
|
|
const _computeHavePointPrice = async (items) => {
|
|
try {
|
|
let total = 0;
|
|
for (const item of items) {
|
|
if (item.havePoint) {
|
|
let priceItem = item.price - (item.price * item.static_discount || 0 / 100);
|
|
let totalPrice = priceItem * item.quantity;
|
|
total += totalPrice;
|
|
}
|
|
}
|
|
|
|
return total;
|
|
} catch (error) {
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////public
|
|
////////////////////////////////////// cart
|
|
module.exports.addToCart = [
|
|
//// check start time and end time
|
|
// async (req, res, next) => {
|
|
// try {
|
|
// const getTime = await StoreInfo.findOne()
|
|
//
|
|
// if (getTime) {
|
|
// if (getTime?.open24){
|
|
// return next()
|
|
// } else if (getTime?.utcStartTime && getTime?.utcEndTime) {
|
|
// let start = getMinutes(getTime.utcStartTime)
|
|
// let end = getMinutes(getTime.utcEndTime)
|
|
// let now = getMinutesNow(getTime.timezone)
|
|
//
|
|
// if (
|
|
// (start < now && end > now) || (start > end && (now < end || now > start))
|
|
// ) {
|
|
// return next()
|
|
// } else if (start === end) {
|
|
// return res.status(503).json({message: `در حال حاظر پذیرش سفارش نداریم`})
|
|
// }else {
|
|
// return res.status(503).json({message: `پذیرش سفارش از ساعت ${getTime?.startTime} تا ${getTime?.endTime} می باشد`})
|
|
// }
|
|
//
|
|
// } else {
|
|
// return next()
|
|
// }
|
|
// } else {
|
|
// return next()
|
|
// }
|
|
//
|
|
// } catch (error) {
|
|
// return res500(res, _sr['fa'].response.unknownError)
|
|
// }
|
|
// },
|
|
[
|
|
body("product_id").custom((value, { req }) => {
|
|
return Food.findById(value)
|
|
.then((product) => {
|
|
if (product) return true;
|
|
else return Promise.reject(_sr["fa"].not_found.item_id);
|
|
})
|
|
.catch((err) => {
|
|
return Promise.reject(_sr["fa"].not_found.item_id);
|
|
});
|
|
}),
|
|
body("type").notEmpty().withMessage(`نوع عملی که باید انجام شود را بفرستید`),
|
|
|
|
body("branchId")
|
|
.notEmpty()
|
|
.withMessage(_sr["fa"].required.field)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
return StoreInfo.findOne({ _id: value }).then((store) => {
|
|
if (!store) return Promise.reject(_sr["fa"].not_found.item_id);
|
|
else return true;
|
|
});
|
|
}),
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const { product_id, type, branchId } = req.body;
|
|
const checkCart = await CartItem.findOne({ branchId, product_id, user_id: req.user._id }).populate("product_id");
|
|
|
|
if (checkCart) {
|
|
if (Number(checkCart.quantity) > 0) {
|
|
if (type === "positive") {
|
|
checkCart.quantity = Number(checkCart.quantity) + 1;
|
|
} else if (type === "negative") {
|
|
checkCart.quantity = Number(checkCart.quantity) - 1;
|
|
}
|
|
await checkCart.save();
|
|
|
|
if (Number(checkCart.quantity) === 0 || checkCart.product_id.stock === 0) {
|
|
await checkCart.deleteOne();
|
|
}
|
|
}
|
|
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
} else {
|
|
const addCart = await CartItem.create({
|
|
branchId,
|
|
product_id,
|
|
user_id: req.user._id,
|
|
quantity: 1,
|
|
});
|
|
|
|
if (!addCart) return res500(res, _sr["fa"].response.unknownError);
|
|
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
}
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.getCartItems = [
|
|
async (req, res) => {
|
|
try {
|
|
const branchId = req?.params?.branchId;
|
|
|
|
const allCartItems = await CartItem.find({ branchId, user_id: req.user._id })
|
|
.populate({
|
|
path: "user_id",
|
|
select: "-password -token",
|
|
sort: { useRate: -1 },
|
|
})
|
|
.populate("product_id");
|
|
|
|
return res.json(allCartItems);
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.updateCart = [
|
|
[
|
|
body("quantity")
|
|
.notEmpty()
|
|
.withMessage((value, { req }) => {
|
|
return _sr["fa"].required.quantity;
|
|
})
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage((value, { req }) => {
|
|
return _sr["fa"].format.number;
|
|
}),
|
|
],
|
|
checkValidations(validationResult),
|
|
(req, res) => {
|
|
CartItem.findById(req.params.item_id)
|
|
.then((item) => {
|
|
if (!item) return res404(res, _sr["fa"].not_found.item_id);
|
|
item.quantity = Number(req.body.quantity);
|
|
item.save();
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
})
|
|
.catch((err) => {
|
|
return res404(res, err);
|
|
});
|
|
},
|
|
];
|
|
|
|
module.exports.deleteAllCartItem = [
|
|
(req, res) => {
|
|
CartItem.deleteMany({ user_id: req.user._id }, (err, result) => {
|
|
if (err) return res500(res, _sr["fa"].response.unknownError);
|
|
else return res.json({ message: _sr["fa"].response.success_remove });
|
|
});
|
|
},
|
|
];
|
|
|
|
/////////////////////////////////// reorder
|
|
module.exports.reOrder = [
|
|
//////////////////// validation step
|
|
// (req, res, next) => {
|
|
// CartItem.find({user_id: req.user._id})
|
|
// .then(items => {
|
|
// // check if cart is not empty
|
|
// if (items.length) {
|
|
// // check product stock
|
|
// let outOfRun = []
|
|
// items.forEach(async (item, index) => {
|
|
// await Food.findById(item.product_id)
|
|
// .then(product => {
|
|
// if (product.stock < item.quantity) {
|
|
// outOfRun.push({
|
|
// product_id: product._id,
|
|
// category_id: product.category,
|
|
// stock: product.stock
|
|
// })
|
|
// item.remove()
|
|
// }
|
|
// if (index + 1 === items.length) {
|
|
// if (!outOfRun.length) return next()
|
|
// else return res.status(422).json(outOfRun)
|
|
// }
|
|
// })
|
|
// })
|
|
// } else {
|
|
// return res.status(404).json({message: _sr['fa'].response.cart_empty})
|
|
// }
|
|
// })
|
|
// },
|
|
async (req, res) => {
|
|
try {
|
|
const orderId = req.params?.orderId;
|
|
const checkOrder = await Order.findOne({ status: "delivered", user_id: req.user._id, _id: orderId }).populate("product_id");
|
|
|
|
if (!checkOrder) return res404(res, `سفارش کاربر یافت نشد`);
|
|
|
|
await CartItem.deleteMany({ user_id: req.user._id });
|
|
|
|
for (const food of checkOrder.order_items) {
|
|
if (food.product_id && !food.product_id?.deleted) {
|
|
await CartItem.create({
|
|
product_id: food.product_id._id,
|
|
user_id: req.user._id,
|
|
quantity: food.quantity,
|
|
});
|
|
}
|
|
}
|
|
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
////////////////////////////////////// order
|
|
module.exports.addOrder = [
|
|
[
|
|
body("description").optional().isString().withMessage(`توضیحات سفارش باید به صورت رشته فرستاده شود`),
|
|
|
|
body("bag").optional().isBoolean().withMessage(_sr["fa"].format.boolean),
|
|
|
|
body("score").optional().isBoolean().withMessage(_sr["fa"].format.boolean),
|
|
|
|
body("discountCode")
|
|
.if((value, { req }) => {
|
|
return value;
|
|
})
|
|
.custom((value, { req }) => {
|
|
return DiscountCode.findOne({ discount_code: value })
|
|
.then((discount) => {
|
|
if (!discount) return Promise.reject(`کد تخفیف وارد شده صحیح نمیباشد`);
|
|
if (Number(discount.discount_expire_date) > Date.now()) return Promise.reject(`تاریخ مصرف کد تخفیف به اتمام رشیده است`);
|
|
if (discount.used_by.includes(req?.user?._id)) return Promise.reject(`کد تخفیف قبلا استفاده شده است`);
|
|
if (!discount.isPublic) {
|
|
if (discount?.discount_user_id?.toString() !== req?.user?._id.toString())
|
|
return Promise.reject(`کد تخفیف وارد شده صحیح نمیباشد`);
|
|
} else return true;
|
|
})
|
|
.catch((error) => {
|
|
return Promise.reject(`کد تخفیف وارد شده صحیح نمیباشد`);
|
|
});
|
|
}),
|
|
|
|
body("branchId")
|
|
.notEmpty()
|
|
.withMessage(_sr["fa"].required.field)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
return StoreInfo.findOne({ _id: value }).then((store) => {
|
|
if (!store) return Promise.reject(_sr["fa"].not_found.item_id);
|
|
else return true;
|
|
});
|
|
}),
|
|
],
|
|
checkValidations(validationResult),
|
|
//////////////////// validation step
|
|
(req, res, next) => {
|
|
CartItem.find({ branchId: req?.body?.branchId, user_id: req.user._id }).then((items) => {
|
|
// check if cart is not empty
|
|
if (items.length) {
|
|
// check product stock
|
|
let outOfRun = [];
|
|
items.forEach(async (item, index) => {
|
|
await Food.findById(item.product_id).then((product) => {
|
|
if (product.stock < item.quantity) {
|
|
outOfRun.push({
|
|
name: product.name,
|
|
product_id: product._id,
|
|
category_id: product.category,
|
|
stock: product.stock,
|
|
});
|
|
item.remove();
|
|
}
|
|
if (index + 1 === items.length) {
|
|
if (!outOfRun.length) return next();
|
|
else return res.status(422).json(outOfRun);
|
|
}
|
|
});
|
|
});
|
|
} else {
|
|
return res.status(404).json({ message: _sr["fa"].response.cart_empty });
|
|
}
|
|
});
|
|
},
|
|
//////////////////// save order
|
|
async (req, res) => {
|
|
try {
|
|
const { branchId, description, bag, score, discountCode } = req.body;
|
|
const cartItems = await CartItem.find({ branchId, user_id: req.user._id }).populate("product_id");
|
|
const getUserInfo = await User.findById(req.user._id);
|
|
const getDiscountCode = await DiscountCode.findOne({ branchId, discount_code: discountCode });
|
|
|
|
if (!getUserInfo) return res404(res, `اطلاعات کاربر یافت نشد`);
|
|
|
|
if (!cartItems.length) return res.status(404).json({ message: `هیچ محصولی در سبد خرید شما وجود ندارد` });
|
|
|
|
await Order.deleteMany({ branchId, status: "incomplete", user_id: req.user._id });
|
|
|
|
/// check order exist or not
|
|
// const checkOrder = await Order.findOne({'status': 'incomplete', user_id: req.user._id});
|
|
//
|
|
// if (checkOrder) {
|
|
// await checkOrder.remove()
|
|
// }
|
|
|
|
const orderItems = [];
|
|
for (const item of cartItems) {
|
|
orderItems.push({
|
|
product_id: item.product_id._id,
|
|
name: item.product_id.name,
|
|
quantity: item.quantity,
|
|
price: item.product_id.price,
|
|
static_discount: item.product_id.static_discount,
|
|
havePoint: item.product_id.havePoint,
|
|
});
|
|
}
|
|
|
|
if (score && bag) return res.status(422).json({ message: "استفاده همزمان از کیف پول و امتیاز برای خرید مجاز نمی باشد" });
|
|
|
|
const orderData = {
|
|
branchId,
|
|
user_id: req.user._id,
|
|
number: Date.now(),
|
|
order_items: orderItems,
|
|
statuses: [
|
|
{
|
|
status: "incomplete",
|
|
},
|
|
],
|
|
description,
|
|
bag,
|
|
score,
|
|
discount_code: getDiscountCode?.discount_code,
|
|
discount_amount: getDiscountCode?.discount_amount,
|
|
discount_menuType: getDiscountCode?.menuTypeId,
|
|
};
|
|
await Order.create(orderData);
|
|
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
} catch (error) {
|
|
console.log(error);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.orderPay = [
|
|
[
|
|
body("branchId")
|
|
.notEmpty()
|
|
.withMessage(_sr["fa"].required.field)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
return StoreInfo.findOne({ _id: value }).then((store) => {
|
|
if (!store) return Promise.reject(_sr["fa"].not_found.item_id);
|
|
else return true;
|
|
});
|
|
}),
|
|
],
|
|
checkValidations(validationResult),
|
|
(req, res, next) => {
|
|
CartItem.find({ branchId: req?.body?.branchId, user_id: req.user._id }).then((items) => {
|
|
// check if cart is not empty
|
|
if (items.length) {
|
|
// check product stock
|
|
let outOfRun = [];
|
|
items.forEach(async (item, index) => {
|
|
await Food.findById(item.product_id).then((product) => {
|
|
if (product.stock < item.quantity) {
|
|
outOfRun.push({
|
|
product_id: product._id,
|
|
category_id: product.category,
|
|
stock: product.stock,
|
|
});
|
|
item.remove();
|
|
}
|
|
if (index + 1 === items.length) {
|
|
if (!outOfRun.length) return next();
|
|
else return res.status(422).json(outOfRun);
|
|
}
|
|
});
|
|
});
|
|
} else {
|
|
return res.status(404).json({ message: _sr["fa"].response.cart_empty });
|
|
}
|
|
});
|
|
},
|
|
async (req, res) => {
|
|
try {
|
|
const branchId = req?.body?.branchId;
|
|
const cartItems = await CartItem.find({ branchId, user_id: req.user._id }).populate("product_id");
|
|
const checkOrder = await Order.findOne({ branchId, status: "incomplete", user_id: req.user._id });
|
|
const getUserInfo = await User.findById(req.user._id);
|
|
const getStoreInfo = await StoreInfo.findOne({ _id: branchId });
|
|
|
|
if (!checkOrder) return res404(res, "لطفا از مرحله سبد خرید دوباره ادامه دهید");
|
|
|
|
let pricePoint = Math.floor(getStoreInfo?.priceForChange / getStoreInfo?.pointForChange) || 0;
|
|
let totalPricePoint = getStoreInfo?.totalPricePoint || 0;
|
|
let pointForBuy = getStoreInfo?.pointForBuy || 0;
|
|
|
|
let discount_percent = checkOrder?.discount_amount || 0;
|
|
let discount_menuType = checkOrder?.discount_menuType;
|
|
let specialDiscountMenuType = false;
|
|
let routePrice = 0;
|
|
let sum = 0;
|
|
let sumFoodByPercent = 0;
|
|
let sumFoodByPercentForDiscount = 0;
|
|
let total = 0;
|
|
let firstTotal = 0;
|
|
let percent = 0;
|
|
let tax = 0;
|
|
|
|
if (!getUserInfo) return res404(res, `اطلاعات کاربر یافت نشد`);
|
|
|
|
if (!cartItems.length) return res.status(404).json({ message: `هیچ محصولی در سبد خرید شما وجود ندارد` });
|
|
|
|
const orderItems = [];
|
|
for (const item of cartItems) {
|
|
orderItems.push({
|
|
product_id: item.product_id._id,
|
|
name: item.product_id.name,
|
|
quantity: item.quantity,
|
|
price: item.product_id.price,
|
|
static_discount: item.product_id.static_discount,
|
|
havePoint: item.product_id.havePoint,
|
|
});
|
|
|
|
const itemPercent = (item.product_id.price * item.product_id.static_discount) / 100;
|
|
const sumPercent = itemPercent * item.quantity;
|
|
const price = item.product_id.price;
|
|
const sumPriceItem = price * item.quantity;
|
|
|
|
let sumByPercentForDiscount = sumPriceItem - sumPercent;
|
|
|
|
if (Boolean(discount_percent) && discount_menuType) {
|
|
specialDiscountMenuType = true;
|
|
if (item?.product_id?.category.type?.toString() === discount_menuType?.toString()) {
|
|
sumFoodByPercentForDiscount += sumByPercentForDiscount;
|
|
}
|
|
}
|
|
|
|
sum = sum + sumPriceItem; /// sum food price without percent
|
|
percent = percent + sumPercent; /// sum all food percent
|
|
}
|
|
|
|
/// sum food price with percent
|
|
sumFoodByPercent = sum - percent;
|
|
|
|
/// compute shipping cost
|
|
if (getStoreInfo) {
|
|
if (getStoreInfo?.shippingType) {
|
|
routePrice = getStoreInfo?.shippingCost || 0;
|
|
} else {
|
|
routePrice =
|
|
(await _computeShippingCostByRoad(getUserInfo?.addresses, getStoreInfo?.location)) * (getStoreInfo?.shippingCost || 0) || 0;
|
|
}
|
|
|
|
/// compute tax of order
|
|
if (getStoreInfo?.tax) {
|
|
tax = (sumFoodByPercent * 9) / 100;
|
|
}
|
|
}
|
|
|
|
/// compute discount code
|
|
if (Boolean(discount_percent)) {
|
|
let discountPercent = ((specialDiscountMenuType ? sumFoodByPercentForDiscount : sumFoodByPercent) * discount_percent) / 100;
|
|
percent = percent + discountPercent;
|
|
/// compute sum food with discount percent
|
|
sumFoodByPercent = sumFoodByPercent - discountPercent;
|
|
}
|
|
|
|
/// compute total of order
|
|
total = sumFoodByPercent + tax + routePrice;
|
|
|
|
checkOrder.order_items = orderItems;
|
|
checkOrder.createdOn = Date.now();
|
|
checkOrder.address = getUserInfo.addresses.find((item) => item.used);
|
|
checkOrder.sum = Math.ceil(sum);
|
|
checkOrder.routePrice = Math.ceil(routePrice);
|
|
checkOrder.tax = Math.ceil(tax);
|
|
checkOrder.percent = Math.ceil(percent);
|
|
checkOrder.total = Math.ceil(total);
|
|
checkOrder.pricePoint = pricePoint;
|
|
firstTotal = Math.ceil(total);
|
|
|
|
if (checkOrder.bag) {
|
|
const payPrice = total - getUserInfo?.bagAmount;
|
|
total = payPrice <= 0 ? 0 : payPrice;
|
|
}
|
|
|
|
if (checkOrder.score && pricePoint > 0) {
|
|
const payScore = total - getUserInfo?.score * pricePoint;
|
|
total = payScore <= 0 ? 0 : payScore;
|
|
}
|
|
|
|
checkOrder.payTotal = Math.ceil(total);
|
|
|
|
console.log("total", total);
|
|
console.log("payTotal", checkOrder?.payTotal);
|
|
|
|
/// if total pay is zero dont move to pay method
|
|
if (checkOrder?.payTotal <= 0) {
|
|
/// if bag true use the bagAmount of user
|
|
if (checkOrder?.bag) {
|
|
getUserInfo.bagAmount -= firstTotal;
|
|
|
|
// add point for user only for available product
|
|
const computeAvaPro = await _computeHavePointPrice(checkOrder.order_items);
|
|
/// add score for order
|
|
if (computeAvaPro >= totalPricePoint && totalPricePoint > 0) {
|
|
const point = Math.floor(computeAvaPro / totalPricePoint) * pointForBuy;
|
|
|
|
if (point > 0) {
|
|
getUserInfo.score = getUserInfo.score + point;
|
|
getUserInfo.scoreLogs = [
|
|
{
|
|
score: point,
|
|
order_id: getUserInfo._id,
|
|
forWhat: "buy",
|
|
action: "increase",
|
|
},
|
|
];
|
|
}
|
|
}
|
|
await getUserInfo.save();
|
|
|
|
if (Boolean(discount_percent)) {
|
|
const updateDiscount = await DiscountCode.findOne({ discount_code: checkOrder.discount_code });
|
|
|
|
if (!updateDiscount || Number(updateDiscount.discount_expire_date) > Date.now())
|
|
return res.status(403).json({ message: "مشکلی در پرداخت و ثبت سفارش پیش آمده است لطفا با پشتیبانی تماس بگیرید" });
|
|
|
|
updateDiscount.used_by.push(getUserInfo._id);
|
|
await updateDiscount.save();
|
|
}
|
|
|
|
const addPayment = await Payment.create({
|
|
user_id: getUserInfo._id,
|
|
order_id: checkOrder._id,
|
|
transactionId: Date.now(),
|
|
refId: Date.now(),
|
|
getPayment: true,
|
|
action: "decreaseBag",
|
|
status: "paid",
|
|
cost: firstTotal,
|
|
});
|
|
|
|
checkOrder.payment.push(addPayment._id);
|
|
checkOrder.bagCost = firstTotal;
|
|
} /// it was ok!
|
|
|
|
/// if score true use the score of user
|
|
if (checkOrder?.score && pricePoint > 0) {
|
|
const point = Math.ceil(firstTotal / pricePoint);
|
|
checkOrder.scoreCost = point * pricePoint;
|
|
checkOrder.scorePoint = point;
|
|
getUserInfo.score -= point;
|
|
getUserInfo.scoreLogs = [
|
|
{
|
|
score: point,
|
|
order_id: checkOrder._id,
|
|
forWhat: "buy",
|
|
action: "decrease",
|
|
},
|
|
];
|
|
|
|
await getUserInfo.save();
|
|
}
|
|
|
|
checkOrder.statuses.push({
|
|
status: "processing",
|
|
});
|
|
checkOrder.status = "processing";
|
|
checkOrder.paymentStatus = "paid";
|
|
await checkOrder.save();
|
|
|
|
for (const food of checkOrder.order_items) {
|
|
const getFood = await Food.findById(food.product_id);
|
|
|
|
if (getFood) {
|
|
getFood.stock = getFood.stock - food.quantity;
|
|
// getFood.canReview.push(req.user._id)///add user id for review
|
|
getFood.save();
|
|
}
|
|
}
|
|
|
|
/// remove cart item
|
|
await CartItem.deleteMany({ user_id: getUserInfo._id });
|
|
|
|
//----------------------- send notif for admins -----------------
|
|
const fcmTokens = [];
|
|
const allAdmins = await User.find({ scope: "admin" });
|
|
for (const admin of allAdmins) {
|
|
if (admin.fcmToken) fcmTokens.push(admin.fcmToken);
|
|
}
|
|
const objNotif = {
|
|
title: "سفارش جدید!",
|
|
body: "یک سفارش جدید در پنل برگ من ثبت گردید",
|
|
};
|
|
const payload = {
|
|
notification: objNotif,
|
|
};
|
|
const input = {
|
|
registrationTokens: fcmTokens,
|
|
payload,
|
|
};
|
|
await sendMulti(input);
|
|
|
|
sendNotifyOrder(checkOrder?.branchId);
|
|
//----------------------------------------------------------------
|
|
|
|
//--------------------- send notif to user --------------------------
|
|
const messageUser = {
|
|
title: "ثبت سفارش",
|
|
body: "با تشکر از اعتماد شما سفارش شما با موفقیت ثبت شد",
|
|
};
|
|
const payloadUser = {
|
|
notification: messageUser,
|
|
};
|
|
const inputUser = {
|
|
registrationTokens: getUserInfo.fcmToken,
|
|
payload: payloadUser,
|
|
};
|
|
await sendSingle(inputUser);
|
|
//-------------------------------------------------------------------
|
|
|
|
//------------------------------- send sms --------------------------
|
|
const smsTemplate = `سفارش شما با موفقیت ثبت شد با تشکر از اعتماد شما برگ من لغو11`;
|
|
|
|
const smsResult = await sms(getUserInfo.mobile_number, smsTemplate);
|
|
|
|
if (!smsResult) {
|
|
return res500(res, `مشکلی در ارسال پیامک پیش آمده است`);
|
|
}
|
|
//-------------------------------------------------------------------
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
}
|
|
|
|
const request = await zarinpal.request(checkOrder?.payTotal, checkOrder?.number?.toString(), req.user);
|
|
|
|
if (!request.status) {
|
|
console.log(request);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
|
|
// add payment to order
|
|
const addPayment = await Payment.create({
|
|
user_id: getUserInfo._id,
|
|
order_id: checkOrder._id,
|
|
transactionId: request.response.authority,
|
|
cost: checkOrder.payTotal,
|
|
});
|
|
|
|
if (addPayment) {
|
|
checkOrder.payment = addPayment._id;
|
|
await checkOrder.save();
|
|
} else {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
|
|
/// remove cart item
|
|
await CartItem.deleteMany({ branchId, user_id: req.user._id });
|
|
|
|
return res.json({ paymentUrl: `${zarinUrl}/${request.response.authority}` });
|
|
} catch (error) {
|
|
console.log(error.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.getPaymentResponse = [
|
|
async (req, res) => {
|
|
try {
|
|
const checkPayment = await Payment.findOne({ transactionId: req?.query?.Authority }).populate("order_id");
|
|
|
|
const user = await User.findById(checkPayment.user_id);
|
|
|
|
///check duplicate transaction
|
|
if (!checkPayment || checkPayment.getPayment || checkPayment.action === "decreaseBag") {
|
|
return res.json({
|
|
status: false,
|
|
fromWhere: user?.fromWhere || "app",
|
|
message: "پرداخت ناموفق بود",
|
|
});
|
|
}
|
|
|
|
/// verify transaction
|
|
const verify = await zarinpal.verify(
|
|
checkPayment.action === "increaseBag" ? checkPayment.cost : checkPayment.order_id.payTotal,
|
|
checkPayment.transactionId,
|
|
);
|
|
|
|
console.log(verify);
|
|
|
|
if (verify.status) {
|
|
if (verify.code === 101) {
|
|
console.log(verify);
|
|
return res.json({
|
|
status: false,
|
|
message: "پرداخت ناموفق بود",
|
|
});
|
|
}
|
|
|
|
checkPayment.status = "paid";
|
|
checkPayment.refId = verify?.response?.ref_id;
|
|
checkPayment.getPayment = true;
|
|
checkPayment.fee_type = verify?.response?.fee_type;
|
|
checkPayment.card_hash = verify?.response?.card_hash;
|
|
checkPayment.card_pan = verify?.response?.card_pan;
|
|
checkPayment.fee = verify?.response?.fee;
|
|
checkPayment.created_at = Date.now();
|
|
checkPayment.createdOn = Date.now();
|
|
|
|
await checkPayment.save();
|
|
|
|
/// only for buy food execute this action
|
|
if (checkPayment.action === "payOrder") {
|
|
const getOrder = await Order.findById(checkPayment.order_id._id);
|
|
|
|
if (!getOrder) return res404(res, "سفارش پیدا نشد");
|
|
|
|
for (const food of getOrder.order_items) {
|
|
const getFood = await Food.findById(food.product_id);
|
|
|
|
if (getFood) {
|
|
getFood.stock = getFood.stock - food.quantity;
|
|
// getFood.canReview.push(req.user._id)///add user id for review
|
|
getFood.save();
|
|
}
|
|
}
|
|
|
|
if (getOrder.discount_code) {
|
|
const discount = await DiscountCode.findOne({ discount_code: getOrder.discount_code });
|
|
|
|
if (discount) {
|
|
discount.used_by.push(getOrder.user_id);
|
|
|
|
await discount.save();
|
|
}
|
|
}
|
|
|
|
if (user) {
|
|
/// decrease score
|
|
if (getOrder?.score) {
|
|
getOrder.scorePoint = user.score;
|
|
getOrder.scoreCost = user.score * getOrder?.pricePoint;
|
|
user.scoreLogs = [
|
|
{
|
|
score: user.score,
|
|
order_id: getOrder._id,
|
|
forWhat: "buy",
|
|
action: "decrease",
|
|
},
|
|
];
|
|
user.score = 0;
|
|
await user.save();
|
|
}
|
|
|
|
/// decrease bag
|
|
if (getOrder.bag) {
|
|
const addPayment = await Payment.create({
|
|
user_id: user._id,
|
|
order_id: getOrder._id,
|
|
transactionId: Date.now(),
|
|
refId: Date.now(),
|
|
getPayment: true,
|
|
action: "decreaseBag",
|
|
status: "paid",
|
|
cost: user.bagAmount,
|
|
});
|
|
getOrder.payment.push(addPayment._id);
|
|
getOrder.bagCost = user.bagAmount;
|
|
user.bagAmount = 0;
|
|
await user.save();
|
|
}
|
|
|
|
if (!getOrder.score || !getOrder?.discount_code) {
|
|
// add point for user only for available product
|
|
const computeAvaPro = await _computeHavePointPrice(getOrder?.order_items);
|
|
|
|
/// add score for order
|
|
if (computeAvaPro >= getOrder?.totalPricePoint && getOrder?.totalPricePoint > 0) {
|
|
const point = Math.floor(computeAvaPro / getOrder?.totalPricePoint) * getOrder?.pointForBuy;
|
|
|
|
if (point > 0) {
|
|
user.score = user.score + point;
|
|
user.scoreLogs = [
|
|
{
|
|
score: point,
|
|
order_id: getOrder._id,
|
|
forWhat: "buy",
|
|
action: "increase",
|
|
},
|
|
];
|
|
await user.save();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
getOrder.statuses.push({
|
|
status: "processing",
|
|
});
|
|
getOrder.status = "processing";
|
|
getOrder.paymentStatus = "paid";
|
|
|
|
await getOrder.save();
|
|
|
|
//----------------------- send notif for admins -----------------
|
|
const fcmTokens = [];
|
|
const allAdmins = await User.find({ scope: "admin" });
|
|
for (const admin of allAdmins) {
|
|
if (admin.fcmToken) fcmTokens.push(admin.fcmToken);
|
|
}
|
|
const objNotif = {
|
|
title: "سفارش جدید!",
|
|
body: "یک سفارش جدید در پنل برگ من ثبت گردید",
|
|
};
|
|
const payload = {
|
|
notification: objNotif,
|
|
};
|
|
const input = {
|
|
registrationTokens: fcmTokens,
|
|
payload,
|
|
};
|
|
await sendMulti(input);
|
|
|
|
sendNotifyOrder(getOrder?.branchId);
|
|
//----------------------------------------------------------------
|
|
|
|
//--------------------- send notif to user --------------------------
|
|
const messageUser = {
|
|
title: "ثبت سفارش",
|
|
body: "با تشکر از اعتماد شما سفارش شما با موفقیت ثبت شد",
|
|
};
|
|
const payloadUser = {
|
|
notification: messageUser,
|
|
};
|
|
const inputUser = {
|
|
registrationTokens: user.fcmToken,
|
|
payload: payloadUser,
|
|
};
|
|
await sendSingle(inputUser);
|
|
//-------------------------------------------------------------------
|
|
|
|
//------------------------------- send sms --------------------------
|
|
const smsTemplate = `سفارش شما با موفقیت ثبت شد با تشکر از اعتماد شما برگ من لغو11`;
|
|
|
|
const smsResult = await sms(user.mobile_number, smsTemplate);
|
|
|
|
if (!smsResult) {
|
|
return res500(res, `مشکلی در ارسال پیامک پیش آمده است`);
|
|
}
|
|
//-------------------------------------------------------------------
|
|
} else if (checkPayment.action === "increaseBag") {
|
|
if (!user)
|
|
return res.json({
|
|
status: false,
|
|
message: "مشکلی در افزایش موجودی کیف پول شما پیش آمده است لطفا با پشتیبانی تماس بگیرید",
|
|
});
|
|
|
|
user.bagAmount = user.bagAmount + checkPayment?.cost;
|
|
|
|
await user.save();
|
|
//--------------------- send notif to user --------------------------
|
|
const messageUser = {
|
|
title: "افزایش موجودی",
|
|
body: "با تشکر از اعتماد شما کیف پول شما با موفقیت شارژ شد برگ من",
|
|
};
|
|
const payloadUser = {
|
|
notification: messageUser,
|
|
};
|
|
const inputUser = {
|
|
registrationTokens: user.fcmToken,
|
|
payload: payloadUser,
|
|
};
|
|
await sendSingle(inputUser);
|
|
//-------------------------------------------------------------------
|
|
|
|
//------------------------------- send sms --------------------------
|
|
const smsTemplate = `با تشکر از اعتماد شما کیف پول شما با موفقیت شارژ شد برگ من لغو11`;
|
|
|
|
const smsResult = await sms(user.mobile_number, smsTemplate);
|
|
|
|
if (!smsResult) {
|
|
return res500(res, `مشکلی در ارسال پیامک پیش آمده است`);
|
|
}
|
|
//-------------------------------------------------------------------
|
|
}
|
|
|
|
return res.json({
|
|
status: true,
|
|
refId: verify?.response?.ref_id,
|
|
fromWhere: user?.fromWhere || "app",
|
|
message: "پرداخت با موفقیت انجام شد",
|
|
});
|
|
} else {
|
|
/// only for buy food execute this action
|
|
if (checkPayment.action === "payOrder") {
|
|
let getOrder = await Order.findById(checkPayment.order_id._id);
|
|
|
|
if (getOrder) {
|
|
getOrder.statuses.push({
|
|
status: "void",
|
|
});
|
|
getOrder.status = "void";
|
|
getOrder.paymentStatus = "unpaid";
|
|
|
|
await getOrder.save();
|
|
}
|
|
|
|
checkPayment.getPayment = true;
|
|
checkPayment.created_at = new Date();
|
|
await checkPayment.save();
|
|
}
|
|
|
|
return res.json({
|
|
status: false,
|
|
fromWhere: user?.fromWhere || "app",
|
|
message: "پرداخت ناموفق بود",
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.log(error.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.addAddressToOrder = [
|
|
(req, res) => {
|
|
Order.findById(req.params.order_id)
|
|
.then((order) => {
|
|
if (!order.address) {
|
|
User.findOne({ "addresses._id": req.body.address_id })
|
|
.then((user) => {
|
|
order.address = user.addresses.id(req.body.address_id);
|
|
// add processing status to order
|
|
order.statuses.push({
|
|
status: "processing",
|
|
});
|
|
order.save();
|
|
return res.json(order);
|
|
})
|
|
.catch((err) => {
|
|
return res500(res, err);
|
|
});
|
|
} else {
|
|
return res.status(500).json({ message: v_m[req.body.locale].response.already_has_address });
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
return res404(res, err);
|
|
});
|
|
},
|
|
];
|
|
|
|
module.exports.addStatusToOrder = [
|
|
async (req, res) => {
|
|
try {
|
|
const order = await Order.findById(req.params.order_id).populate("user_id");
|
|
|
|
if (!order) return res404(res, "سفارش مورد نظر یافت نشد");
|
|
|
|
order.statuses.push({
|
|
status: req.body.status,
|
|
});
|
|
order.status = req.body.status;
|
|
order.save();
|
|
|
|
if (req.body.status === "delivered") {
|
|
//--------------------- send notif to user --------------------------
|
|
const messageUser = {
|
|
title: "ارسال سفارش",
|
|
body: "سفارش شما ارسال گردید با تشکر برگ من",
|
|
};
|
|
const payloadUser = {
|
|
notification: messageUser,
|
|
};
|
|
const inputUser = {
|
|
registrationTokens: order?.user_id?.fcmToken,
|
|
payload: payloadUser,
|
|
};
|
|
await sendSingle(inputUser);
|
|
//-------------------------------------------------------------------
|
|
|
|
setTimeout(async () => {
|
|
let smsTemplate = "";
|
|
if (order.user_id.fromWhere === "app")
|
|
smsTemplate = `لطفا با ثبت نظر برای سفارش خود به ما برای خدمات بهتر کمک کنید با تشکر برگ من`;
|
|
else
|
|
smsTemplate = `لطفا با ثبت نظر برای سفارش خود به ما برای خدمات بهتر کمک کنید با تشکر برگ من لغو11
|
|
لینک : https://app.bargrestaurant.com/rate/${req.params.order_id}`;
|
|
const smsResult = await sms(order?.user_id?.mobile_number, smsTemplate);
|
|
|
|
//--------------------- send notif to user --------------------------
|
|
const messageUser = {
|
|
title: "ثبت نظر",
|
|
body: "لطفا با ثبت نظر برای سفارش خود به ما برای خدمات بهتر کمک کنید با تشکر",
|
|
};
|
|
const payloadUser = {
|
|
notification: messageUser,
|
|
};
|
|
const inputUser = {
|
|
registrationTokens: order?.user_id?.fcmToken,
|
|
payload: payloadUser,
|
|
};
|
|
await sendSingle(inputUser);
|
|
//-------------------------------------------------------------------
|
|
|
|
if (!smsResult) {
|
|
console.log("order sms", smsResult);
|
|
}
|
|
}, timeToStart);
|
|
}
|
|
return res.json(order);
|
|
} catch (error) {
|
|
console.log(error.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.changePayStatus = [
|
|
[
|
|
body("status")
|
|
.notEmpty()
|
|
.withMessage(_sr["fa"].required.field)
|
|
.bail()
|
|
.isIn(["refund", "unpaid", "paid"])
|
|
.withMessage("وضعیت ارسال شده صحیح نمی باشد"),
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const targetOrder = await Order.findById(req.params.id);
|
|
|
|
if (!targetOrder) return res404(res, "سفارش مورد نظر پیدا نشد");
|
|
|
|
const targetPayment = await Payment.findById(targetOrder.payment);
|
|
|
|
if (targetPayment) {
|
|
targetPayment.status = req.body.status;
|
|
await targetPayment.save();
|
|
}
|
|
|
|
targetOrder.paymentStatus = req.body.status;
|
|
await targetOrder.save();
|
|
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.getOrders = [
|
|
(req, res) => {
|
|
const branchId = req?.params?.branchId;
|
|
Order.find({
|
|
branchId,
|
|
user_id: req.user._id,
|
|
status: { $in: ["canceled", "processing", "sent", "delivered"] },
|
|
paymentStatus: "paid",
|
|
})
|
|
.populate({
|
|
path: "order_items.product_id",
|
|
select: "name canReview ratings",
|
|
})
|
|
.sort({ _id: -1 })
|
|
.then((orders) => {
|
|
const allOrders = [];
|
|
|
|
for (const item of orders) {
|
|
let clone = JSON.parse(JSON.stringify(item.order_items));
|
|
|
|
clone.map((food) => {
|
|
// food.review = food?.product_id?.canReview?.includes(req.user._id.toString())
|
|
// food.rating = food?.product_id?.ratings?.find(rate => rate.user_id.toString() === req.user._id.toString() && rate?.order_id?.toString() === item?._id?.toString())?.rate || 0
|
|
food.rating = food?.product_id?.ratings?.find((rate) => rate?.user_id?.toString() === req?.user?._id.toString())?.rate || 0;
|
|
});
|
|
|
|
allOrders.push({
|
|
_id: item._id,
|
|
address: item.address,
|
|
status: item.status,
|
|
items: clone,
|
|
orderType: item.orderType,
|
|
review: item.rating.rate,
|
|
created_at: item.createdOn,
|
|
total: item.total,
|
|
});
|
|
}
|
|
|
|
return res.json(allOrders);
|
|
})
|
|
.catch((err) => {
|
|
console.log(err.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
});
|
|
},
|
|
];
|
|
|
|
module.exports.getOrdersForReport = [
|
|
async (req, res) => {
|
|
try {
|
|
const branchId = req?.params?.branchId;
|
|
const orders = await Order.find({
|
|
branchId,
|
|
status: { $in: ["canceled", "processing", "sent", "delivered"] },
|
|
paymentStatus: "paid",
|
|
});
|
|
return res.json(orders);
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.getOneOrderByUser = [
|
|
async (req, res) => {
|
|
try {
|
|
const targetOrder = await Order.findOne({ _id: req.params.id, user_id: req.user._id }).select("status");
|
|
|
|
if (!targetOrder) return res404(res, "سفارش مورد نظر پیدا نشد");
|
|
|
|
return res.json(targetOrder);
|
|
} catch (error) {
|
|
console.log("get one order by user |", error.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.deleteOrder = [
|
|
async (req, res) => {
|
|
try {
|
|
const targetOrder = await Order.findById(req.params.id);
|
|
|
|
if (!targetOrder) return res404(res, "سفارش مورد نظر پیدا نشد");
|
|
|
|
/// @todo maybe delete payment too
|
|
|
|
await targetOrder.deleteOne();
|
|
|
|
return res.json({ message: _sr["fa"].response.success_remove });
|
|
} catch (error) {
|
|
console.log("delete order: ", error.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.increaseBag = [
|
|
[body("price").notEmpty().withMessage(`لطفا یک مقدار مشخص کنید`)],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const cost = req.body.price;
|
|
const user = await User.findById(req.user._id);
|
|
|
|
if (!user) return res404(res, `اطلاعات کاربر پیدا نشد`);
|
|
|
|
const request = await zarinpal.request(cost, "کیف پول", req.user);
|
|
|
|
if (!request.status) {
|
|
console.log(request);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
|
|
// add payment to order
|
|
await Payment.create({
|
|
user_id: user._id,
|
|
order_id: null,
|
|
transactionId: request.response.authority,
|
|
cost: cost,
|
|
action: "increaseBag",
|
|
});
|
|
|
|
return res.json({ paymentUrl: `${zarinUrl}/${request.response.authority}` });
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
/////// admin panel
|
|
module.exports.getOneOrder = [
|
|
(req, res) => {
|
|
Order.findById(req.params.id)
|
|
.populate({
|
|
path: "user_id",
|
|
select: "first_name last_name scoreLogs",
|
|
})
|
|
.populate("order_items.product_id")
|
|
.populate("payment")
|
|
.then((order) => {
|
|
return res.json(order);
|
|
})
|
|
.catch((err) => {
|
|
return res404(res, err);
|
|
});
|
|
},
|
|
];
|
|
|
|
module.exports.search = [
|
|
async (req, res) => {
|
|
try {
|
|
let { branchId, number, orderStatus, paymentStatus, userId, date } = req.body;
|
|
|
|
let findQuery = {
|
|
branchId,
|
|
status: { $nin: ["incomplete", "void"] },
|
|
};
|
|
findQuery["$and"] = [];
|
|
findQuery["$or"] = [];
|
|
|
|
/** search by number */
|
|
if (number && !_.isEmpty(number)) {
|
|
findQuery["$and"].push({
|
|
number,
|
|
});
|
|
}
|
|
|
|
/** search by orderStatus */
|
|
if (orderStatus && !_.isEmpty(orderStatus)) {
|
|
findQuery["$and"].push({
|
|
status: {
|
|
$in: orderStatus,
|
|
},
|
|
});
|
|
}
|
|
|
|
/** search by paymentStatus */
|
|
if (paymentStatus && !_.isEmpty(paymentStatus)) {
|
|
findQuery["$and"].push({
|
|
paymentStatus: {
|
|
$in: paymentStatus,
|
|
},
|
|
});
|
|
}
|
|
|
|
/** search by user_id */
|
|
if (userId && !_.isEmpty(userId)) {
|
|
findQuery["$and"].push({
|
|
user_id: userId,
|
|
});
|
|
}
|
|
|
|
/** search by date */
|
|
if (date && !_.isEmpty(date)) {
|
|
if (date.length === 1) {
|
|
findQuery["$and"].push({
|
|
createdOn: {
|
|
$gte: moment(date[0]).startOf("days"),
|
|
$lt: moment(date[0]).endOf("days"),
|
|
},
|
|
});
|
|
} else {
|
|
findQuery["$and"].push({
|
|
createdOn: {
|
|
$gte: new Date(date[0]),
|
|
$lt: new Date(date[1]),
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
_.isEmpty(findQuery["$and"]) && delete findQuery["$and"];
|
|
_.isEmpty(findQuery["$or"]) && delete findQuery["$or"];
|
|
|
|
/** get news */
|
|
const orders = await Order.paginate(findQuery, {
|
|
page: req.query.page,
|
|
limit,
|
|
populate: [{ path: "user_id", select: "first_name last_name" }],
|
|
sort: {
|
|
_id: -1,
|
|
},
|
|
});
|
|
|
|
/** show result */
|
|
return res.json(orders);
|
|
} catch (error) {
|
|
console.log(error.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.reports = [
|
|
// [
|
|
// body('startDate')
|
|
// .notEmpty().withMessage(_sr['fa'].required.date),
|
|
//
|
|
// body('endDate')
|
|
// .notEmpty().withMessage(_sr['fa'].required.date),
|
|
// ],
|
|
// checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const branchId = req?.params?.branchId;
|
|
let findQuery = {
|
|
branchId,
|
|
status: { $nin: ["incomplete", "void"] },
|
|
};
|
|
|
|
let { startDate, endDate } = req.body;
|
|
|
|
// if (!startDate || !endDate){
|
|
// findQuery.createdOn = {
|
|
// createdOn: {
|
|
// $gte: moment().startOf('days'),
|
|
// $lt: moment().endOf('days')
|
|
// }
|
|
// }
|
|
// }else {
|
|
if (startDate && endDate) {
|
|
findQuery.createdOn = {
|
|
$gte: new Date(startDate),
|
|
$lt: new Date(endDate),
|
|
};
|
|
} else if (startDate) {
|
|
findQuery.createdOn = {
|
|
$gte: moment(startDate),
|
|
$lt: new Date(),
|
|
};
|
|
} else if (endDate) {
|
|
findQuery.createdOn = {
|
|
// $gte: '',
|
|
$lt: moment(endDate),
|
|
};
|
|
}
|
|
// }
|
|
|
|
/** search by date */
|
|
// if (startDate || endDate && !_.isEmpty(date)) {
|
|
// if (date.length === 1) {
|
|
// findQuery.createdOn = {
|
|
// $gte: moment(startDate),
|
|
// $lt: moment(startDate)
|
|
// }
|
|
// } else {
|
|
// findQuery.createdOn = {
|
|
// $gte: new Date(date[0]),
|
|
// $lt: new Date(date[1])
|
|
// }
|
|
// }
|
|
// } else {
|
|
//
|
|
// }
|
|
|
|
/** get news */
|
|
const orders = await Order.find(findQuery).populate({ path: "user_id", select: "first_name last_name" }).sort({ _id: -1 });
|
|
|
|
let result = {
|
|
count: orders?.length || 0,
|
|
total:
|
|
orders?.reduce((total, item) => {
|
|
return total + item?.total;
|
|
}, 0) || 0,
|
|
payOnline:
|
|
orders?.reduce((total, item) => {
|
|
return total + item?.payTotal;
|
|
}, 0) || 0,
|
|
routePrice:
|
|
orders?.reduce((total, item) => {
|
|
return total + item?.routePrice;
|
|
}, 0) || 0,
|
|
bagCost:
|
|
orders?.reduce((total, item) => {
|
|
return total + item?.bagCost;
|
|
}, 0) || 0,
|
|
scorePoint:
|
|
orders?.reduce((total, item) => {
|
|
return total + item?.scorePoint;
|
|
}, 0) || 0,
|
|
scoreCost:
|
|
orders?.reduce((total, item) => {
|
|
return total + item?.scoreCost;
|
|
}, 0) || 0,
|
|
};
|
|
|
|
/** show result */
|
|
return res.json(result);
|
|
} catch (error) {
|
|
console.log(error.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
//////////////////////////////////// compute price
|
|
module.exports.computePrice = [
|
|
//////////////////// validation step
|
|
(req, res, next) => {
|
|
const branchId = req?.params?.branchId;
|
|
CartItem.find({ branchId, user_id: req.user._id }).then((items) => {
|
|
// check if cart is not empty
|
|
if (items.length) {
|
|
// check product stock
|
|
let outOfRun = [];
|
|
items.forEach(async (item, index) => {
|
|
await Food.findById(item.product_id).then((product) => {
|
|
if (product.stock < item.quantity) {
|
|
outOfRun.push({
|
|
product_id: product._id,
|
|
category_id: product.category,
|
|
stock: product.stock,
|
|
});
|
|
item.remove();
|
|
}
|
|
if (index + 1 === items.length) {
|
|
if (!outOfRun.length) return next();
|
|
else return res.status(422).json(outOfRun);
|
|
}
|
|
});
|
|
});
|
|
} else {
|
|
return res.status(404).json({ message: _sr["fa"].response.cart_empty });
|
|
}
|
|
});
|
|
},
|
|
async (req, res) => {
|
|
try {
|
|
const branchId = req?.params?.branchId;
|
|
const cartItems = await CartItem.find({ branchId, user_id: req.user._id }).populate({
|
|
path: "product_id",
|
|
populate: {
|
|
path: "category",
|
|
model: "FoodCategory",
|
|
},
|
|
});
|
|
const checkOrder = await Order.findOne({ branchId, status: "incomplete", user_id: req.user._id });
|
|
const getUserInfo = await User.findById(req.user._id);
|
|
const getStoreInfo = await StoreInfo.findOne({ _id: branchId });
|
|
const product = [];
|
|
const userAddress = getUserInfo.addresses.find((item) => item.used === true) || null;
|
|
let specialDiscountMenuType = false;
|
|
let discount_percent = checkOrder?.discount_amount || 0;
|
|
let discount_menuType = checkOrder?.discount_menuType;
|
|
let routePrice = 0;
|
|
let sum = 0;
|
|
let sumFoodByPercent = 0;
|
|
let sumFoodByPercentForDiscount = 0;
|
|
let total = 0;
|
|
let percent = 0;
|
|
let tax = 0;
|
|
|
|
if (!getUserInfo) return res404(res, `اطلاعات کاربر یافت نشد`);
|
|
|
|
if (!cartItems.length) return res.status(404).json({ message: `هیچ محصولی در سبد خرید شما وجود ندارد` });
|
|
|
|
if (checkOrder) {
|
|
const orderItems = [];
|
|
for (const item of cartItems) {
|
|
orderItems.push({
|
|
product_id: item.product_id._id,
|
|
name: item.product_id.name,
|
|
quantity: item.quantity,
|
|
price: item.product_id.price,
|
|
static_discount: item.product_id.static_discount,
|
|
havePoint: item.product_id.havePoint,
|
|
});
|
|
|
|
product.push({
|
|
product: item.product_id,
|
|
quantity: item.quantity,
|
|
});
|
|
|
|
const itemPercent = (item.product_id.price * item.product_id.static_discount) / 100;
|
|
const sumPercent = itemPercent * item.quantity;
|
|
const price = item.product_id.price;
|
|
const sumPriceItem = price * item.quantity;
|
|
|
|
let sumByPercentForDiscount = sumPriceItem - sumPercent;
|
|
|
|
if (Boolean(discount_percent) && discount_menuType) {
|
|
specialDiscountMenuType = true;
|
|
if (item?.product_id?.category.type?.toString() === discount_menuType?.toString()) {
|
|
sumFoodByPercentForDiscount += sumByPercentForDiscount;
|
|
}
|
|
}
|
|
|
|
sum = sum + sumPriceItem; /// sum food price without percent
|
|
percent = percent + sumPercent; /// sum all food percent
|
|
}
|
|
|
|
/// sum food price with percent
|
|
sumFoodByPercent = sum - percent;
|
|
|
|
/// compute shipping cost
|
|
if (getStoreInfo) {
|
|
if (getStoreInfo?.shippingType) {
|
|
routePrice = getStoreInfo?.shippingCost || 0;
|
|
} else {
|
|
routePrice =
|
|
(await _computeShippingCostByRoad(getUserInfo?.addresses, getStoreInfo?.location)) * (getStoreInfo?.shippingCost || 0) || 0;
|
|
}
|
|
|
|
/// compute tax of order
|
|
if (getStoreInfo?.tax) {
|
|
tax = (sumFoodByPercent * 9) / 100;
|
|
}
|
|
}
|
|
|
|
/// compute discount code
|
|
if (Boolean(discount_percent)) {
|
|
let discountPercent = ((specialDiscountMenuType ? sumFoodByPercentForDiscount : sumFoodByPercent) * discount_percent) / 100;
|
|
percent = percent + discountPercent;
|
|
/// compute sum food with discount percent
|
|
sumFoodByPercent = sumFoodByPercent - discountPercent;
|
|
}
|
|
|
|
/// compute total of order
|
|
total = sumFoodByPercent + tax + routePrice;
|
|
|
|
checkOrder.order_items = orderItems;
|
|
checkOrder.createdOn = Date.now();
|
|
checkOrder.sum = Math.ceil(sum);
|
|
checkOrder.routePrice = Math.ceil(routePrice);
|
|
checkOrder.tax = Math.ceil(tax);
|
|
checkOrder.percent = Math.ceil(percent);
|
|
checkOrder.total = Math.ceil(total);
|
|
checkOrder.pricePoint = getStoreInfo?.pricePoint;
|
|
|
|
if (checkOrder.bag) {
|
|
const payPrice = total - getUserInfo?.bagAmount;
|
|
total = payPrice <= 0 ? 0 : payPrice;
|
|
}
|
|
|
|
if (checkOrder.score && getStoreInfo?.pricePoint > 0) {
|
|
const payScore = total - getUserInfo?.score * getStoreInfo?.pricePoint;
|
|
total = payScore <= 0 ? 0 : payScore;
|
|
}
|
|
|
|
checkOrder.payTotal = Math.ceil(total);
|
|
|
|
checkOrder.save();
|
|
}
|
|
|
|
return res.json({
|
|
usePoint: getStoreInfo?.usePointWhenPay,
|
|
product,
|
|
userAddress,
|
|
sum: Math.ceil(sum),
|
|
routePrice: Math.ceil(routePrice),
|
|
tax: Math.ceil(tax),
|
|
percent: Math.ceil(percent),
|
|
total: Math.ceil(checkOrder.payTotal),
|
|
});
|
|
} catch (error) {
|
|
console.log(error.message);
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
////////////////////////////////////// get list of all orders for admin
|
|
module.exports.getAllOrders = [
|
|
async (req, res) => {
|
|
try {
|
|
const branchId = req?.params?.branchId;
|
|
const orders = await Order.paginate(
|
|
{ branchId, status: { $nin: ["incomplete", "void"] } },
|
|
{
|
|
page: req.query.page || 1,
|
|
limit,
|
|
populate: [{ path: "user_id", select: "first_name last_name" }],
|
|
sort: { _id: -1 },
|
|
},
|
|
);
|
|
|
|
return res.json(orders);
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
///////////////////////////////////// get payment list
|
|
module.exports.getAllPaymentByUser = [
|
|
async (req, res) => {
|
|
try {
|
|
const getAll = await Payment.find({ user_id: req.user._id }).sort({ _id: -1 });
|
|
return res.json(getAll);
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.getAllPaymentByAdmin = [
|
|
async (req, res) => {
|
|
try {
|
|
const getAll = await Payment.paginate(
|
|
{ user_id: req.params.id },
|
|
{
|
|
page: req.query.page || 1,
|
|
limit,
|
|
sort: { _id: -1 },
|
|
},
|
|
);
|
|
return res.json(getAll);
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
//////////////////////////////////// get all foods for rates
|
|
module.exports.getAllRateFood = [
|
|
async (req, res) => {
|
|
try {
|
|
const getOrder = await Order.findOne({
|
|
_id: req.params.order_id,
|
|
user_id: req.user._id,
|
|
status: "delivered",
|
|
paymentStatus: "paid",
|
|
}).populate({
|
|
path: "order_items.product_id",
|
|
select: "name ratings",
|
|
});
|
|
|
|
if (!getOrder) return res404(res, `سفارش مورد نظر پیدا نشد`);
|
|
|
|
return res.json(getOrder);
|
|
} catch (e) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
/////////////////////////////////// rate order
|
|
module.exports.rateOrderAndFood = [
|
|
[body("rateOrder").notEmpty().withMessage(_sr["fa"].required.field)],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const orderId = req?.params?.order_id;
|
|
const { rateOrder, reason, foods } = req.body;
|
|
const getOrder = await Order.findOne({
|
|
_id: orderId,
|
|
user_id: req.user._id,
|
|
status: "delivered",
|
|
paymentStatus: "paid",
|
|
});
|
|
|
|
if (!getOrder) return res404(res, `سفارش مورد نظر پیدا نشد`);
|
|
|
|
//// add rate for all foods
|
|
for (const food of foods) {
|
|
const data = {
|
|
rate: food.rate,
|
|
comment: food.comment,
|
|
order_id: getOrder._id,
|
|
user_id: getOrder.user_id,
|
|
};
|
|
//// check food exist or not
|
|
const getFood = await Food.findById(food?.product_id?._id);
|
|
|
|
if (getFood && getOrder?.order_items.some((item) => item?.product_id?._id?.toString() === getFood?._id?.toString())) {
|
|
getFood.ratings.push(data);
|
|
let rateSUM = 0;
|
|
getFood?.ratings?.forEach((item) => (rateSUM += Number(item.rate)));
|
|
getFood.rate = (rateSUM / getFood?.ratings?.length).toFixed(1);
|
|
await getFood.save();
|
|
}
|
|
}
|
|
|
|
//// add rate to order
|
|
getOrder.rating = {
|
|
rate: rateOrder,
|
|
reasonForBad: reason,
|
|
};
|
|
|
|
await getOrder.save();
|
|
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
} catch (e) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
////////////////////////////////// buy club
|
|
module.exports.buyClub = [
|
|
[body("clubId").notEmpty().withMessage(_sr["fa"].required.field)],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const clubId = req.body?.clubId;
|
|
|
|
const user = await User.findById(req.user._id);
|
|
if (!user) return res404(res, "اطلاعات کاربر یافت نشد");
|
|
|
|
const club = await Food.findOne({ _id: clubId, club: true });
|
|
if (!club) return res404(res, "کلاب مورد نظر پیدا نشد");
|
|
|
|
if (user.score < club.point) return res.status(422).json({ message: "امتیاز شما برای خرید این محصول کافی نمی باشد" });
|
|
|
|
const data = {
|
|
user_id: user._id,
|
|
score: true,
|
|
scorePoint: club.point,
|
|
scoreCost: club.price,
|
|
orderType: "club",
|
|
number: Date.now(),
|
|
address: user?.addresses.find((item) => item.used),
|
|
createdOn: Date.now(),
|
|
paymentStatus: "paid",
|
|
statuses: [
|
|
{
|
|
status: "processing",
|
|
},
|
|
],
|
|
status: "processing",
|
|
order_items: [
|
|
{
|
|
product_id: club._id,
|
|
name: club.name,
|
|
quantity: 1,
|
|
price: club.price,
|
|
point: club.point,
|
|
havePoint: true,
|
|
},
|
|
],
|
|
sum: club.point,
|
|
routePrice: 0,
|
|
tax: 0,
|
|
percent: 0,
|
|
total: club.price,
|
|
};
|
|
|
|
const order = await Order.create(data);
|
|
if (!order) return res500(res, _sr["fa"].response.unknownError);
|
|
|
|
user.score -= club.point;
|
|
user.scoreLogs = [
|
|
{
|
|
score: club.point,
|
|
order_id: order._id,
|
|
forWhat: "buy",
|
|
action: "decrease",
|
|
},
|
|
];
|
|
await user.save();
|
|
|
|
club.stock -= club?.clubQuantity || 1;
|
|
await club.save();
|
|
|
|
return res.json({ message: _sr["fa"].response.success_save });
|
|
} catch (error) {
|
|
return res500(res, _sr["fa"].response.unknownError);
|
|
}
|
|
},
|
|
];
|
|
|
|
////////////////////////////////// test notif
|
|
module.exports.testNotif = [
|
|
async (req, res) => {
|
|
try {
|
|
sendNotifyOrder("6126313206f2593a6a4f71db");
|
|
return res.json({});
|
|
} catch (error) {
|
|
return res500(res, error.message);
|
|
}
|
|
},
|
|
];
|
|
|
|
module.exports.chromeNotif = [
|
|
async (req, res) => {
|
|
try {
|
|
const fcmTokens = [];
|
|
const allAdmins = await User.find({ scope: "admin" });
|
|
|
|
for (const admin of allAdmins) {
|
|
if (admin.fcmToken) fcmTokens.push(admin.fcmToken);
|
|
}
|
|
|
|
const objNotif = {
|
|
title: "سفارش جدید!",
|
|
body: "یک سفارش جدید در پنل برگ من ثبت گردید",
|
|
};
|
|
|
|
const payload = {
|
|
notification: objNotif,
|
|
data: {
|
|
routeName: "test",
|
|
type: "bazaar",
|
|
routeType: "viewBazaar",
|
|
},
|
|
};
|
|
console.log(fcmTokens);
|
|
|
|
const input = {
|
|
registrationTokens: fcmTokens,
|
|
payload,
|
|
};
|
|
|
|
console.log(input);
|
|
|
|
const test = await sendMulti(input);
|
|
|
|
return res.json(test);
|
|
// const payload = JSON.stringify({
|
|
// title: 'Push notifications with Service Workers',
|
|
// });
|
|
//
|
|
// webPush.sendNotification('test', payload)
|
|
// .catch(error => console.error(error));
|
|
} catch (error) {}
|
|
},
|
|
];
|