#ninjajinja_code

1 messages ¡ Page 1 of 1 (latest)

gaunt lodgeBOT
#

👋 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/1299363296964644898

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

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.

eternal zealot
#

subscription Id
sub_1QDhj5GA5TYWMni87Fk83tt1

#

complete function
``
const stripeSubscription = await stripe.subscriptions.retrieve(
dbSubscription.subscriptionId as string
);

if (newNfts.length > 0) {
  const chargeAmount = newNfts.length * 9500;

  await stripe.invoiceItems.create({
    customer: stripeSubscription.customer as string,
    amount: chargeAmount,
    currency: "usd",
    description: `Charge for ${newNfts.length} new NFT(s)`,
  });

  const invoice = await stripe.invoices.create({
    customer: stripeSubscription.customer as string,
    auto_advance: true,
    collection_method: "charge_automatically",
  });

  await stripe.invoices.pay(invoice.id);
}
const { updatedSubscription, priceId, quantity } =
  await updateStripeSubscriptionQuantity(stripeSubscription, nfts);

const subscriptionSchedule = await isSubscriptionScheduleCreated(
  updatedSubscription.schedule as string
);

await updateStripeSubscriptionSchedule(
  subscriptionSchedule.id,
  subscriptionSchedule.phases[0]?.start_date,
  priceId,
  quantity
);

await handlePaymentMethodUpdate(stripeSubscription.id, setupIntentId);

const updatedSub = await updateLocalSubscriptionStatus(
  subscriptionId,
  updatedSubscription.status,
  nfts
);

return {
  success: true,
  message: "Subscription updated successfully",
  subscription: updatedSub,
};

}```

lethal cloak
#

Can you explain more about what the unexpected thing happening here is?

eternal zealot
#

amount due should be 190 but comes out to be $379.91

#

since they have aready paid 190 $

#

next moth they should be paying 190$

#

why they are being charged 379.91

#

its bit confusing

lethal cloak
#

By default when you update a subscription, we prorate the update, and prorations are charged on the next invoice

eternal zealot
#

but we set prorations to none

#
  scheduleId: string,
  scheduleStartDate: number,
  price: string,
  quantity: number
): Promise<Stripe.SubscriptionSchedule> {
  const now = new Date();
  const currentQuarterEnd = endOfQuarter(now);
  const nextQuarterStart = addDays(currentQuarterEnd, 1);

  // Get the next quarter start date as a Unix timestamp (in seconds)
  const endDateInSeconds = getUnixTime(nextQuarterStart);

  return stripe.subscriptionSchedules.update(scheduleId, {
    phases: [
      {
        start_date: scheduleStartDate,
        end_date: endDateInSeconds,
        items: [
          {
            price,
            quantity, // Ensure correct quantity is set
          },
        ],
        proration_behavior: "none",
      },
      {
        billing_cycle_anchor: "phase_start",
        items: [
          {
            price,
            quantity, // Set quantity for the next phase as well
          },
        ],
        proration_behavior: "none",
      },
    ],
  });
}```
#

while creatng Sub

  stripeCustomerId: string,
  priceId: string,
  nfts: number[],
  dbSubscriptionId: string,
  dbUserId: string
) {
  return stripe.subscriptions.create({
    customer: stripeCustomerId,
    items: [{ price: priceId, quantity: nfts.length }],
    payment_settings: {
      payment_method_types: ["card", "paypal"],
      save_default_payment_method: "on_subscription",
    },
    payment_behavior: "default_incomplete",
    expand: ["latest_invoice.payment_intent", "schedule"],
    metadata: {
      userId: dbUserId,
      subscriptionId: dbSubscriptionId,
      nfts: JSON.stringify(nfts),
    },
    proration_behavior: "none",
    collection_method: "charge_automatically",
  });
}
```\
lethal cloak
#

Prorations aren't set globally

#

They're set on a per-request basis

#

You didn't set it on the update request

#

So, the default behavior of create prorations is used

eternal zealot
#
 * Updates the quantity and metadata of a Stripe subscription
 *
 * @param stripeSubscription - The Stripe subscription object to update
 * @param nfts - Array of NFT IDs to be included in the subscription
 * @throws {ServiceError} If price ID or quantity is missing from the updated subscription
 * @returns {Promise<{
 *   updatedSubscription: Stripe.Subscription,
 *   priceId: string,
 *   quantity: number
 * }>} Updated subscription details
 */
export async function updateStripeSubscriptionQuantity(
  stripeSubscription: Stripe.Subscription,
  nfts: number[]
) {
  const updatedItemParams = stripeSubscription.items.data.map((item) => ({
    id: item.id,
    quantity: nfts.length,
    metadata: { nfts: JSON.stringify(nfts) },
  }));

  const updatedSubscription = await stripe.subscriptions.update(
    stripeSubscription.id,
    { items: updatedItemParams }
  );

  const { priceId, quantity } = getSubscriptionDetails(updatedSubscription);
  if (!priceId || !quantity) {
    Logger.error(
      `Missing price ID or quantity for subscription ${updatedSubscription.id}`
    );
    throw new ServiceError({
      code: "PriceId_Or_Quantity_Missing",
      message: "subscription price id or quantity missing",
    });
  }

  return { updatedSubscription, priceId, quantity };
}```
#

so here as well I would need to set prorations to none? @lethal cloak

lethal cloak
#

If the behavior you're trying to achieve is to disable prorations, then yeah

#

But I recommend reading that doc I sent you before doing anything else

#

So you understand what you're building

eternal zealot
#

I will run you through it
we have a cut off date if a user want to add some more seat before that date we create a invoice charge so eg if a seat is 15 $ and they add 2 more we would charge them 30 $ and then the next cycle would charge them 45 $\

lethal cloak
#

Please read the doc though

#

It's not good to build a subscription integration if you don't understand how our prorations work

#

That's how you end up in trouble with unexpected behavior you didn't anticipate

#

But to achieve what you want, it sounds like you need to disable prorations

#

And charge them an extra 30 in an invoice outside of the subscription

#

Because if you set proration_behavior to always_invoice, it will immediately charge you a prorated amount for those 2 extra seats

#

Again, recomend reading the doc so you understand