From 4e9e08718884b1c4394d16055ba3f30c790ef8d0 Mon Sep 17 00:00:00 2001 From: Max Nanis Date: Tue, 1 Sep 2026 16:58:01 -0700 Subject: Latest state for Django Migrations / Discussion --- generalresearch/grliq/managers/forensic_results.py | 6 +-- generalresearch/models/gr/business.py | 4 +- .../0010_supplierpayout_payout_supplier_payout.py | 51 ++++++++++++++++++++ test_utils/conftest.py | 51 ++++++++++++-------- test_utils/managers/gr/conftest.py | 2 + test_utils/managers/thl/conftest.py | 34 +++++++------ test_utils/models/gr/conftest.py | 55 ++++++++++++++-------- tests/managers/gr/test_business.py | 10 ++-- tests/models/gr/test_business.py | 23 +++++---- tests/test_postgres.py | 13 ++++- 10 files changed, 171 insertions(+), 78 deletions(-) create mode 100644 generalresearch/thl_django/migrations/0010_supplierpayout_payout_supplier_payout.py diff --git a/generalresearch/grliq/managers/forensic_results.py b/generalresearch/grliq/managers/forensic_results.py index 587b768..158e582 100644 --- a/generalresearch/grliq/managers/forensic_results.py +++ b/generalresearch/grliq/managers/forensic_results.py @@ -1,17 +1,15 @@ from collections.abc import Collection from datetime import datetime -from typing import TYPE_CHECKING, Any +from typing import Any from generalresearch.grliq.models.forensic_result import ( GrlIqForensicCategoryResult, Phase, ) from generalresearch.grliq.models.useragents import GrlUserAgent +from generalresearch.models.thl.user import User from generalresearch.pg_helper import PostgresConfig -if TYPE_CHECKING: - from generalresearch.models.thl.user import User - class GrlIqCategoryResultsReader: def __init__(self, postgres_config: PostgresConfig): diff --git a/generalresearch/models/gr/business.py b/generalresearch/models/gr/business.py index b01c902..73a2f27 100644 --- a/generalresearch/models/gr/business.py +++ b/generalresearch/models/gr/business.py @@ -449,7 +449,7 @@ class Business(BaseModel): def prebuild_pop_financial( self, - thl_pg_config: PostgresConfig, + product_manager: ProductManager, thl_lm: ThlLedgerManager, ds: GRLDatasets, client: DaskClient, @@ -461,7 +461,7 @@ class Business(BaseModel): financial activity within that time window. """ if self.bp_accounts is None: - self.prefetch_bp_accounts(thl_lm=thl_lm, thl_pg_config=thl_pg_config) + self.prefetch_bp_accounts(thl_lm=thl_lm, product_manager=product_manager) from generalresearch.models.admin.request import ( ReportRequest, diff --git a/generalresearch/thl_django/migrations/0010_supplierpayout_payout_supplier_payout.py b/generalresearch/thl_django/migrations/0010_supplierpayout_payout_supplier_payout.py new file mode 100644 index 0000000..5c3319c --- /dev/null +++ b/generalresearch/thl_django/migrations/0010_supplierpayout_payout_supplier_payout.py @@ -0,0 +1,51 @@ +# Generated by Django 6.1 on 2026-09-01 23:15 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ( + "thl_django", + "0009_toolrun_mtrhop_portscanport_iplabel_mtr_portscan_and_more", + ), + ] + + operations = [ + migrations.CreateModel( + name="SupplierPayout", + fields=[ + ("id", models.BigAutoField(primary_key=True, serialize=False)), + ("ext_ref_id", models.CharField(max_length=64, unique=True)), + ("business_id", models.UUIDField(null=True)), + ("created", models.DateTimeField(auto_now_add=True)), + ("amount", models.BigIntegerField()), + ("status", models.CharField(max_length=20, null=True)), + ("payout_type", models.CharField(max_length=14)), + ("request_data", models.JSONField(null=True)), + ("order_data", models.JSONField(null=True)), + ], + options={ + "db_table": "supplier_payout", + "indexes": [ + models.Index( + fields=["created"], name="supplier_pa_created_336236_idx" + ), + models.Index( + fields=["business_id"], name="supplier_pa_busines_2c7a4e_idx" + ), + ], + }, + ), + migrations.AddField( + model_name="payout", + name="supplier_payout", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + to="thl_django.supplierpayout", + ), + ), + ] diff --git a/test_utils/conftest.py b/test_utils/conftest.py index daf6b43..44e36a6 100644 --- a/test_utils/conftest.py +++ b/test_utils/conftest.py @@ -225,8 +225,10 @@ def django_db_factory( _ran = {} import django + from django.apps import apps from django.conf import settings as django_settings from django.core.management import call_command + from django.utils.functional import empty def _inner( django_project: str = "generalresearch.thl_django", @@ -242,34 +244,43 @@ def django_db_factory( # We need model files that are NOT in this repo. gr_path = gr_repo() sys.path.insert(0, str(gr_path)) + print("DJANGO_PROJECT_PATH", str(gr_path), sys.path) # 1. Bootstrapping Django settings - if not django_settings.configured: - django_settings.configure( - DATABASES={ - "default": { - "ENGINE": "django.db.backends.postgresql", - "NAME": postgres_instance_dict["name"], - "USER": postgres_instance_dict["username"], - "PASSWORD": postgres_instance_dict["password"], - "HOST": postgres_instance_dict["host"], - "PORT": postgres_instance_dict["port"], - } - }, - INSTALLED_APPS=[ - "django.contrib.postgres", - "django.contrib.contenttypes", - django_project, - ], - ) + # if not django_settings.configured: + # 1. Reset the lazy wrapper back to an empty state + # if not django_settings.configured: + + django_settings._wrapped = empty + + django_settings.configure( + DATABASES={ + "default": { + "ENGINE": "django.db.backends.postgresql", + "NAME": postgres_instance_dict["name"], + "USER": postgres_instance_dict["username"], + "PASSWORD": postgres_instance_dict["password"], + "HOST": postgres_instance_dict["host"], + "PORT": postgres_instance_dict["port"], + } + }, + INSTALLED_APPS=[ + "django.contrib.postgres", + "django.contrib.contenttypes", + django_project, + ], + ) django.setup() - # for model in apps.get_models(): - # print(f"Discovered model: {model._meta.label}") + for model in apps.get_models(): + print(f"Discovered model: {model._meta.label}") # 2. Run migrations directly during fixture activation + print("DJANGO_PROJECT", django_project) if "gr" in django_project: call_command("makemigrations", "common", interactive=False) + else: + call_command("makemigrations", interactive=False) call_command("migrate") diff --git a/test_utils/managers/gr/conftest.py b/test_utils/managers/gr/conftest.py index a7fa9e9..b5db2a5 100644 --- a/test_utils/managers/gr/conftest.py +++ b/test_utils/managers/gr/conftest.py @@ -24,6 +24,8 @@ if TYPE_CHECKING: # === Msc === + + @pytest.fixture(scope="session") def gr_redis_config_db() -> str: return str(randint(99, 1_023)) diff --git a/test_utils/managers/thl/conftest.py b/test_utils/managers/thl/conftest.py index 391b74c..6e19bef 100644 --- a/test_utils/managers/thl/conftest.py +++ b/test_utils/managers/thl/conftest.py @@ -45,20 +45,7 @@ if TYPE_CHECKING: WallManager, ) - -@pytest.fixture(scope="session") -def thl_web_rr(django_db_factory: Callable[..., PostgresDsn]) -> PostgresConfig: - - return PostgresConfig( - dsn=django_db_factory("generalresearch.thl_django"), - connect_timeout=1, - statement_timeout=5, - ) - - -@pytest.fixture(scope="session") -def thl_web_rw(thl_web_rr: PostgresConfig) -> PostgresConfig: - return thl_web_rr +# === Msc === @pytest.fixture(scope="session") @@ -97,6 +84,25 @@ def thl_redis_config( r.flushdb() +@pytest.fixture(scope="session") +def thl_web_rr(django_db_factory: Callable[..., PostgresDsn]) -> PostgresConfig: + _dsn = django_db_factory("generalresearch.thl_django") + + return PostgresConfig( + dsn=_dsn, + connect_timeout=1, + statement_timeout=5, + ) + + +@pytest.fixture(scope="session") +def thl_web_rw(thl_web_rr: PostgresConfig) -> PostgresConfig: + return thl_web_rr + + +# === Managers === + + @pytest.fixture(scope="session") def payout_event_manager( thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig diff --git a/test_utils/models/gr/conftest.py b/test_utils/models/gr/conftest.py index b87f3bb..a73dd70 100644 --- a/test_utils/models/gr/conftest.py +++ b/test_utils/models/gr/conftest.py @@ -66,35 +66,58 @@ def gr_user_cache( return gr_user +# --- Business Bank Account --- + + @pytest.fixture def gr_business_bank_account_factory( - gr_bbam: BusinessBankAccountManager, + gr_business_bank_account_manager: BusinessBankAccountManager, ) -> Callable[..., BusinessBankAccount]: def _inner( business_id: PositiveInt, + save: bool = True, uuid: UUIDStr | None = None, transfer_method: TransferMethod | None = None, account_number: str | None = None, routing_number: str | None = None, iban: str | None = None, swift: str | None = None, - ): - from generalresearch.models.gr.business import TransferMethod + **kwargs, + ) -> BusinessBankAccount: - return gr_bbam.create( - business_id=business_id, - uuid=uuid or uuid4().hex, - transfer_method=transfer_method or TransferMethod.ACH, - account_number=account_number or uuid4().hex[:6], - routing_number=routing_number or uuid4().hex[:6], - iban=iban or uuid4().hex[:6], - swift=swift or uuid4().hex[:6], - ) + if save: + return gr_business_bank_account_manager.create( + business_id=business_id, + uuid=uuid or uuid4().hex, + transfer_method=transfer_method or TransferMethod.ACH, + account_number=account_number or uuid4().hex[:6], + routing_number=routing_number or uuid4().hex[:6], + iban=iban or uuid4().hex[:6], + swift=swift or uuid4().hex[:6], + **kwargs, + ) + else: + raise ValueError("BusinessBankAccount Business not supported yet") return _inner +@pytest.fixture +def gr_business_bank_account(gr_business_factory: Callable[..., Business]) -> Business: + return gr_business_factory(save=True) + + +@pytest.fixture +def unsaved_gr_business_bank_account( + gr_business_factory: Callable[..., Business], +) -> Business: + return gr_business_factory(save=False) + + +# ----------------- + + @pytest.fixture def gr_business_address_factory( gr_bam: BusinessAddressManager, @@ -204,14 +227,6 @@ def business_address( return business_address_manager.create_dummy(business_id=gr_business.id) -@pytest.fixture -def business_bank_account( - gr_business: Business, - business_bank_account_manager: BusinessBankAccountManager, -) -> BusinessBankAccount: - return business_bank_account_manager.create_dummy(business_id=gr_business.id) - - @pytest.fixture() def gr_user_token_header(gr_user_token: GRToken) -> dict[str, str]: return gr_user_token.auth_header diff --git a/tests/managers/gr/test_business.py b/tests/managers/gr/test_business.py index 35c471e..3513af5 100644 --- a/tests/managers/gr/test_business.py +++ b/tests/managers/gr/test_business.py @@ -25,18 +25,18 @@ class TestBusinessBankAccountManager: def test_init( self, - business_bank_account_manager: BusinessBankAccountManager, + gr_business_bank_account_manager: BusinessBankAccountManager, gr_db: PostgresConfig, ): - assert business_bank_account_manager.pg_config == gr_db + assert gr_business_bank_account_manager.pg_config == gr_db def test_create( self, gr_business: Business, - business_bank_account_manager: BusinessBankAccountManager, + gr_business_bank_account_manager: BusinessBankAccountManager, ): - instance = business_bank_account_manager.create( + instance = gr_business_bank_account_manager.create( business_id=gr_business.id, uuid=uuid4().hex, transfer_method=TransferMethod.ACH, @@ -44,7 +44,7 @@ class TestBusinessBankAccountManager: assert isinstance(instance, BusinessBankAccount) assert isinstance(instance.id, int) - res = business_bank_account_manager.get_by_business_id( + res = gr_business_bank_account_manager.get_by_business_id( business_id=instance.business_id ) assert isinstance(res, list) diff --git a/tests/models/gr/test_business.py b/tests/models/gr/test_business.py index 90e69db..57f31f3 100644 --- a/tests/models/gr/test_business.py +++ b/tests/models/gr/test_business.py @@ -62,12 +62,12 @@ class TestBusinessBankAccount: def test_init( self, gr_business: Business, - business_bank_account_manager: BusinessBankAccountManager, + gr_business_bank_account_manager: BusinessBankAccountManager, ): from generalresearch.models.gr.business import BusinessBankAccount from generalresearch.models.gr.definitions import TransferMethod - instance = business_bank_account_manager.create( + instance = gr_business_bank_account_manager.create( business_id=gr_business.id, uuid=uuid4().hex, transfer_method=TransferMethod.ACH, @@ -76,20 +76,20 @@ class TestBusinessBankAccount: def test_business( self, - business_bank_account: BusinessBankAccount, + gr_business_bank_account: BusinessBankAccount, gr_business: Business, gr_db: PostgresConfig, gr_redis_config: RedisConfig, ): from generalresearch.models.gr.business import Business - assert business_bank_account.business is None + assert gr_business_bank_account.business is None - business_bank_account.prefetch_business( + gr_business_bank_account.prefetch_business( pg_config=gr_db, redis_config=gr_redis_config ) - assert isinstance(business_bank_account.business, Business) - assert business_bank_account.business.uuid == gr_business.uuid + assert isinstance(gr_business_bank_account.business, Business) + assert gr_business_bank_account.business.uuid == gr_business.uuid class TestBusinessAddress: @@ -264,13 +264,13 @@ class TestBusiness: def test_bank_accounts( self, gr_business: Business, - business_bank_account_manager: BusinessBankAccountManager, + gr_business_bank_account_manager: BusinessBankAccountManager, ): assert gr_business.products is None # It's an empty list after prefetch gr_business.prefetch_bank_accounts( - business_bank_account_manager=business_bank_account_manager + business_bank_account_manager=gr_business_bank_account_manager ) assert isinstance(gr_business.bank_accounts, list) assert len(gr_business.bank_accounts) == 1 @@ -423,7 +423,7 @@ class TestBusiness: def test_pop_financial( self, gr_business: Business, - thl_web_rr: PostgresConfig, + product_manager: ProductManager, thl_ledger_manager: ThlLedgerManager, mnt_filepath: GRLDatasets, client_no_amm: DaskClient, @@ -431,7 +431,7 @@ class TestBusiness: ): assert gr_business.pop_financial is None gr_business.prebuild_pop_financial( - thl_pg_config=thl_web_rr, + product_manager=product_manager, thl_lm=thl_ledger_manager, ds=mnt_filepath, client=client_no_amm, @@ -442,7 +442,6 @@ class TestBusiness: def test_bp_accounts( self, gr_business: Business, - thl_web_rr: PostgresConfig, product_factory: Callable[..., Product], thl_ledger_manager: ThlLedgerManager, product_manager: ProductManager, diff --git a/tests/test_postgres.py b/tests/test_postgres.py index c53f644..9794321 100644 --- a/tests/test_postgres.py +++ b/tests/test_postgres.py @@ -68,4 +68,15 @@ class TestPostgresDjangoCreation: WHERE table_schema = 'public'; """) assert len(res) == 1 - assert res[0]["count"] == 56 + assert res[0]["count"] == 57 + + def test_django_tables_with_gr( + self, thl_web_rw: PostgresConfig, gr_db: PostgresConfig + ): + res = thl_web_rw.execute_sql_query(query=""" + SELECT COUNT(*) + FROM information_schema.tables + WHERE table_schema = 'public'; + """) + assert len(res) == 1 + assert res[0]["count"] > 57 -- cgit v1.2.3