1

Sending an invoice with one invoice item works fine, but things get a bit hairy when I try an send an invoice with many invoice items.

At times multiple invoices gets sent correctly, but often one of the invoice items is missing in the invoice, but get's included in the next invoice. Or at times I will get an error message of: Error: Nothing to invoice for customer, even thought I had just ran stripe.invoiceItems.create. Has anyone else ran into this issue?

To create multiple invoice items I have logic like this:

  await req.body.items.map(item => {
    const unitAmount = (item.wholesale_price + (item.shipping_amount/item.quantity) + (item.s_h/item.quantity));
    stripe.invoiceItems.create({
      unit_amount: unitAmount,
      currency: 'usd',
      customer: stripe_cus_id,
      description: item.description,
      quantity: item.quantity
    }, function(err, invoiceItem) {
      if(err) {
        console.error(err);
      } else {
        console.log(`CREATED: ${item.description}`);
      }
    });
  });

Then I send the invoice like so:

const invoice = await stripe.invoices.create({
  customer: stripe_cus_id,
  billing: 'send_invoice',
  days_until_due: 15
});
benschinn
  • 41
  • 5
  • Are you certain the invoice items are getting created before you're attempting to create the invoice? That's the only thing that this could be I think. If you email into https://support.stripe.com/email, their team can go through the logs with you to see if there is some kind of timing problem happening. – korben Aug 15 '18 at 23:51
  • Thanks. I will email stripe. And yes I am certain it gets created, because I get a response with the invoice item objects. Also on the customer page on Stripe Dashboard it show the pending invoice items. It just doesn't get included in the invoice sometimes... – benschinn Aug 16 '18 at 04:03

2 Answers2

1

I think the expected behaviour is that invoice items are added to the customer's upcoming invoice not the current.

I'm not sure that is the behaviour you're hoping for but to rule things out I would first try to retrieve the customer's upcoming invoice. I tried it with 3 invoice items (1+2+3) and the total amount in the upcoming invoice was correct at 6

https://api.stripe.com/v1/invoices/upcoming?customer=cus_DQk9sobcA4UnlQ

Postman Representation

Kimmiies
  • 91
  • 1
  • 5
1

I have discovered the issue to be using await with Array.prototype.map. In MDN docs for await it says:

If the value of the expression following 
the await operator is not a Promise, it's
converted to a resolved Promise.

The problem was that the value following await was Array.prototype.map, and it is not a promise. This caused the await to resolve prematurely.

I found a solution to this issue here. Wrapping my map in a Promise.all fixed the issue, like so:

    await Promise.all(
      req.body.items.map(item => {
        return new Promise(function( resolve, reject) {
          const unitAmount = (item.wholesale_price + (item.shipping_amount/item.quantity) + (item.s_h/item.quantity));
          stripe.invoiceItems.create({
            unit_amount: unitAmount,
            currency: 'usd',
            customer: stripe_cus_id,
            description: item.description,
            quantity: item.quantity
          }, {
            idempotency_key: uuidv4()
          }, function(err, invoiceItem) {
            if(err) {
              console.error(err);
              reject(err);
            } else {
              console.log(`CREATED: ${item.description}`);
              resolve();
            }
          });
        })
      })
    );
benschinn
  • 41
  • 5
  • Yes, basic problem is that stripe.invoiceItems.create is an asychronous call and your original code was not waiting for it to complete before calling invoice.create (even though the await makes it looks like was). – Brad Peabody Jan 31 '20 at 18:45