mirror of https://github.com/zulip/zulip.git
models: Move billing models from zilencer to corporate.
This commit is contained in:
parent
d77a4c776d
commit
d8c19cb003
|
@ -18,7 +18,7 @@ from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime
|
|||
from zerver.lib.utils import generate_random_token
|
||||
from zerver.lib.actions import do_change_plan_type
|
||||
from zerver.models import Realm, UserProfile, RealmAuditLog
|
||||
from zilencer.models import Customer, Plan, Coupon, BillingProcessor
|
||||
from corporate.models import Customer, Plan, Coupon, BillingProcessor
|
||||
from zproject.settings import get_secret
|
||||
|
||||
STRIPE_PUBLISHABLE_KEY = get_secret('stripe_publishable_key')
|
||||
|
|
|
@ -17,7 +17,7 @@ from zerver.lib.context_managers import lockfile
|
|||
from zerver.lib.management import sleep_forever
|
||||
from corporate.lib.stripe import StripeConnectionError, \
|
||||
run_billing_processor_one_step
|
||||
from zilencer.models import BillingProcessor
|
||||
from corporate.models import BillingProcessor
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = """Run BillingProcessors, to sync billing-relevant updates into Stripe.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from zerver.lib.management import ZulipBaseCommand
|
||||
from zilencer.models import Plan, Coupon, Customer
|
||||
from corporate.models import Plan, Coupon, Customer
|
||||
from zproject.settings import get_secret
|
||||
|
||||
from typing import Any
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.14 on 2018-09-25 12:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('zerver', '0189_userprofile_add_some_emojisets'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BillingProcessor',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('state', models.CharField(max_length=20)),
|
||||
('last_modified', models.DateTimeField(auto_now=True)),
|
||||
('log_row', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='zerver.RealmAuditLog')),
|
||||
('realm', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='zerver.Realm')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Coupon',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('percent_off', models.SmallIntegerField(unique=True)),
|
||||
('stripe_coupon_id', models.CharField(max_length=255, unique=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Customer',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('stripe_customer_id', models.CharField(max_length=255, unique=True)),
|
||||
('has_billing_relationship', models.BooleanField(default=False)),
|
||||
('realm', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='zerver.Realm')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Plan',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('nickname', models.CharField(max_length=40, unique=True)),
|
||||
('stripe_plan_id', models.CharField(max_length=255, unique=True)),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -0,0 +1,46 @@
|
|||
import datetime
|
||||
|
||||
from django.db import models
|
||||
|
||||
from zerver.models import Realm, RealmAuditLog
|
||||
|
||||
class Customer(models.Model):
|
||||
realm = models.OneToOneField(Realm, on_delete=models.CASCADE) # type: Realm
|
||||
stripe_customer_id = models.CharField(max_length=255, unique=True) # type: str
|
||||
# Becomes True the first time a payment successfully goes through, and never
|
||||
# goes back to being False
|
||||
has_billing_relationship = models.BooleanField(default=False) # type: bool
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "<Customer %s %s>" % (self.realm, self.stripe_customer_id)
|
||||
|
||||
class Plan(models.Model):
|
||||
# The two possible values for nickname
|
||||
CLOUD_MONTHLY = 'monthly'
|
||||
CLOUD_ANNUAL = 'annual'
|
||||
nickname = models.CharField(max_length=40, unique=True) # type: str
|
||||
|
||||
stripe_plan_id = models.CharField(max_length=255, unique=True) # type: str
|
||||
|
||||
class Coupon(models.Model):
|
||||
percent_off = models.SmallIntegerField(unique=True) # type: int
|
||||
stripe_coupon_id = models.CharField(max_length=255, unique=True) # type: str
|
||||
|
||||
def __str__(self) -> str:
|
||||
return '<Coupon: %s %s %s>' % (self.percent_off, self.stripe_coupon_id, self.id)
|
||||
|
||||
class BillingProcessor(models.Model):
|
||||
log_row = models.ForeignKey(RealmAuditLog, on_delete=models.CASCADE) # RealmAuditLog
|
||||
# Exactly one processor, the global processor, has realm=None.
|
||||
realm = models.OneToOneField(Realm, null=True, on_delete=models.CASCADE) # type: Realm
|
||||
|
||||
DONE = 'done'
|
||||
STARTED = 'started'
|
||||
SKIPPED = 'skipped' # global processor only
|
||||
STALLED = 'stalled' # realm processors only
|
||||
state = models.CharField(max_length=20) # type: str
|
||||
|
||||
last_modified = models.DateTimeField(auto_now=True) # type: datetime.datetime
|
||||
|
||||
def __str__(self) -> str:
|
||||
return '<BillingProcessor: %s %s %s>' % (self.realm, self.log_row, self.id)
|
|
@ -21,7 +21,7 @@ from corporate.lib.stripe import catch_stripe_errors, \
|
|||
get_seat_count, extract_current_subscription, sign_string, unsign_string, \
|
||||
get_next_billing_log_entry, run_billing_processor_one_step, \
|
||||
BillingError, StripeCardError, StripeConnectionError
|
||||
from zilencer.models import Customer, Plan, Coupon, BillingProcessor
|
||||
from corporate.models import Customer, Plan, Coupon, BillingProcessor
|
||||
|
||||
fixture_data_file = open(os.path.join(os.path.dirname(__file__), 'stripe_fixtures.json'), 'r')
|
||||
fixture_data = ujson.load(fixture_data_file)
|
||||
|
|
|
@ -19,7 +19,7 @@ from corporate.lib.stripe import STRIPE_PUBLISHABLE_KEY, \
|
|||
stripe_get_customer, stripe_get_upcoming_invoice, get_seat_count, \
|
||||
extract_current_subscription, process_initial_upgrade, sign_string, \
|
||||
unsign_string, BillingError, process_downgrade, do_replace_payment_source
|
||||
from zilencer.models import Customer, Plan
|
||||
from corporate.models import Customer, Plan
|
||||
|
||||
billing_logger = logging.getLogger('corporate.stripe')
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ To set up the development environment to work on the billing code:
|
|||
|
||||
It is safe to run `manage.py setup_stripe` multiple times.
|
||||
|
||||
Nearly all the billing-relevant code lives in `zilencer/`.
|
||||
Nearly all the billing-relevant code lives in `corporate/`.
|
||||
|
||||
## General architecture
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ from zerver.models import (
|
|||
flush_per_request_caches, DefaultStream, Realm,
|
||||
)
|
||||
from zerver.views.home import home, sent_time_in_epoch_seconds
|
||||
from zilencer.models import Customer
|
||||
from corporate.models import Customer
|
||||
|
||||
class HomeTest(ZulipTestCase):
|
||||
def test_home(self) -> None:
|
||||
|
|
|
@ -250,8 +250,8 @@ def home_real(request: HttpRequest) -> HttpResponse:
|
|||
|
||||
show_billing = False
|
||||
show_plans = False
|
||||
if settings.ZILENCER_ENABLED:
|
||||
from zilencer.models import Customer
|
||||
if settings.CORPORATE_ENABLED:
|
||||
from corporate.models import Customer
|
||||
if user_profile.is_billing_admin or user_profile.is_realm_admin:
|
||||
customer = Customer.objects.filter(realm=user_profile.realm).first()
|
||||
if customer is not None and customer.has_billing_relationship:
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.14 on 2018-09-25 12:01
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('zilencer', '0014_cleanup_pushdevicetoken'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='billingprocessor',
|
||||
name='log_row',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='billingprocessor',
|
||||
name='realm',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Coupon',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='customer',
|
||||
name='realm',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Plan',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='BillingProcessor',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Customer',
|
||||
),
|
||||
]
|
|
@ -2,8 +2,7 @@ import datetime
|
|||
|
||||
from django.db import models
|
||||
|
||||
from zerver.models import AbstractPushDeviceToken, Realm, UserProfile, \
|
||||
RealmAuditLog
|
||||
from zerver.models import AbstractPushDeviceToken
|
||||
|
||||
def get_remote_server_by_uuid(uuid: str) -> 'RemoteZulipServer':
|
||||
return RemoteZulipServer.objects.get(uuid=uuid)
|
||||
|
@ -35,44 +34,3 @@ class RemotePushDeviceToken(AbstractPushDeviceToken):
|
|||
|
||||
def __str__(self) -> str:
|
||||
return "<RemotePushDeviceToken %s %s>" % (self.server, self.user_id)
|
||||
|
||||
class Customer(models.Model):
|
||||
realm = models.OneToOneField(Realm, on_delete=models.CASCADE) # type: Realm
|
||||
stripe_customer_id = models.CharField(max_length=255, unique=True) # type: str
|
||||
# Becomes True the first time a payment successfully goes through, and never
|
||||
# goes back to being False
|
||||
has_billing_relationship = models.BooleanField(default=False) # type: bool
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "<Customer %s %s>" % (self.realm, self.stripe_customer_id)
|
||||
|
||||
class Plan(models.Model):
|
||||
# The two possible values for nickname
|
||||
CLOUD_MONTHLY = 'monthly'
|
||||
CLOUD_ANNUAL = 'annual'
|
||||
nickname = models.CharField(max_length=40, unique=True) # type: str
|
||||
|
||||
stripe_plan_id = models.CharField(max_length=255, unique=True) # type: str
|
||||
|
||||
class Coupon(models.Model):
|
||||
percent_off = models.SmallIntegerField(unique=True) # type: int
|
||||
stripe_coupon_id = models.CharField(max_length=255, unique=True) # type: str
|
||||
|
||||
def __str__(self) -> str:
|
||||
return '<Coupon: %s %s %s>' % (self.percent_off, self.stripe_coupon_id, self.id)
|
||||
|
||||
class BillingProcessor(models.Model):
|
||||
log_row = models.ForeignKey(RealmAuditLog, on_delete=models.CASCADE) # RealmAuditLog
|
||||
# Exactly one processor, the global processor, has realm=None.
|
||||
realm = models.OneToOneField(Realm, null=True, on_delete=models.CASCADE) # type: Realm
|
||||
|
||||
DONE = 'done'
|
||||
STARTED = 'started'
|
||||
SKIPPED = 'skipped' # global processor only
|
||||
STALLED = 'stalled' # realm processors only
|
||||
state = models.CharField(max_length=20) # type: str
|
||||
|
||||
last_modified = models.DateTimeField(auto_now=True) # type: datetime.datetime
|
||||
|
||||
def __str__(self) -> str:
|
||||
return '<BillingProcessor: %s %s %s>' % (self.realm, self.log_row, self.id)
|
||||
|
|
|
@ -575,6 +575,7 @@ if USING_PGROONGA:
|
|||
INSTALLED_APPS += EXTRA_INSTALLED_APPS
|
||||
|
||||
ZILENCER_ENABLED = 'zilencer' in INSTALLED_APPS
|
||||
CORPORATE_ENABLED = 'corporate' in INSTALLED_APPS
|
||||
|
||||
# Base URL of the Tornado server
|
||||
# We set it to None when running backend tests or populate_db.
|
||||
|
|
Loading…
Reference in New Issue