def should_be_billed(self, billing_date, generate_documents_datetime=None): if self.state not in [self.STATES.ACTIVE, self.STATES.CANCELED]: return False if not generate_documents_datetime: generate_documents_datetime = timezone.now() if self.cycle_billing_duration: if self.start_date > first_day_of_month(billing_date) + self.cycle_billing_duration: # There was nothing to bill on the last day of the first cycle billing duration return False # We need the full cycle here (ignoring trial ends) cycle_start_datetime_ignoring_trial = self._cycle_start_date(billing_date, ignore_trial=False) latest_possible_billing_datetime = ( cycle_start_datetime_ignoring_trial + self.cycle_billing_duration ) billing_date = min(billing_date, latest_possible_billing_datetime) if billing_date > generate_documents_datetime.date(): return False cycle_start_date = self.cycle_start_date(billing_date) if not cycle_start_date: return False if self.state == self.STATES.CANCELED: if billing_date <= self.cancel_date: return False cycle_start_date = self.cancel_date + ONE_DAY cycle_start_datetime = datetime.combine(cycle_start_date, datetime.min.time()).replace(tzinfo=utc) generate_after = timedelta(seconds=self.plan.generate_after) if generate_documents_datetime < cycle_start_datetime + generate_after: return False billed_up_to_dates = self.billed_up_to_dates plan_billed_up_to = billed_up_to_dates['plan_billed_up_to'] metered_features_billed_up_to = billed_up_to_dates['metered_features_billed_up_to'] # We want to bill the subscription if the plan hasn't been billed for this cycle or # if the subscription has been canceled and the plan won't be billed for this cycle. if self.prebill_plan or self.state == self.STATES.CANCELED: plan_should_be_billed = plan_billed_up_to < cycle_start_date if self.state == self.STATES.CANCELED: return metered_features_billed_up_to < cycle_start_date or plan_should_be_billed return plan_should_be_billed # wait until the cycle that is going to be billed ends: billed_cycle_end_date = self.cycle_end_date(plan_billed_up_to + ONE_DAY) return billed_cycle_end_date < cycle_start_date