async.forEachOf 中的多个保存操作
Multiple save operations in async.forEachOf
我在 mongo 集合中循环处理一些付款。所有 payoutdate == today() 的付款都必须导出并写入 sepa 文件,以便我们可以通过银行处理付款。
付款在创建时没有发票编号,我们会在处理付款时生成一个发票编号(通过上述函数导出)。
问题是,当我们 运行 导出多笔付款的函数时,所有付款都获得相同的发票编号。所以看起来,在下一次付款处理之前,最后一次保存操作没有完成。
如何实现每次付款都在增加?
这是循环函数:
const fs = require('fs');
const async = require('async');
const DateDiff = require('date-diff');
const SEPA = require('sepa');
const shopService = require(path.join(__dirname, '..', 'services', 'shop.service'));
async.forEachOf(payments, function(payment, key, paymentDone){
var diff = new DateDiff(new Date(payment.payoutDate), new Date());
if(payment.payoutDate && payment.amount > 0 && payment.completed == false && payment.exported == false && diff.days() <= 0){
//payment has amount, is not completed and is not exported, create an SEPA transfer, and set the payment to completed
//but first create an invoicenumber
orderService.updateOrderPayment(payment.orderId, {generateInvoiceNumber: true}, function(err, result){
if(err){
console.log("error updating payment", err);
}
//reget the payment to avoid duplicated invoice numbers
orderService.getPayment(result.orderId, function(err, payment){
if(err){
console.log("error getting payment", err);
}
Shop.findOne({_id: payment.shopId}).exec(function(err, shop){
if(shop && shop.bankAccountNumber && shop.accountHolder && shop.bicCode){
//create transaction and add this to the file
}else{
var result = {
paymentID: payment._id,
orderId: payment.orderId,
status: payment.status,
message: "shop does not have an iban, accountholder or biccode",
shop: shop.nameSlug
}
resultArray.push(result);
console.log("shop does not have an iban, accountholder or biccode", shop.nameSlug);
paymentDone();
}
orderService.updateOrderPayment(payment.orderId, {status: 'completed'}, function(err, result){
orderService.updateOrderStatusById(payment.orderId, {status: 'Granted', date: new Date(), comment: null});
var result = {
paymentID: payment._id,
orderId: payment.orderId,
status: payment.status,
message: "payment exported",
}
resultArray.push(result);
counter++;
paymentDone();
})
})
})
})
}else{
var result = {
paymentID: payment._id,
orderId: payment.orderId,
status: payment.status,
message: "order already processed"
}
resultArray.push(result);
paymentDone();
}
}, function(){
if(resultArray.length == payments.length){
//console.log("Result", resultArray);
if(counter == 0){
res.status(200).json({"message":"No orders to export", resultArray});
}else{
res.set({"Content-Disposition":"attachment; filename=\"sepa.xml\""});
res.send(doc.toString());
}
}
})
订单服务包含以下功能(与本题相关)
function updateOrderPayment(orderId, paymentStatus, callback){
console.log("updateOrderPayment");
if(!paymentStatus){
return callback("No payment details provided");
}else{
if(!paymentStatus.comment){
paymentStatus.comment = null;
}
}
getPayment(orderId, function(err, payment){
if(err)
return callback(err);
handlePayment(payment, paymentStatus, function(result){
result.save(function(err, result){
if(err){
return callback(err);
}
console.log("payment saved");
return callback(null, result);
})
})
})
}
function handlePayment(payment, paymentStatus, callback){
if(paymentStatus.status){
var status = {
status: paymentStatus.status,
comment: paymentStatus.comment,
date: Date.now()
}
payment.status.push(status);
}
if(paymentStatus.generateInvoiceNumber){
console.log("generateInvoiceNumber");
var invoiceNumber =0;
Payment.findOne({invoiceNumber: {$exists:true}}).sort({_id: -1}).exec(function(err, latestPaymentsWithNumber){
if(latestPaymentsWithNumber && latestPaymentsWithNumber.invoiceNumber){
invoiceNumber = latestPaymentsWithNumber.invoiceNumber.split("-")[1];
}
var date = new Date();
payment.invoiceNumber = date.getFullYear().toString() + date.getMonth().toString() + "-" + (parseInt(invoiceNumber)+1);
console.log("number", payment.invoiceNumber);
return callback(payment);
})
}
if(paymentStatus.status == 'returned' || paymentStatus.status == 'cancelled'){
payment.cancelled = true;
payment.amount = 0;
payment.payoutDate = null;
return callback(payment);
}
if(paymentStatus.status == 'completed'){
payment.completed = true;
payment.exported = true;
payment.payoutDate = null;
return callback(payment);
}
}
function getPayment(orderId, callback){
Payment.findOne({orderId: orderId}).exec(function(err, payment){
if(err){
return callback(err);
}
return callback(null, payment);
})
}
你有2个选择:
1) 在范围内实现对保存操作的回调
x.forEach(function(_x) {
_x.save(function(err) { });
});
2) 将您的函数分解为异步单元或使用异步库
function async(x, cb) {
x.operations(cb)
}
function series(x) {
if (x) {
async(x, function() { series(xs.pop()); });
} else // finished
}
series(xs.pop()); // xs is the array you're iterating
感谢两位的回复!组合是解决方案。
我已将查找最后一个 invoiceNumber
的查询更改为
Payment.find({invoiceNumber: {$ne:null}}).sort({date: -1}).limit(1).exec(function(err, latestPaymentsWithNumber){
我现在使用 async.eachSeries 迭代 payments
:
async.eachSeries(payments, function(payment, paymentDone)
{
然后我在第一个回调中执行 result.save 以假设我有正确的数据
result.save(function(err, payment){
我在 mongo 集合中循环处理一些付款。所有 payoutdate == today() 的付款都必须导出并写入 sepa 文件,以便我们可以通过银行处理付款。
付款在创建时没有发票编号,我们会在处理付款时生成一个发票编号(通过上述函数导出)。 问题是,当我们 运行 导出多笔付款的函数时,所有付款都获得相同的发票编号。所以看起来,在下一次付款处理之前,最后一次保存操作没有完成。
如何实现每次付款都在增加?
这是循环函数:
const fs = require('fs');
const async = require('async');
const DateDiff = require('date-diff');
const SEPA = require('sepa');
const shopService = require(path.join(__dirname, '..', 'services', 'shop.service'));
async.forEachOf(payments, function(payment, key, paymentDone){
var diff = new DateDiff(new Date(payment.payoutDate), new Date());
if(payment.payoutDate && payment.amount > 0 && payment.completed == false && payment.exported == false && diff.days() <= 0){
//payment has amount, is not completed and is not exported, create an SEPA transfer, and set the payment to completed
//but first create an invoicenumber
orderService.updateOrderPayment(payment.orderId, {generateInvoiceNumber: true}, function(err, result){
if(err){
console.log("error updating payment", err);
}
//reget the payment to avoid duplicated invoice numbers
orderService.getPayment(result.orderId, function(err, payment){
if(err){
console.log("error getting payment", err);
}
Shop.findOne({_id: payment.shopId}).exec(function(err, shop){
if(shop && shop.bankAccountNumber && shop.accountHolder && shop.bicCode){
//create transaction and add this to the file
}else{
var result = {
paymentID: payment._id,
orderId: payment.orderId,
status: payment.status,
message: "shop does not have an iban, accountholder or biccode",
shop: shop.nameSlug
}
resultArray.push(result);
console.log("shop does not have an iban, accountholder or biccode", shop.nameSlug);
paymentDone();
}
orderService.updateOrderPayment(payment.orderId, {status: 'completed'}, function(err, result){
orderService.updateOrderStatusById(payment.orderId, {status: 'Granted', date: new Date(), comment: null});
var result = {
paymentID: payment._id,
orderId: payment.orderId,
status: payment.status,
message: "payment exported",
}
resultArray.push(result);
counter++;
paymentDone();
})
})
})
})
}else{
var result = {
paymentID: payment._id,
orderId: payment.orderId,
status: payment.status,
message: "order already processed"
}
resultArray.push(result);
paymentDone();
}
}, function(){
if(resultArray.length == payments.length){
//console.log("Result", resultArray);
if(counter == 0){
res.status(200).json({"message":"No orders to export", resultArray});
}else{
res.set({"Content-Disposition":"attachment; filename=\"sepa.xml\""});
res.send(doc.toString());
}
}
})
订单服务包含以下功能(与本题相关)
function updateOrderPayment(orderId, paymentStatus, callback){
console.log("updateOrderPayment");
if(!paymentStatus){
return callback("No payment details provided");
}else{
if(!paymentStatus.comment){
paymentStatus.comment = null;
}
}
getPayment(orderId, function(err, payment){
if(err)
return callback(err);
handlePayment(payment, paymentStatus, function(result){
result.save(function(err, result){
if(err){
return callback(err);
}
console.log("payment saved");
return callback(null, result);
})
})
})
}
function handlePayment(payment, paymentStatus, callback){
if(paymentStatus.status){
var status = {
status: paymentStatus.status,
comment: paymentStatus.comment,
date: Date.now()
}
payment.status.push(status);
}
if(paymentStatus.generateInvoiceNumber){
console.log("generateInvoiceNumber");
var invoiceNumber =0;
Payment.findOne({invoiceNumber: {$exists:true}}).sort({_id: -1}).exec(function(err, latestPaymentsWithNumber){
if(latestPaymentsWithNumber && latestPaymentsWithNumber.invoiceNumber){
invoiceNumber = latestPaymentsWithNumber.invoiceNumber.split("-")[1];
}
var date = new Date();
payment.invoiceNumber = date.getFullYear().toString() + date.getMonth().toString() + "-" + (parseInt(invoiceNumber)+1);
console.log("number", payment.invoiceNumber);
return callback(payment);
})
}
if(paymentStatus.status == 'returned' || paymentStatus.status == 'cancelled'){
payment.cancelled = true;
payment.amount = 0;
payment.payoutDate = null;
return callback(payment);
}
if(paymentStatus.status == 'completed'){
payment.completed = true;
payment.exported = true;
payment.payoutDate = null;
return callback(payment);
}
}
function getPayment(orderId, callback){
Payment.findOne({orderId: orderId}).exec(function(err, payment){
if(err){
return callback(err);
}
return callback(null, payment);
})
}
你有2个选择:
1) 在范围内实现对保存操作的回调
x.forEach(function(_x) {
_x.save(function(err) { });
});
2) 将您的函数分解为异步单元或使用异步库
function async(x, cb) {
x.operations(cb)
}
function series(x) {
if (x) {
async(x, function() { series(xs.pop()); });
} else // finished
}
series(xs.pop()); // xs is the array you're iterating
感谢两位的回复!组合是解决方案。
我已将查找最后一个 invoiceNumber
的查询更改为
Payment.find({invoiceNumber: {$ne:null}}).sort({date: -1}).limit(1).exec(function(err, latestPaymentsWithNumber){
我现在使用 async.eachSeries 迭代 payments
:
async.eachSeries(payments, function(payment, paymentDone)
{
然后我在第一个回调中执行 result.save 以假设我有正确的数据
result.save(function(err, payment){