mirror of https://github.com/zulip/zulip.git
billing: Adding invoicing fields to CustomerPlan.
This commit is contained in:
parent
fe280fc38c
commit
421cda0e34
|
@ -231,10 +231,10 @@ def compute_plan_parameters(
|
||||||
if discount is not None:
|
if discount is not None:
|
||||||
# There are no fractional cents in Stripe, so round down to nearest integer.
|
# There are no fractional cents in Stripe, so round down to nearest integer.
|
||||||
price_per_license = int(float(price_per_license * (1 - discount / 100)) + .00001)
|
price_per_license = int(float(price_per_license * (1 - discount / 100)) + .00001)
|
||||||
next_billing_date = period_end
|
next_invoice_date = period_end
|
||||||
if automanage_licenses:
|
if automanage_licenses:
|
||||||
next_billing_date = add_months(billing_cycle_anchor, 1)
|
next_invoice_date = add_months(billing_cycle_anchor, 1)
|
||||||
return billing_cycle_anchor, next_billing_date, period_end, price_per_license
|
return billing_cycle_anchor, next_invoice_date, period_end, price_per_license
|
||||||
|
|
||||||
# Only used for cloud signups
|
# Only used for cloud signups
|
||||||
@catch_stripe_errors
|
@catch_stripe_errors
|
||||||
|
@ -251,7 +251,7 @@ def process_initial_upgrade(user: UserProfile, licenses: int, automanage_license
|
||||||
"Customer {} trying to upgrade, but has an active subscription".format(customer))
|
"Customer {} trying to upgrade, but has an active subscription".format(customer))
|
||||||
raise BillingError('subscribing with existing subscription', BillingError.TRY_RELOADING)
|
raise BillingError('subscribing with existing subscription', BillingError.TRY_RELOADING)
|
||||||
|
|
||||||
billing_cycle_anchor, next_billing_date, period_end, price_per_license = compute_plan_parameters(
|
billing_cycle_anchor, next_invoice_date, period_end, price_per_license = compute_plan_parameters(
|
||||||
automanage_licenses, billing_schedule, customer.default_discount)
|
automanage_licenses, billing_schedule, customer.default_discount)
|
||||||
# The main design constraint in this function is that if you upgrade with a credit card, and the
|
# The main design constraint in this function is that if you upgrade with a credit card, and the
|
||||||
# charge fails, everything should be rolled back as if nothing had happened. This is because we
|
# charge fails, everything should be rolled back as if nothing had happened. This is because we
|
||||||
|
@ -294,15 +294,16 @@ def process_initial_upgrade(user: UserProfile, licenses: int, automanage_license
|
||||||
customer=customer,
|
customer=customer,
|
||||||
# Deprecated, remove
|
# Deprecated, remove
|
||||||
licenses=-1,
|
licenses=-1,
|
||||||
billed_through=billing_cycle_anchor,
|
next_invoice_date=next_invoice_date,
|
||||||
next_billing_date=next_billing_date,
|
|
||||||
**plan_params)
|
**plan_params)
|
||||||
LicenseLedger.objects.create(
|
ledger_entry = LicenseLedger.objects.create(
|
||||||
plan=plan,
|
plan=plan,
|
||||||
is_renewal=True,
|
is_renewal=True,
|
||||||
event_time=billing_cycle_anchor,
|
event_time=billing_cycle_anchor,
|
||||||
licenses=billed_licenses,
|
licenses=billed_licenses,
|
||||||
licenses_at_next_renewal=billed_licenses)
|
licenses_at_next_renewal=billed_licenses)
|
||||||
|
plan.invoiced_through = ledger_entry
|
||||||
|
plan.save(update_fields=['invoiced_through'])
|
||||||
RealmAuditLog.objects.create(
|
RealmAuditLog.objects.create(
|
||||||
realm=realm, acting_user=user, event_time=billing_cycle_anchor,
|
realm=realm, acting_user=user, event_time=billing_cycle_anchor,
|
||||||
event_type=RealmAuditLog.CUSTOMER_PLAN_CREATED,
|
event_type=RealmAuditLog.CUSTOMER_PLAN_CREATED,
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.18 on 2019-01-28 13:04
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('corporate', '0004_licenseledger'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='customerplan',
|
||||||
|
old_name='next_billing_date',
|
||||||
|
new_name='next_invoice_date',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='customerplan',
|
||||||
|
name='billed_through',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerplan',
|
||||||
|
name='invoiced_through',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='corporate.LicenseLedger'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='customerplan',
|
||||||
|
name='invoicing_status',
|
||||||
|
field=models.SmallIntegerField(default=1),
|
||||||
|
),
|
||||||
|
]
|
|
@ -39,9 +39,12 @@ class CustomerPlan(models.Model):
|
||||||
MONTHLY = 2
|
MONTHLY = 2
|
||||||
billing_schedule = models.SmallIntegerField() # type: int
|
billing_schedule = models.SmallIntegerField() # type: int
|
||||||
|
|
||||||
# This is like analytic's FillState, but for billing
|
next_invoice_date = models.DateTimeField(db_index=True) # type: datetime.datetime
|
||||||
billed_through = models.DateTimeField() # type: datetime.datetime
|
invoiced_through = models.ForeignKey(
|
||||||
next_billing_date = models.DateTimeField(db_index=True) # type: datetime.datetime
|
'LicenseLedger', null=True, on_delete=CASCADE, related_name='+') # type: Optional[LicenseLedger]
|
||||||
|
DONE = 1
|
||||||
|
STARTED = 2
|
||||||
|
invoicing_status = models.SmallIntegerField(default=DONE) # type: int
|
||||||
|
|
||||||
STANDARD = 1
|
STANDARD = 1
|
||||||
PLUS = 2 # not available through self-serve signup
|
PLUS = 2 # not available through self-serve signup
|
||||||
|
|
|
@ -392,8 +392,8 @@ class StripeTest(StripeTestCase):
|
||||||
plan = CustomerPlan.objects.get(
|
plan = CustomerPlan.objects.get(
|
||||||
customer=customer, automanage_licenses=True,
|
customer=customer, automanage_licenses=True,
|
||||||
price_per_license=8000, fixed_price=None, discount=None, billing_cycle_anchor=self.now,
|
price_per_license=8000, fixed_price=None, discount=None, billing_cycle_anchor=self.now,
|
||||||
billing_schedule=CustomerPlan.ANNUAL, billed_through=self.now,
|
billing_schedule=CustomerPlan.ANNUAL, invoiced_through=LicenseLedger.objects.first(),
|
||||||
next_billing_date=self.next_month, tier=CustomerPlan.STANDARD,
|
next_invoice_date=self.next_month, tier=CustomerPlan.STANDARD,
|
||||||
status=CustomerPlan.ACTIVE)
|
status=CustomerPlan.ACTIVE)
|
||||||
LicenseLedger.objects.get(
|
LicenseLedger.objects.get(
|
||||||
plan=plan, is_renewal=True, event_time=self.now, licenses=self.seat_count,
|
plan=plan, is_renewal=True, event_time=self.now, licenses=self.seat_count,
|
||||||
|
@ -477,8 +477,8 @@ class StripeTest(StripeTestCase):
|
||||||
plan = CustomerPlan.objects.get(
|
plan = CustomerPlan.objects.get(
|
||||||
customer=customer, automanage_licenses=False, charge_automatically=False,
|
customer=customer, automanage_licenses=False, charge_automatically=False,
|
||||||
price_per_license=8000, fixed_price=None, discount=None, billing_cycle_anchor=self.now,
|
price_per_license=8000, fixed_price=None, discount=None, billing_cycle_anchor=self.now,
|
||||||
billing_schedule=CustomerPlan.ANNUAL, billed_through=self.now,
|
billing_schedule=CustomerPlan.ANNUAL, invoiced_through=LicenseLedger.objects.first(),
|
||||||
next_billing_date=self.next_year, tier=CustomerPlan.STANDARD,
|
next_invoice_date=self.next_year, tier=CustomerPlan.STANDARD,
|
||||||
status=CustomerPlan.ACTIVE)
|
status=CustomerPlan.ACTIVE)
|
||||||
LicenseLedger.objects.get(
|
LicenseLedger.objects.get(
|
||||||
plan=plan, is_renewal=True, event_time=self.now, licenses=123, licenses_at_next_renewal=123)
|
plan=plan, is_renewal=True, event_time=self.now, licenses=123, licenses_at_next_renewal=123)
|
||||||
|
|
Loading…
Reference in New Issue