基本上,我有一个代码可以通过将用户输入的优惠券应用到订单交易中来批准订单代码:
var Order = require('../models/order');
var Product = require('../models/product');
var Coupon = require('../models/coupon');
var _ = require('lodash');
exports.approveOrder = function(req, res) {
var tempProducts;
var tempCoupon;
var orderNbr = req.params.OrderNbr;
if (orderNbr != undefined && orderNbr != '')
{
Order.findOne({ OrderNbr: orderNbr }).exec()
.then(function(order) {
if (order == undefined) {
throw "Order " + orderNbr + " does not exist.";
}
else {
if (order.OrderLines.length <= 0) throw "Ensure your Order has at least one order line.";
if (req.body.CouponCode != undefined && req.body.CouponCode != '') {
// ***********************************************
// Want to refactor this following codes into some functions
// ***********************************************
Coupon.findOne({ CouponCode: req.body.CouponCode }).exec()
.then(function(coupon) {
if (coupon == undefined) {
throw "Coupon " + req.body.CouponCode + " does not exist.";
}
else {
if (coupon.Qty > 0 && (coupon.ValidFrom <= new Date() && coupon.ValidTo >= new Date())) {
coupon.Qty -= 1;
tempCoupon = coupon;
var prodNbrs = _.map(order.OrderLines, 'ProdNbr');
return Product.find({ ProdNbr: { $in : prodNbrs } }).exec();
}
else {
throw "Coupon " + coupon.CouponCode + " is not valid.";
}
}
})
.then(function(products) {
var prodNbrs = _.map(order.OrderLines, 'ProdNbr');
var totalQtyPerProd = 0;
_.forEach(products, function(product) {
totalQtyPerProd = _.sumBy(order.OrderLines, function(line) {
if (product.ProdNbr == line.ProdNbr) return line.Qty;
})
if (product.QtyOnHand - totalQtyPerProd < 0) throw "Product " + product.ProdNbr + " has insufficient quantity on hand.";
_.remove(prodNbrs, function(nbr) { return nbr == product.ProdNbr });
product.QtyOnHand -= totalQtyPerProd;
var totalDiscount = tempCoupon.Value / order.OrderLines.length;
if (tempCoupon.IsPercentage) {
totalDiscount = 1 - (tempCoupon.Value / 100);
}
_.forEach(order.OrderLines, function(line) {
if (line.ProdNbr == product.ProdNbr) {
line.UnitPrice = product.UnitPrice;
line.Amount = (line.Qty * line.UnitPrice) - totalDiscount;
if (line.Amount < 0) line.Amount = 0;
if (tempCoupon.IsPercentage) {
line.Amount = (line.Qty * line.UnitPrice) * totalDiscount;
}
}
})
})
if (prodNbrs.length > 0) throw "Product " + prodNbrs[0] + " does not exist.";
tempProducts = products;
order.CouponCode = tempCoupon.CouponCode;
order.Status = 'S';
return order.save();
})
.then(function() {
return tempCoupon.save();
})
.then(function() {
_.forEach(tempProducts, function(product) {
product.save()
.then(function() {
})
.catch(function(err) {
if (err) res.status('500').jsonp({ error: err });
});
})
res.status('200').jsonp({ information: "Order "+ order.OrderNbr +" has been submitted successfully." });
})
.catch(function(err) {
if (err) res.status('500').jsonp({ error: err });
});
}
}
})
.catch(function(err) {
if (err) res.status('500').jsonp({ error: err });
});
}
else {
res.status('500').jsonp({ error: "Order Number must be specified." });
}
};
我想将每个“then”子句的代码拆分为一些函数:
- 找到优惠券,然后返还优惠券。
- 更新订单行金额
- 更新优惠券
- 返回确认消息
我尝试使用局部变量来保留找到的优惠券,不幸的是,如果它超出了 findOne() 方法,该变量将是未定义的,所以在这段代码中我在 findOne() 中使用了很多又长的“.then”
有什么想法吗?
最佳答案
您使用“then chain”的方法很好。 我将重构代码,创建单独的函数以在链中使用,如下所示:
var saveProducts = function() {
_.forEach(tempProducts, function(product) {
product.save()
.then(function() {
})
.catch(function(err) {
if (err) res.status('500').jsonp({ error: err });
});
})
res.status('200').jsonp({ information: "Order "+ order.OrderNbr +" has been submitted successfully." });
}
var saveCoupon = function() {
return tempCoupon.save();
}
var products = function(products) {
var prodNbrs = _.map(order.OrderLines, 'ProdNbr');
var totalQtyPerProd = 0;
_.forEach(products, function(product) {
totalQtyPerProd = _.sumBy(order.OrderLines, function(line) {
if (product.ProdNbr == line.ProdNbr) return line.Qty;
})
if (product.QtyOnHand - totalQtyPerProd < 0) throw "Product " + product.ProdNbr + " has insufficient quantity on hand.";
_.remove(prodNbrs, function(nbr) { return nbr == product.ProdNbr });
product.QtyOnHand -= totalQtyPerProd;
var totalDiscount = tempCoupon.Value / order.OrderLines.length;
if (tempCoupon.IsPercentage) {
totalDiscount = 1 - (tempCoupon.Value / 100);
}
_.forEach(order.OrderLines, function(line) {
if (line.ProdNbr == product.ProdNbr) {
line.UnitPrice = product.UnitPrice;
line.Amount = (line.Qty * line.UnitPrice) - totalDiscount;
if (line.Amount < 0) line.Amount = 0;
if (tempCoupon.IsPercentage) {
line.Amount = (line.Qty * line.UnitPrice) * totalDiscount;
}
}
})
})
if (prodNbrs.length > 0) throw "Product " + prodNbrs[0] + " does not exist.";
tempProducts = products;
order.CouponCode = tempCoupon.CouponCode;
order.Status = 'S';
return order.save();
}
var getProducts = function(coupon) {
if (coupon == undefined) {
throw "Coupon " + req.body.CouponCode + " does not exist.";
}
else {
if (coupon.Qty > 0 && (coupon.ValidFrom <= new Date() && coupon.ValidTo >= new Date())) {
coupon.Qty -= 1;
tempCoupon = coupon;
var prodNbrs = _.map(order.OrderLines, 'ProdNbr');
return Product.find({ ProdNbr: { $in : prodNbrs } }).exec();
}
else {
throw "Coupon " + coupon.CouponCode + " is not valid.";
}
}
}
exports.approveOrder = function(req, res) {
var tempProducts;
var tempCoupon;
var orderNbr = req.params.OrderNbr;
if (orderNbr != undefined && orderNbr != '')
{
Order.findOne({ OrderNbr: orderNbr }).exec()
.then(function(order) {
if (order == undefined) {
throw "Order " + orderNbr + " does not exist.";
}
else {
if (order.OrderLines.length <= 0) throw "Ensure your Order has at least one order line.";
if (req.body.CouponCode != undefined && req.body.CouponCode != '') {
// ***********************************************
// Want to refactor this following codes into some functions
// ***********************************************
Coupon.findOne({ CouponCode: req.body.CouponCode }).exec()
.then(getProducts)
.then(products)
.then(saveCoupon)
.then(saveProducts)
.catch(function(err) {
if (err) res.status('500').jsonp({ error: err });
});
}
}
})
.catch(function(err) {
if (err) res.status('500').jsonp({ error: err });
});
}
else {
res.status('500').jsonp({ error: "Order Number must be specified." });
}
};
每个函数的结果将传递到链中的下一个函数
我建议这个关于 Promise 最佳实践的帖子
关于javascript - 重构 Promise javascript 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47034622/