Skip to content
Merged

Dev #62

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
3a52a99
chore(deps): bump python-dotenv from 1.0.1 to 1.2.2
dependabot[bot] Aug 4, 2026
b7dd800
chore(deps): bump requests from 2.31.0 to 2.33.0
dependabot[bot] Aug 4, 2026
df4d3a4
chore(deps): bump django from 5.0.6 to 5.1.15
dependabot[bot] Aug 4, 2026
8aa0a7e
chore(deps): bump cryptography from 43.0.3 to 50.0.0
dependabot[bot] Aug 4, 2026
1e0caa3
feat: implement migration file for billing
ngovinh2k2 Aug 17, 2026
7c698e9
Merge pull request #38 from Space-DF/feat/implement-migration-for-bil…
ngovinh2k2 Aug 17, 2026
1f6d197
feat: implement get plans api
ngovinh2k2 Aug 17, 2026
bdde3e3
Merge pull request #39 from Space-DF/feat/implement-get-plans
ngovinh2k2 Aug 17, 2026
1a42ce9
feat: create default subscription on org creation
ngovinh2k2 Aug 17, 2026
2dbac5b
Merge pull request #40 from Space-DF/feat/org-default-subscription
ngovinh2k2 Aug 17, 2026
a4e4a9d
feat: update the org check api to specify plan type
ngovinh2k2 Aug 17, 2026
e1b2487
Merge pull request #41 from Space-DF/feat/update-org-check-api-specif…
ngovinh2k2 Aug 17, 2026
7f6a99d
feat: seed default plans, features
ngovinh2k2 Aug 17, 2026
4dcc842
Merge pull request #42 from Space-DF/feat/set-default-plans-features
ngovinh2k2 Aug 17, 2026
7f015b0
chore: update plan model
ngovinh2k2 Aug 17, 2026
2a32cc6
Merge pull request #43 from Space-DF/chore/update-plan-model
ngovinh2k2 Aug 17, 2026
00b5e49
fix: add plan field in the org response
ngovinh2k2 Aug 17, 2026
12bc4dc
Merge pull request #44 from Space-DF/fix/add-plan-field-in-the-org-re…
ngovinh2k2 Aug 17, 2026
17f2f4a
fix: add is_current_plan field for api get plan
ngovinh2k2 Aug 17, 2026
a3dd802
Merge pull request #45 from Space-DF/fix/add-is_current_plan-field-fo…
ngovinh2k2 Aug 17, 2026
5481af8
feat: plan limit enforcement
ngovinh2k2 Aug 17, 2026
7443998
Merge pull request #46 from Space-DF/feat/plan-limit-enforcement
ngovinh2k2 Aug 17, 2026
b5264dc
feat: implement api to get detail plan
ngovinh2k2 Aug 17, 2026
6abbae0
Merge pull request #47 from Space-DF/feat/implement-api-to-get-detail…
ngovinh2k2 Aug 17, 2026
e4266a9
feat: downgrade subscription when its expired
ngovinh2k2 Aug 17, 2026
748886b
Merge pull request #48 from Space-DF/feat/downgrading-subscription
ngovinh2k2 Aug 17, 2026
a52d6c1
feat: implement contact sales api
ngovinh2k2 Aug 17, 2026
fdde7bf
Merge pull request #49 from Space-DF/feat/implement-contact-sales
ngovinh2k2 Aug 17, 2026
c1144e1
fix: auth space quota scopes
ngovinh2k2 Aug 17, 2026
d620dcd
Merge pull request #50 from Space-DF/fix/quota-scopes
ngovinh2k2 Aug 17, 2026
39c14c3
chore: quota org header period
ngovinh2k2 Aug 17, 2026
e488830
fix: ci issue
ngovinh2k2 Aug 17, 2026
ba8587a
Merge pull request #51 from Space-DF/chore/quota-org-header-period
ngovinh2k2 Aug 17, 2026
4b18f4a
chore: subscription cancel to free
ngovinh2k2 Aug 17, 2026
e67ba37
Merge pull request #52 from Space-DF/chore/subscription-cancel-to-free
ngovinh2k2 Aug 17, 2026
db9a902
feat: add downgrade date
ngovinh2k2 Aug 17, 2026
797cedb
Merge pull request #53 from Space-DF/feat/add-downgrade-date
ngovinh2k2 Aug 17, 2026
21cb76c
feat: implement subscription email templates
ngovinh2k2 Aug 17, 2026
9e3b81c
Merge pull request #54 from Space-DF/feat/implement-subscription-emai…
ngovinh2k2 Aug 17, 2026
e8108ad
feat:implement the default settings for water level
ngovinh2k2 Aug 17, 2026
f3853c5
Merge pull request #55 from Space-DF/feat/implement-the-default-setti…
ngovinh2k2 Aug 17, 2026
e31e3e5
chore: add organization monitoring user
ngovinh2k2 Aug 17, 2026
7daad84
Merge pull request #56 from Space-DF/chore/add-organization-monitorin…
ngovinh2k2 Aug 17, 2026
630d66f
feat: implement quota mixins
ngovinh2k2 Aug 18, 2026
4a2093a
Merge pull request #57 from Space-DF/feat/implement-quota-mixins
ngovinh2k2 Aug 18, 2026
6d0af7a
feat: subscription lifecycle routing
ngovinh2k2 Aug 18, 2026
806f449
Merge pull request #58 from Space-DF/feat/subscription-lifecycle-routing
ngovinh2k2 Aug 18, 2026
f84834a
fix: use organization settings for custom pages and emails
ngovinh2k2 Aug 18, 2026
d6ce68c
Merge pull request #59 from Space-DF/fix/use-organization-settings-fo…
ngovinh2k2 Aug 18, 2026
1bb3ad3
fix: cant create new org
ngovinh2k2 Aug 18, 2026
8e3312c
Merge pull request #60 from Space-DF/fix/cant-create-new-org
ngovinh2k2 Aug 18, 2026
07f7d06
Merge pull request #37 from Space-DF/dependabot/pip/cryptography-50.0.0
ngovinh2k2 Aug 18, 2026
35d59fc
Merge pull request #36 from Space-DF/dependabot/pip/django-5.1.15
ngovinh2k2 Aug 18, 2026
c60aa2f
Merge pull request #35 from Space-DF/dependabot/pip/requests-2.33.0
ngovinh2k2 Aug 18, 2026
ef7d134
Merge branch 'dev' into dependabot/pip/python-dotenv-1.2.2
ngovinh2k2 Aug 18, 2026
30ac969
Merge pull request #34 from Space-DF/dependabot/pip/python-dotenv-1.2.2
ngovinh2k2 Aug 18, 2026
8e1ea03
chore: update python dependencies
ngovinh2k2 Aug 18, 2026
311172f
Merge pull request #61 from Space-DF/chore/update-python-dependencies
ngovinh2k2 Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added apps/billing/__init__.py
Empty file.
10 changes: 10 additions & 0 deletions apps/billing/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from django.apps import AppConfig


class BillingConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.billing"

def ready(self):
# Importing tasks connects the task_failure signal handler defined there.
from apps.billing import tasks # noqa: F401
34 changes: 34 additions & 0 deletions apps/billing/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from django.db import models


class PlanCodeType:
# Plan code used as the default when provisioning a new organization.
FREE = "free"
PRO = "pro"


class CurrencyType(models.TextChoices):
USD = "USD"
VND = "VND"


class BillingCycle(models.TextChoices):
MONTHLY = "monthly"
YEARLY = "yearly"


class FeatureValueType(models.TextChoices):
BOOLEAN = "boolean"
LIMIT = "limit"
QUOTA = "quota"


class UsageType(models.TextChoices):
RESOURCE = "resource"
PERIOD = "period"


BILLING_CYCLE_DAYS = {
BillingCycle.MONTHLY: 30,
BillingCycle.YEARLY: 365,
}
295 changes: 295 additions & 0 deletions apps/billing/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
# Generated by Django 5.0.6 on 2026-07-08 08:19

import django.core.validators
import django.db.models.deletion
import uuid
from django.db import migrations, models


class Migration(migrations.Migration):
initial = True

dependencies = [
("organization", "0004_alter_organization_template"),
]

operations = [
migrations.CreateModel(
name="Feature",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("code", models.CharField(max_length=128, unique=True)),
("name", models.CharField(max_length=256)),
("description", models.TextField(blank=True)),
(
"value_type",
models.CharField(
choices=[
("boolean", "Boolean"),
("limit", "Limit"),
("quota", "Quota"),
],
max_length=16,
),
),
],
options={
"db_table": "features",
},
),
migrations.CreateModel(
name="Plan",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("name", models.CharField(max_length=256)),
("code", models.CharField(max_length=64, unique=True)),
("description", models.TextField(blank=True)),
],
options={
"db_table": "plans",
},
),
migrations.CreateModel(
name="PlanItem",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"price",
models.DecimalField(
decimal_places=2,
default=0,
max_digits=10,
validators=[django.core.validators.MinValueValidator(0)],
),
),
("icon", models.CharField(blank=True, default="", max_length=256)),
(
"currency",
models.CharField(
choices=[("USD", "Usd"), ("VND", "Vnd")],
default="USD",
max_length=8,
),
),
(
"discount",
models.IntegerField(
default=0,
validators=[
django.core.validators.MinValueValidator(0),
django.core.validators.MaxValueValidator(100),
],
),
),
(
"billing_cycle",
models.CharField(
choices=[("monthly", "Monthly"), ("yearly", "Yearly")],
default="monthly",
max_length=16,
),
),
("is_active", models.BooleanField(default=True)),
(
"plan",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="plan_items",
to="billing.plan",
),
),
],
options={
"db_table": "plan_items",
},
),
migrations.CreateModel(
name="PlanFeature",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("enabled", models.BooleanField(default=True)),
(
"limit_value",
models.IntegerField(
blank=True,
null=True,
validators=[django.core.validators.MinValueValidator(0)],
),
),
("metadata", models.JSONField(blank=True, default=dict)),
(
"feature",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="plan_features",
to="billing.feature",
),
),
(
"plan",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="plan_features",
to="billing.plan",
),
),
],
options={
"db_table": "plan_features",
},
),
migrations.CreateModel(
name="Subscription",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("period_start", models.DateTimeField()),
("period_end", models.DateTimeField()),
(
"organization",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="subscriptions",
to="organization.organization",
),
),
(
"plan_item",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="subscriptions",
to="billing.planitem",
),
),
],
options={
"db_table": "subscriptions",
},
),
migrations.CreateModel(
name="FeatureUsage",
fields=[
(
"id",
models.UUIDField(
default=uuid.uuid4,
editable=False,
primary_key=True,
serialize=False,
unique=True,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"usage_type",
models.CharField(
choices=[("resource", "Resource"), ("period", "Period")],
max_length=16,
),
),
(
"used_value",
models.BigIntegerField(
default=0,
validators=[django.core.validators.MinValueValidator(0)],
),
),
("billing_period", models.DateField()),
(
"feature",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="feature_usages",
to="billing.feature",
),
),
(
"subscription",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="feature_usages",
to="billing.subscription",
),
),
],
options={
"db_table": "feature_usages",
},
),
migrations.AddConstraint(
model_name="planfeature",
constraint=models.UniqueConstraint(
fields=("plan", "feature"), name="unique_plan_feature"
),
),
migrations.AddConstraint(
model_name="planitem",
constraint=models.UniqueConstraint(
fields=("plan", "billing_cycle"), name="unique_plan_billing_cycle"
),
),
migrations.AddConstraint(
model_name="subscription",
constraint=models.CheckConstraint(
check=models.Q(("period_end__gt", models.F("period_start"))),
name="subscription_period_end_after_period_start",
),
),
]
Loading
Loading