MCPcopy
hub / github.com/uselotus/lotus / switch_plan

Method switch_plan

backend/metering_billing/models.py:3179–3302  ·  view source on GitHub ↗
(
        self,
        new_version,
        transfer_usage=True,
        invoice_now=True,
        component_fixed_charges_initial_units=None,
    )

Source from the content-addressed store, hash-verified

3177 return True
3178
3179 def switch_plan(
3180 self,
3181 new_version,
3182 transfer_usage=True,
3183 invoice_now=True,
3184 component_fixed_charges_initial_units=None,
3185 ):
3186 from metering_billing.invoice import generate_invoice
3187
3188 if component_fixed_charges_initial_units is None:
3189 component_fixed_charges_initial_units = []
3190 component_fixed_charges_initial_units = {
3191 d["metric"]: d["units"] for d in component_fixed_charges_initial_units
3192 }
3193 # when switching a plan, there's a few things we need to take into account:
3194 # 1. flat fees dont transfer. Just end them.
3195 # 2. what does it mean for usage to transfer? Does it just mean the billing records for the old plan are cancelled and new ones are created for the new plan with a start date the same as previously? In the case we used to charge for x but no longer do, then perhaps in that case we do charge? If we weren;t doing the whole reset frequency thing anymore it would be awesome because we could just switch which plan component it points at and have the already billed for be a part of that.
3196 now = now_utc()
3197 sr = SubscriptionRecord.objects.create(
3198 organization=self.organization,
3199 customer=self.customer,
3200 billing_plan=new_version,
3201 start_date=now + relativedelta(microseconds=1),
3202 end_date=self.end_date,
3203 auto_renew=self.auto_renew,
3204 )
3205 # current recurring_charge billing records must be canceled + billed
3206 for billing_record in self.billing_records.filter(
3207 recurring_charge__isnull=False, fully_billed=False
3208 ):
3209 # this is common enough that we made a method for it
3210 SubscriptionRecord._billing_record_cancel_protocol(
3211 billing_record, now, invoice_now=invoice_now
3212 )
3213 # and now we generate the new recurring_charge billing records
3214 for recurring_charge in new_version.recurring_charges.all():
3215 sr._create_recurring_charge_billing_records(recurring_charge)
3216 # same for component based billing records
3217 # so we're going to have to create a new billing record for each component, except if the metric coincides in the old plan and the new plan, then if transfer usage is true we have to do some wizardry to accomplish this
3218 # first a set of components we'll create from scratch... if we transfer usage from anywhere we'll remove it from this set
3219 pcs_to_create_charges_for = set(new_version.plan_components.all())
3220 # dict of metrics for convenience
3221 new_version_metrics_map = {
3222 x.billable_metric: x for x in pcs_to_create_charges_for
3223 }
3224 for billing_record in self.billing_records.filter(
3225 component__isnull=False, fully_billed=False
3226 ):
3227 component = billing_record.component
3228 # if not transferring usage, simple, just cancel the billing record same as above
3229 if not transfer_usage:
3230 SubscriptionRecord._billing_record_cancel_protocol(
3231 billing_record, now, invoice_now=invoice_now
3232 )
3233 else:
3234 metric = component.billable_metric
3235 if metric in new_version_metrics_map:
3236 # if the metric is in the new plan, we perform the surgery to switch the billing record to the new plan. Don't create from scratch.

Callers

nothing calls this directly

Calls 10

saveMethod · 0.95
now_utcFunction · 0.90
generate_invoiceFunction · 0.90
createMethod · 0.45
saveMethod · 0.45
deleteMethod · 0.45

Tested by

no test coverage detected