async.forEachOf

时间:2017-09-22 07:02:47

标签: mongodb async.js

我在mongo集合中进行了一些付款循环。 payoutdate == today()的所有付款必须导出并写入单独的文件,因此我们可以通过银行处理付款。

付款在创建时没有invoicenumber,我们在处理付款时生成一个(通过上述功能导出)。 问题是,当我们运行要导出多个付款的功能时,所有付款都会获得相同的发票编号。所以看起来,在处理下一笔付款之前,最后的保存操作没有完成。

我怎么能认为每笔付款的数量都在增加?

这是循环函数:

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());
            }
        }
    })

orderService包含以下功能(与此问题相关)

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 个答案:

答案 0 :(得分:1)

你有两个选择:

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

答案 1 :(得分:0)

感谢两位回复!一个组合是解决方案。

我更改了查询以查找最后invoiceNumber

Payment.find({invoiceNumber: {$ne:null}}).sort({date: -1}).limit(1).exec(function(err, latestPaymentsWithNumber){

我现在使用async.eachSeries迭代paymentsasync.eachSeries(payments, function(payment, paymentDone) {

我在第一次回调中做了一个result.save,因为我有正确的数据

result.save(function(err, payment){