(
self,
new_version,
transfer_usage=True,
invoice_now=True,
component_fixed_charges_initial_units=None,
)
| 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. |
nothing calls this directly
no test coverage detected