benschinn
benschinn

Reputation: 41

Stripe invoice items not always being sent together in one invoice

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

Upvotes: 1

Views: 2360

Answers (2)

benschinn
benschinn

Reputation: 41

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

Upvotes: 1

Kimmiies
Kimmiies

Reputation: 101

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

Upvotes: 1

Related Questions