stripe: Link InvoiceItem to Invoice.

This is required for upgrading to the basil version of stripe.
Changes haven't been tested in this commit. It is just for easy
verification of changes.
This commit is contained in:
Aman Agrawal
2025-05-10 13:25:17 +05:30
committed by Tim Abbott
parent 6fb7a21cef
commit 3cdda91afe

View File

@@ -3216,25 +3216,32 @@ class BillingSession(ABC):
licenses_base = plan.invoiced_through.licenses licenses_base = plan.invoiced_through.licenses
invoiced_through_id = plan.invoiced_through.id invoiced_through_id = plan.invoiced_through.id
# Invoice Variables
stripe_invoice: stripe.Invoice | None = None
need_to_invoice = False
# Track if we added renewal invoice item which is possibly eligible for discount. # Track if we added renewal invoice item which is possibly eligible for discount.
renewal_invoice_period: stripe.InvoiceItem.CreateParamsPeriod | None = None renewal_invoice_period: stripe.InvoiceItem.CreateParamsPeriod | None = None
for ledger_entry in LicenseLedger.objects.filter( for ledger_entry in LicenseLedger.objects.filter(
plan=plan, id__gt=invoiced_through_id, event_time__lte=event_time plan=plan, id__gt=invoiced_through_id, event_time__lte=event_time
).order_by("id"): ).order_by("id"):
price_args: PriceArgs = {} # InvoiceItem variables.
invoice_item_params = stripe.InvoiceItem.CreateParams(
customer=plan.customer.stripe_customer_id
)
if ledger_entry.is_renewal: if ledger_entry.is_renewal:
if plan.fixed_price is not None: if plan.fixed_price is not None:
amount_due = get_amount_due_fixed_price_plan( amount_due = get_amount_due_fixed_price_plan(
plan.fixed_price, plan.billing_schedule plan.fixed_price, plan.billing_schedule
) )
price_args = {"amount": amount_due} invoice_item_params["amount"] = amount_due
else: else:
assert plan.price_per_license is not None # needed for mypy assert plan.price_per_license is not None # needed for mypy
price_args = { invoice_item_params["unit_amount"] = plan.price_per_license
"unit_amount": plan.price_per_license, invoice_item_params["quantity"] = ledger_entry.licenses
"quantity": ledger_entry.licenses, invoice_item_params["description"] = f"{plan.name} - renewal"
} need_to_invoice = True
description = f"{plan.name} - renewal"
elif ( elif (
plan.fixed_price is None plan.fixed_price is None
and licenses_base is not None and licenses_base is not None
@@ -3260,61 +3267,15 @@ class BillingSession(ABC):
plan_renewal_or_end_date - ledger_entry.event_time plan_renewal_or_end_date - ledger_entry.event_time
) / (billing_period_end - last_renewal) ) / (billing_period_end - last_renewal)
unit_amount = int(plan.price_per_license * proration_fraction + 0.5) unit_amount = int(plan.price_per_license * proration_fraction + 0.5)
price_args = { invoice_item_params["unit_amount"] = unit_amount
"unit_amount": unit_amount, invoice_item_params["quantity"] = ledger_entry.licenses - licenses_base
"quantity": ledger_entry.licenses - licenses_base, invoice_item_params["description"] = "Additional license ({} - {})".format(
}
description = "Additional license ({} - {})".format(
ledger_entry.event_time.strftime("%b %-d, %Y"), ledger_entry.event_time.strftime("%b %-d, %Y"),
plan_renewal_or_end_date.strftime("%b %-d, %Y"), plan_renewal_or_end_date.strftime("%b %-d, %Y"),
) )
need_to_invoice = True
if price_args: if stripe_invoice is None and need_to_invoice:
plan.invoiced_through = ledger_entry
plan.invoicing_status = CustomerPlan.INVOICING_STATUS_STARTED
plan.save(update_fields=["invoicing_status", "invoiced_through"])
invoice_period = stripe.InvoiceItem.CreateParamsPeriod(
start=datetime_to_timestamp(ledger_entry.event_time),
end=datetime_to_timestamp(
get_plan_renewal_or_end_date(plan, ledger_entry.event_time)
),
)
if ledger_entry.is_renewal:
renewal_invoice_period = invoice_period
stripe.InvoiceItem.create(
currency="usd",
customer=plan.customer.stripe_customer_id,
description=description,
discountable=False,
period=invoice_period,
idempotency_key=get_idempotency_key(ledger_entry),
**price_args,
)
# Update license base per ledger_entry.
licenses_base = ledger_entry.licenses
plan.invoiced_through = ledger_entry
if renewal_invoice_period is not None:
flat_discount, flat_discounted_months = self.get_flat_discount_info(plan.customer)
if plan.fixed_price is None and flat_discounted_months > 0:
num_months = (
12 if plan.billing_schedule == CustomerPlan.BILLING_SCHEDULE_ANNUAL else 1
)
flat_discounted_months = min(flat_discounted_months, num_months)
discount = flat_discount * flat_discounted_months
plan.customer.flat_discounted_months -= flat_discounted_months
plan.customer.save(update_fields=["flat_discounted_months"])
stripe.InvoiceItem.create(
currency="usd",
customer=plan.customer.stripe_customer_id,
description=f"${cents_to_dollar_string(flat_discount)}/month new customer discount",
# Negative value to apply discount.
amount=(-1 * discount),
period=renewal_invoice_period,
)
if plan.charge_automatically: if plan.charge_automatically:
collection_method: Literal["charge_automatically", "send_invoice"] = ( collection_method: Literal["charge_automatically", "send_invoice"] = (
"charge_automatically" "charge_automatically"
@@ -3332,6 +3293,57 @@ class BillingSession(ABC):
if days_until_due is not None: if days_until_due is not None:
invoice_params["days_until_due"] = days_until_due invoice_params["days_until_due"] = days_until_due
stripe_invoice = stripe.Invoice.create(**invoice_params) stripe_invoice = stripe.Invoice.create(**invoice_params)
if invoice_item_params.get("description") is not None:
invoice_period = stripe.InvoiceItem.CreateParamsPeriod(
start=datetime_to_timestamp(ledger_entry.event_time),
end=datetime_to_timestamp(
get_plan_renewal_or_end_date(plan, ledger_entry.event_time)
),
)
if ledger_entry.is_renewal:
renewal_invoice_period = invoice_period
invoice_item_params["currency"] = "usd"
invoice_item_params["discountable"] = False
invoice_item_params["period"] = invoice_period
invoice_item_params["idempotency_key"] = get_idempotency_key(ledger_entry)
assert stripe_invoice is not None
assert stripe_invoice.id is not None
invoice_item_params["invoice"] = stripe_invoice.id
stripe.InvoiceItem.create(**invoice_item_params)
# Update license base per ledger_entry.
licenses_base = ledger_entry.licenses
plan.invoiced_through = ledger_entry
flat_discount, flat_discounted_months = self.get_flat_discount_info(plan.customer)
if stripe_invoice is not None:
# Only apply discount if this invoice contains renewal of the plan.
if (
renewal_invoice_period is not None
and plan.fixed_price is None
and flat_discounted_months > 0
):
assert stripe_invoice.id is not None
num_months = (
12 if plan.billing_schedule == CustomerPlan.BILLING_SCHEDULE_ANNUAL else 1
)
flat_discounted_months = min(flat_discounted_months, num_months)
discount = flat_discount * flat_discounted_months
plan.customer.flat_discounted_months -= flat_discounted_months
plan.customer.save(update_fields=["flat_discounted_months"])
stripe.InvoiceItem.create(
invoice=stripe_invoice.id,
currency="usd",
customer=plan.customer.stripe_customer_id,
description=f"${cents_to_dollar_string(flat_discount)}/month new customer discount",
# Negative value to apply discount.
amount=(-1 * discount),
period=renewal_invoice_period,
)
stripe.Invoice.finalize_invoice(stripe_invoice) stripe.Invoice.finalize_invoice(stripe_invoice)
plan.invoicing_status = CustomerPlan.INVOICING_STATUS_DONE plan.invoicing_status = CustomerPlan.INVOICING_STATUS_DONE