#kyle-heat-engineer_code

1 messages · Page 1 of 1 (latest)

sonic hazelBOT
#

👋 Welcome to your new thread!

⏲️ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

⏱️ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

🔗 This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1271564027759169566

📝 Have more to share? Add more details, code, screenshots, videos, etc. below.

primal remnantBOT
#

Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.

dapper edge
#
export const updateOwnerSubscription = async (customer_id: string, plans: PLAN[]) => {
  const currentSubscriptions = await stripeClient.subscriptions.list({
    customer: customer_id,
    status: 'active',
  })

  if (currentSubscriptions.data.length > 1) {
    throw new Error('Multiple subscriptions found')
  }

  const subscription = currentSubscriptions.data.at(0)

  if (!subscription) {
    throw new Error('Subscription not found')
  }

  const {
    subscriptionItemsIdsToRemove,
    subscriptionItemsUnChanged,
    subscriptionItemsToAdd,
  } = await generateSubscriptions(subscription, plans)

  console.log({
    subscriptionItemsIdsToRemove,
    subscriptionItemsUnChanged,
    subscriptionItemsToAdd,
  })

  const updateSubscription = await stripeClient.subscriptions.update(subscription.id, {
    items: [
      ...subscriptionItemsIdsToRemove,
      ...subscriptionItemsUnChanged,
      ...subscriptionItemsToAdd,
    ],
    proration_behavior: 'none',
    automatic_tax: { enabled: true },
  })

  return updateSubscription
}
#

async function generateSubscriptions(subscription: Stripe.Subscription, plans: PLAN[]) {
  const prices = (
    await stripeClient.prices.list({
      lookup_keys: plans,
    })
  )?.data?.map(({ id, lookup_key, nickname }) => ({
    id,
    lookup_key: lookup_key ?? nickname,
  }))

  if (!subscription) {
    throw new Error('Subscription not found')
  }

  const subscriptionItems = subscription.items.data

  return {
    subscriptionItemsIdsToRemove: subscriptionItems
      .filter(
        (item) =>
          !plans.includes(
            (item.price.lookup_key ?? item.price.nickname) as PLAN,
          ),
      )
      .map(({ id }) => ({ id, deleted: true })),
    subscriptionItemsUnChanged: subscriptionItems
      .filter((item) =>
        plans.includes((item.price.lookup_key ?? item.price.nickname) as PLAN),
      )
      .map(({ id }) => ({ id })),
    subscriptionItemsToAdd: prices
      .filter(
        (price) =>
          !subscriptionItems.some(
            (item) =>
              item.price.lookup_key === price.lookup_key ||
              item.price.nickname === price.lookup_key,
          ),
      )
      .map(({ id }) => ({ price: id })),
  }
}
eternal marten
#

You have proration behavior set to none, so what that should do is bill for everthing you passed in at the next cycle

#

What's happening exactly?

#

And can you share a sample subscription id

dapper edge
#

Let me get a screen shot of the dashboard

eternal marten
#

No the id is what i need so i can look it up

#

Not a screenshot

dapper edge
#

Ok one sec

#

sub_1Plq5oJ3mXHphgmzJ6wXChxY its from test dashboard

#

essentially if I was setting my user to have a updated subscription where I am only removing subscription items. The user is getting charged for the unchanged subscription

#

If I set the proration to a different value would this result in the 'invoice.payment_succeeded' event being triggered, as this is what I use to update my db with application business logic

#

Let me update on my end so you can see the issue I am trying to raise

#

Ok you should be able to see how I updated my sole trader to have 0 cad which charged me for the full sole trader year

eternal marten
#

It's not set to bill again until 2025

dapper edge
#

Ok, looks like I have been a bit dumb here

#

Thank you for pointing this out too me

#

But when I do want to change my users subscription I do want them to be charged straight away for it

#

I think the confusing arrised because when I changed them from a monthly subscription to a yearly subscripton this resulted in the charge occuring (how I would expect it too). But when changing the subscripiton from a yearly to another yearly one its not getting charged till the next year

#

Essentailly I need my users to be charged for the parts they change and not charged for the parts that are constant within the subscription update

eternal marten
#

Not sure I understand exactly, but sounds like you should charge immediately for the proration

dapper edge
#

Let me try and explain it again.

Say I have a subscription for A £10 a month and B £20 a month. The user updates the subscription to be A £10 a month and C £30 a month. Currnetly in the logic I have the user is getting charged £40 a month but really they need to be charged £30 on the update of subscription and then the next month they need to be charged £40. Does this make sense?

eternal marten
#

Kind of. This upgrade would be part way through the month?

dapper edge
#

Yeah this would be part way

eternal marten
#

Ok so then if you were to bill them 30, that would actually be overcharging them

#

Since they'd only be on the 30 price for part of the month

#

Really prorations handles this for you

dapper edge
#

In our business context this can be a unit amount so the system would handle it on our end for the over charge

#

In our context it would be £30 for 15 surveys which immidaitly gets added to the user

#

So wouldn't want to charge less than 30 in this case

eternal marten
#

What about the 20 they already paid?

#

Do they not get credit for that?

dapper edge
#

We are happy to over charge for the updated item but don't want to recharge for the unchanged items

eternal marten
#

So really in the current month they'd pay 10 + 20 + 30 = 60 across 2 invoices?

dapper edge
#

Yes

#

then next invoice would be 40

eternal marten
#

Ok our prorations don't work like that

#

This is a pretty unique use case

dapper edge
#

Thats why I had it set to none

eternal marten
#

You'd need to create an invoice for the 30

#

LIke expliclty create and bill them 30 for the update and set proration behavior to none

#

That way next month they get charged 40

#

And you have to manually charge them 30

dapper edge
#

That could work for our use case. Just thinking if I would still see the subscription items from the webhook side as this event 'invoice.payment_succeeded' needs to be able to pick up the subscription items to know to update the users account

eternal marten
#

Well you wouldn't get invoice.payment_succeeded until the next month/billing cycle

#

since proration behavior is none

dapper edge
#

Ah that would be an issue cause the users account wouldn't be updated till next billing cycle

#

You'd need to create an invoice for the 30, this wouldn't trigger a invoice success?

eternal marten
#

It would

dapper edge
#

I guess I could put meta data in the custom created invoice to then detect in the invoice.payment_succeeded event.

eternal marten
#

But it would only have the $30 amount not all the subscription items

#

Since this is a separate invoice you have to manually bill them not a part of the subscription's cycle

dapper edge
#

I think this would still work in our uses case

#

Thank you, I feel like I can see a soltuion to this issue now

eternal marten
#

Happy to help!

dapper edge
#

I know our system is overally complex 😅