aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--generalresearch/gr_django/__init__.py0
-rw-r--r--generalresearch/gr_django/app/__init__.py0
-rw-r--r--generalresearch/gr_django/app/manage.py13
-rw-r--r--generalresearch/gr_django/app/settings.py24
-rw-r--r--generalresearch/gr_django/apps.py7
-rw-r--r--generalresearch/gr_django/migrations/0001_initial.py98
-rw-r--r--generalresearch/gr_django/migrations/0002_business_balance_business_balance_net_7d_and_more.py38
-rw-r--r--generalresearch/gr_django/migrations/__init__.py0
-rw-r--r--generalresearch/gr_django/models.py146
-rw-r--r--generalresearch/gr_django/readme.MD5
10 files changed, 331 insertions, 0 deletions
diff --git a/generalresearch/gr_django/__init__.py b/generalresearch/gr_django/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/generalresearch/gr_django/__init__.py
diff --git a/generalresearch/gr_django/app/__init__.py b/generalresearch/gr_django/app/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/generalresearch/gr_django/app/__init__.py
diff --git a/generalresearch/gr_django/app/manage.py b/generalresearch/gr_django/app/manage.py
new file mode 100644
index 0000000..77700ed
--- /dev/null
+++ b/generalresearch/gr_django/app/manage.py
@@ -0,0 +1,13 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+ os.environ.setdefault(
+ "DJANGO_SETTINGS_MODULE",
+ "generalresearch.gr_django.app.settings",
+ )
+
+ from django.core.management import execute_from_command_line
+
+ execute_from_command_line(sys.argv) \ No newline at end of file
diff --git a/generalresearch/gr_django/app/settings.py b/generalresearch/gr_django/app/settings.py
new file mode 100644
index 0000000..857870e
--- /dev/null
+++ b/generalresearch/gr_django/app/settings.py
@@ -0,0 +1,24 @@
+import os
+
+INSTALLED_APPS = [
+ "django.contrib.postgres",
+ "django.contrib.contenttypes",
+ "generalresearch.gr_django.apps.GRSchemaConfig",
+]
+
+DATABASES = {
+ "default": {
+ "ENGINE": "django.db.backends.postgresql",
+ "NAME": os.environ.get("GR_DB_NAME", "gr"),
+ "USER": os.environ.get("GR_DB_USER", "postgres"),
+ "PASSWORD": os.environ.get("GR_DB_PASSWORD", "password"),
+ "HOST": os.environ.get("GR_DB_HOST", "127.0.0.1"),
+ "PORT": os.environ.get("GR_DB_PORT", "5432"),
+ }
+}
+
+DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
+LANGUAGE_CODE = "en-us"
+TIME_ZONE = "UTC"
+USE_I18N = True
+USE_TZ = True \ No newline at end of file
diff --git a/generalresearch/gr_django/apps.py b/generalresearch/gr_django/apps.py
new file mode 100644
index 0000000..f6a2b62
--- /dev/null
+++ b/generalresearch/gr_django/apps.py
@@ -0,0 +1,7 @@
+from django.apps import AppConfig
+
+
+class GRSchemaConfig(AppConfig):
+ name = "generalresearch.gr_django"
+ label = "common" # preserves the existing gr-carer migration identity
+ default_auto_field = "django.db.models.BigAutoField" \ No newline at end of file
diff --git a/generalresearch/gr_django/migrations/0001_initial.py b/generalresearch/gr_django/migrations/0001_initial.py
new file mode 100644
index 0000000..712592b
--- /dev/null
+++ b/generalresearch/gr_django/migrations/0001_initial.py
@@ -0,0 +1,98 @@
+# Generated by Django 5.2.6 on 2025-09-26 19:41
+
+import django.db.models.deletion
+import uuid
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Business',
+ fields=[
+ ('id', models.BigAutoField(primary_key=True, serialize=False)),
+ ('uuid', models.UUIDField(default=uuid.uuid4, unique=True)),
+ ('kind', models.CharField(choices=[('i', 'Individual'), ('c', 'Company')], default='i', max_length=1)),
+ ('name', models.CharField(blank=True, max_length=255)),
+ ('tax_number', models.CharField(blank=True, max_length=20, null=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Membership',
+ fields=[
+ ('id', models.BigAutoField(primary_key=True, serialize=False)),
+ ('uuid', models.UUIDField(default=uuid.uuid4, unique=True)),
+ ('user_id', models.BigIntegerField(db_index=True, null=True)),
+ ('team_id', models.BigIntegerField(db_index=True, null=True)),
+ ('privilege', models.PositiveSmallIntegerField(choices=[(0, 'Admin'), (1, 'Maintain'), (2, 'Read')], default=1)),
+ ('owner', models.BooleanField(default=False)),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='User',
+ fields=[
+ ('id', models.BigAutoField(primary_key=True, serialize=False)),
+ ('sub', models.CharField(max_length=200)),
+ ('is_superuser', models.BooleanField(default=False)),
+ ('date_joined', models.DateTimeField(auto_now_add=True)),
+ ],
+ options={
+ 'db_table': 'gr_user',
+ },
+ ),
+ migrations.CreateModel(
+ name='UserToken',
+ fields=[
+ ('key', models.CharField(max_length=255, primary_key=True, serialize=False)),
+ ('user_id', models.BigIntegerField(db_index=True, null=True)),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ],
+ options={
+ 'db_table': 'gr_token',
+ },
+ ),
+ migrations.CreateModel(
+ name='BankAccount',
+ fields=[
+ ('id', models.BigAutoField(primary_key=True, serialize=False)),
+ ('uuid', models.UUIDField(default=uuid.uuid4, unique=True)),
+ ('transfer_method', models.PositiveSmallIntegerField(choices=[(0, 'ACH'), (1, 'Wire')], default=0)),
+ ('account_number', models.CharField(blank=True, max_length=50, null=True)),
+ ('routing_number', models.CharField(blank=True, max_length=50, null=True)),
+ ('iban', models.CharField(blank=True, max_length=50, null=True)),
+ ('swift', models.CharField(blank=True, max_length=50, null=True)),
+ ('business', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.business')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='BusinessAddress',
+ fields=[
+ ('id', models.BigAutoField(primary_key=True, serialize=False)),
+ ('uuid', models.UUIDField(default=uuid.uuid4, unique=True)),
+ ('line_1', models.CharField(blank=True, max_length=255, null=True)),
+ ('line_2', models.CharField(blank=True, max_length=255, null=True)),
+ ('city', models.CharField(blank=True, max_length=255, null=True)),
+ ('country', models.CharField(blank=True, max_length=2, null=True)),
+ ('state', models.CharField(blank=True, max_length=255, null=True)),
+ ('postal_code', models.CharField(blank=True, max_length=12, null=True)),
+ ('phone_number', models.CharField(max_length=20, null=True)),
+ ('business', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.business')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Team',
+ fields=[
+ ('id', models.BigAutoField(primary_key=True, serialize=False)),
+ ('uuid', models.UUIDField(default=uuid.uuid4, unique=True)),
+ ('name', models.CharField(blank=True, max_length=255, null=True)),
+ ('businesses', models.ManyToManyField(to='common.business')),
+ ],
+ ),
+ ]
diff --git a/generalresearch/gr_django/migrations/0002_business_balance_business_balance_net_7d_and_more.py b/generalresearch/gr_django/migrations/0002_business_balance_business_balance_net_7d_and_more.py
new file mode 100644
index 0000000..d355368
--- /dev/null
+++ b/generalresearch/gr_django/migrations/0002_business_balance_business_balance_net_7d_and_more.py
@@ -0,0 +1,38 @@
+# Generated by Django 6.1.1 on 2026-10-09 16:48
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('common', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='business',
+ name='balance',
+ field=models.JSONField(default=None, null=True),
+ ),
+ migrations.AddField(
+ model_name='business',
+ name='balance_net_7d',
+ field=models.IntegerField(default=None, null=True),
+ ),
+ migrations.AddField(
+ model_name='business',
+ name='task_completes_7d',
+ field=models.IntegerField(default=None, null=True),
+ ),
+ migrations.AddField(
+ model_name='business',
+ name='user_wallet_balance',
+ field=models.JSONField(default=None, null=True),
+ ),
+ migrations.AddField(
+ model_name='business',
+ name='users_active_7d',
+ field=models.IntegerField(default=None, null=True),
+ ),
+ ]
diff --git a/generalresearch/gr_django/migrations/__init__.py b/generalresearch/gr_django/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/generalresearch/gr_django/migrations/__init__.py
diff --git a/generalresearch/gr_django/models.py b/generalresearch/gr_django/models.py
new file mode 100644
index 0000000..01bf749
--- /dev/null
+++ b/generalresearch/gr_django/models.py
@@ -0,0 +1,146 @@
+import uuid
+
+from django.db import models
+
+
+class User(models.Model):
+ id = models.BigAutoField(primary_key=True)
+ sub = models.CharField(max_length=200, blank=False, null=False)
+
+ is_superuser = models.BooleanField(default=False)
+ date_joined = models.DateTimeField(auto_now_add=True)
+
+ class Meta:
+ db_table = "gr_user"
+
+
+class UserToken(models.Model):
+ key = models.CharField(max_length=255, primary_key=True)
+ user_id = models.BigIntegerField(null=True, db_index=True)
+ created = models.DateTimeField(auto_now_add=True)
+
+ class Meta:
+ db_table = "gr_token"
+
+
+class Membership(models.Model):
+ """
+ A User on generalresearch.com can be a member of many teams, that relationship can have different
+ permission to manage a team or accounts and business entities owned by that team
+ """
+
+ id = models.BigAutoField(primary_key=True)
+ uuid = models.UUIDField(default=uuid.uuid4, unique=True)
+
+ user_id = models.BigIntegerField(null=True, db_index=True)
+ team_id = models.BigIntegerField(null=True, db_index=True)
+
+ PRIVILEGES = (
+ (0, "Admin"),
+ (1, "Maintain"),
+ (2, "Read"),
+ )
+ privilege = models.PositiveSmallIntegerField(default=1, choices=PRIVILEGES)
+ owner = models.BooleanField(default=False)
+
+ created = models.DateTimeField(auto_now_add=True, null=False)
+
+
+class Team(models.Model):
+ """
+ This is a collection of users / accounts that work as a team and share
+ access to the same BPID However, an Organization can have many Bank
+ Accounts as each BPID doesn't need to deposit funds into the same Bank
+ account or Business
+ """
+
+ id = models.BigAutoField(primary_key=True)
+ uuid = models.UUIDField(default=uuid.uuid4, unique=True)
+
+ name = models.CharField(max_length=255, null=True, blank=True)
+
+ businesses = models.ManyToManyField(to="common.Business")
+
+
+class Business(models.Model):
+ """
+ A Team can manage multiple Businesses
+ A Business can have multiple Brokerage Products
+
+ # The IRS responsible entity that our accounts care about for issuing 1099s.
+ # We have this seperated from the Team as some Teams have different
+ # bank accounts + corporate entities for the activity of an app
+ """
+
+ id = models.BigAutoField(primary_key=True)
+ uuid = models.UUIDField(default=uuid.uuid4, unique=True)
+
+ BUSINESS_KINDS = (("i", "Individual"), ("c", "Company"))
+ kind = models.CharField(max_length=1, choices=BUSINESS_KINDS, default="i")
+ name = models.CharField(max_length=255, blank=True, null=False)
+
+ tax_number = models.CharField(max_length=20, blank=True, null=True)
+
+ # BusinessBalances model
+ balance = models.JSONField(default=None, null=True)
+ # BusinessUserWalletBalances model
+ user_wallet_balance = models.JSONField(default=None, null=True)
+
+ users_active_7d = models.IntegerField(default=None, null=True)
+ task_completes_7d = models.IntegerField(default=None, null=True)
+ # Net Earnings over the last 7 days (in USD Cents, this can be positive or negative)
+ balance_net_7d = models.IntegerField(default=None, null=True)
+
+
+class BusinessAddress(models.Model):
+ id = models.BigAutoField(primary_key=True)
+ uuid = models.UUIDField(default=uuid.uuid4, unique=True)
+
+ business = models.ForeignKey(
+ "common.Business",
+ null=True,
+ on_delete=models.SET_NULL,
+ )
+
+ # Location Details
+ line_1 = models.CharField(max_length=255, blank=True, null=True)
+ line_2 = models.CharField(max_length=255, blank=True, null=True)
+ city = models.CharField(max_length=255, blank=True, null=True)
+ country = models.CharField(
+ max_length=2, blank=True, null=True
+ ) # Validate this with pycountry
+ state = models.CharField(max_length=255, blank=True, null=True)
+ postal_code = models.CharField(max_length=12, blank=True, null=True)
+ phone_number = models.CharField(max_length=20, null=True)
+
+
+class BankAccount(models.Model):
+ """
+ A Business can have a single active Bank Account at the time.
+ This is used to deposit funds earned from the Business's Brokerage Products.
+ """
+
+ id = models.BigAutoField(primary_key=True)
+ uuid = models.UUIDField(default=uuid.uuid4, unique=True)
+
+ business = models.ForeignKey(
+ "common.Business",
+ null=True,
+ on_delete=models.SET_NULL,
+ )
+
+ TRANSFER_METHOD = (
+ (0, "ACH"),
+ (1, "Wire"),
+ )
+ transfer_method = models.PositiveSmallIntegerField(
+ choices=TRANSFER_METHOD, default=0
+ )
+
+ # ACH requirements
+ account_number = models.CharField(max_length=50, blank=True, null=True)
+ routing_number = models.CharField(max_length=50, blank=True, null=True)
+
+ # Wire requirements
+ iban = models.CharField(max_length=50, blank=True, null=True)
+ swift = models.CharField(max_length=50, blank=True, null=True)
diff --git a/generalresearch/gr_django/readme.MD b/generalresearch/gr_django/readme.MD
new file mode 100644
index 0000000..1a6e682
--- /dev/null
+++ b/generalresearch/gr_django/readme.MD
@@ -0,0 +1,5 @@
+Run migrations with:
+```shell
+python -m generalresearch.gr_django.app.manage makemigrations common
+python -m generalresearch.gr_django.app.manage migrate
+``` \ No newline at end of file