diff --git a/compose.yaml b/compose.yaml index f1b75256b..99f065140 100644 --- a/compose.yaml +++ b/compose.yaml @@ -31,7 +31,7 @@ services: sh -c " python manage.py makemigrations && python manage.py migrate && - python manage.py loaddata dev_data.yaml org_permissions.yaml && + python manage.py loaddata core_dev.yaml rcrasite_dev.yaml org_dev.yaml profile_dev.yaml && python manage.py runserver 0.0.0.0:8000" healthcheck: test: diff --git a/server/.dockerignore b/server/.dockerignore index 111a454c5..d70243a40 100644 --- a/server/.dockerignore +++ b/server/.dockerignore @@ -2,7 +2,7 @@ **/tests Dockerfile .dockerignore -db.sqlite3 +**/*.sqlite3 **/.git **/.gitignore **/.vscode diff --git a/server/core/fixtures/core_dev.yaml b/server/core/fixtures/core_dev.yaml new file mode 100644 index 000000000..499c340ae --- /dev/null +++ b/server/core/fixtures/core_dev.yaml @@ -0,0 +1,45 @@ +- model: core.trakuser + pk: 8062d496-15f1-485d-961c-a8e5fa118dde + fields: + password: pbkdf2_sha256$390000$iVFyQyb6N3g06Wan8YLnTv$MgFhKBvwPSwctgxWSviA/OXClEKtDXg87iPU+g9+Zjs= + last_login: 2023-03-19 00:29:46.249589+00:00 + is_superuser: false + username: orgadmin + first_name: "org" + last_name: "admin" + email: foo@generator.com + is_staff: true + is_active: true + date_joined: 2022-12-17 19:14:17.239000+00:00 + groups: [1, 2] + user_permissions: [] +- model: core.trakuser + pk: a0ba4966-aa53-44c8-be1a-0a0d2d6b6acd + fields: + password: pbkdf2_sha256$390000$iVFyQyb6N3g06Wan8YLnTv$MgFhKBvwPSwctgxWSviA/OXClEKtDXg87iPU+g9+Zjs= + last_login: 2023-03-19 00:29:46.249589+00:00 + is_superuser: true + username: admin + first_name: "" + last_name: "" + email: balh@blah.com + is_staff: true + is_active: true + date_joined: 2022-12-17 19:14:17.239000+00:00 + groups: [] + user_permissions: [] +- model: core.trakuser + pk: 4ac96f68-42cf-47ea-bffb-f24d423dbc35 + fields: + password: pbkdf2_sha256$390000$SB7EHpYC88CjsX5tcbxa8E$yh1TWONkGI2z/bjblkPSTyjpd1UdhnivPW5nzA9NGOk= + last_login: null + is_superuser: false + username: testuser1 + first_name: "David" + last_name: "Graham" + email: "myemail@proton.me" + is_staff: false + is_active: true + date_joined: 2022-12-17 19:17:58.260000+00:00 + groups: [2] + user_permissions: [] diff --git a/server/core/tests/test_rcrainfo_service.py b/server/core/tests/test_rcrainfo_service.py index c06cbfdd2..2c9064d95 100644 --- a/server/core/tests/test_rcrainfo_service.py +++ b/server/core/tests/test_rcrainfo_service.py @@ -1,12 +1,12 @@ from datetime import UTC, datetime import emanifest +from manifest.models import QuickerSign +from manifest.serializers import QuickerSignSerializer from responses import matchers from rest_framework import status from core.services import RcraClient, get_rcra_client -from handler.models import QuickerSign -from handler.serializers import QuickerSignSerializer class TestRcrainfoService: diff --git a/server/fixtures/dev_data.yaml b/server/fixtures/dev_data.yaml deleted file mode 100644 index 9cdb6594d..000000000 --- a/server/fixtures/dev_data.yaml +++ /dev/null @@ -1,210 +0,0 @@ -- model: core.trakuser - pk: 8062d496-15f1-485d-961c-a8e5fa118dde - fields: - password: pbkdf2_sha256$390000$iVFyQyb6N3g06Wan8YLnTv$MgFhKBvwPSwctgxWSviA/OXClEKtDXg87iPU+g9+Zjs= - last_login: 2023-03-19 00:29:46.249589+00:00 - is_superuser: false - username: orgadmin - first_name: "org" - last_name: "admin" - email: foo@generator.com - is_staff: true - is_active: true - date_joined: 2022-12-17 19:14:17.239000+00:00 - groups: [1, 2] - user_permissions: [] -- model: core.trakuser - pk: a0ba4966-aa53-44c8-be1a-0a0d2d6b6acd - fields: - password: pbkdf2_sha256$390000$iVFyQyb6N3g06Wan8YLnTv$MgFhKBvwPSwctgxWSviA/OXClEKtDXg87iPU+g9+Zjs= - last_login: 2023-03-19 00:29:46.249589+00:00 - is_superuser: true - username: admin - first_name: "" - last_name: "" - email: balh@blah.com - is_staff: true - is_active: true - date_joined: 2022-12-17 19:14:17.239000+00:00 - groups: [] - user_permissions: [] -- model: core.trakuser - pk: 4ac96f68-42cf-47ea-bffb-f24d423dbc35 - fields: - password: pbkdf2_sha256$390000$SB7EHpYC88CjsX5tcbxa8E$yh1TWONkGI2z/bjblkPSTyjpd1UdhnivPW5nzA9NGOk= - last_login: null - is_superuser: false - username: testuser1 - first_name: "David" - last_name: "Graham" - email: "myemail@proton.me" - is_staff: false - is_active: true - date_joined: 2022-12-17 19:17:58.260000+00:00 - groups: [2] - user_permissions: [] -- model: authtoken.token - pk: d9609d7764af771ee0def1db08dc7f90dd5e2d6d - fields: - user: 4ac96f68-42cf-47ea-bffb-f24d423dbc35 - created: 2022-12-18 13:10:40.552000+00:00 -- model: rcrasite.address - pk: 1 - fields: - street_number: null - address1: 123 VA TEST GEN 2021 WAY - address2: null - city: ARLINGTON - state: VA - country: US - zip: "22202" -- model: handler.manifestphone - pk: 1 - fields: - number: 321-321-3214 - extension: null -- model: rcrasite.rcraphone - pk: 1 - fields: - number: 321-321-3214 - extension: null -- model: rcrasite.contact - pk: 1 - fields: - first_name: David - middle_initial: P - last_name: Graham - phone: 1 - email: testuser1@haztrak.net - company_name: haztrak -- model: rcrasite.rcrasite - pk: 1 - fields: - site_type: Generator - epa_id: VATESTGEN001 - name: VA TEST GEN 2021 - site_address: 1 - mail_address: 1 - modified: false - registered: false - contact: 1 - emergency_phone: null - gis_primary: false - can_esign: true - limited_esign: true - registered_emanifest_user: true -- model: rcrasite.rcrasite - pk: 2 - fields: - site_type: Transporter - epa_id: MOCKTRANS001 - name: Mock Transporter 01 - site_address: 1 - mail_address: 1 - modified: false - registered: false - contact: 1 - emergency_phone: null - gis_primary: false - can_esign: true - limited_esign: true - registered_emanifest_user: true -- model: rcrasite.rcrasite - pk: 3 - fields: - site_type: Transporter - epa_id: MOCKTRANS002 - name: Mock Transporter 02 - site_address: 1 - mail_address: 1 - modified: false - registered: false - contact: 1 - emergency_phone: null - gis_primary: false - can_esign: true - limited_esign: true - registered_emanifest_user: true -- model: rcrasite.rcrasite - pk: 4 - fields: - site_type: Tsdf - epa_id: MOCKTSDFS001 - name: Mock haztrak TSDF 01 - site_address: 1 - mail_address: 1 - modified: false - registered: false - contact: 1 - emergency_phone: null - gis_primary: false - can_esign: true - limited_esign: true - registered_emanifest_user: true -- model: profile.rcrainfoprofile - pk: d74f904a-7843-4a60-862c-3b94b6051359 - fields: - rcra_username: dpgraham4401 - phone_number: null - email: orgadmin@generator.com -- model: profile.rcrainfoprofile - pk: 1fd27bec-8743-4eb3-a44c-fd063ea62021 - fields: - rcra_username: "" - phone_number: null - email: superadmin@gmail.com -- model: profile.rcrainfoprofile - pk: 192c73f4-24f1-4f21-8239-dee2da43c547 - fields: - rcra_username: emanifestpyuser1 - phone_number: null - email: testuser1@haztrak.net -- model: org.org - pk: efb9e104-7f61-4365-a9af-9d7b55c854c4 - fields: - name: Generators Org LLC - admin: 8062d496-15f1-485d-961c-a8e5fa118dde - slug: generators-org-llc -- model: profile.profile - pk: c65dbee9-b6bf-400e-93e0-90a749cc2939 - fields: - user: 8062d496-15f1-485d-961c-a8e5fa118dde - rcrainfo_profile: d74f904a-7843-4a60-862c-3b94b6051359 -- model: profile.profile - pk: 186642a9-7b5f-4bcb-b328-0fdf8b43f191 - fields: - user: a0ba4966-aa53-44c8-be1a-0a0d2d6b6acd - rcrainfo_profile: 1fd27bec-8743-4eb3-a44c-fd063ea62021 -- model: profile.profile - pk: 87e355dd-1898-4a0a-81c3-1e9ac8473143 - fields: - user: 4ac96f68-42cf-47ea-bffb-f24d423dbc35 - rcrainfo_profile: 192c73f4-24f1-4f21-8239-dee2da43c547 -- model: org.site - pk: 1 - fields: - name: VA TEST GEN 2021 - rcra_site: 1 - last_rcrainfo_manifest_sync: null - org: efb9e104-7f61-4365-a9af-9d7b55c854c4 -- model: profile.rcrainfositeaccess - pk: 1 - fields: - site: 1 - profile: 192c73f4-24f1-4f21-8239-dee2da43c547 - site_manager: true - annual_report: Certifier - biennial_report: Certifier - e_manifest: Certifier - my_rcra_id: Certifier - wiets: Certifier -- model: org.siteuserobjectpermission - pk: 1 - fields: - permission: - - view_site - - org - - site - user: - - testuser1 - content_object: 1 diff --git a/server/handler/admin.py b/server/handler/admin.py deleted file mode 100644 index bba589bc2..000000000 --- a/server/handler/admin.py +++ /dev/null @@ -1,66 +0,0 @@ -from django.contrib import admin -from django.db.models import Q, QuerySet -from django.urls import reverse -from django.utils.html import format_html, urlencode - -from core.admin import HiddenListView - -from .models import ( - ESignature, - Handler, - Signer, - Transporter, -) -from .models.contact import ManifestPhone - - -class IsApiUser(admin.SimpleListFilter): - title = "API User" - parameter_name = "has_rcrainfo_api_id_key" - - def lookups(self, request, model_admin): - return ("True", True), ("False", False) - - def queryset(self, request, queryset: QuerySet): - if self.value() == "True": - return queryset.filter(mtn__iendswith="DFT") - elif self.value() == "False": - return queryset.filter(~Q(mtn__iendswith="DFT")) - else: - return queryset - - -@admin.register(Transporter) -class TransporterAdmin(admin.ModelAdmin): - list_display = ["__str__", "related_manifest", "order"] - search_fields = ["handler__epa_id", "manifest__mtn"] - - def related_manifest(self, obj): - url = ( - reverse("admin:trak_manifest_changelist") - + "?" - + urlencode({"mtn": str(obj.manifest.mtn)}) - ) - return format_html("{}", url, obj.manifest.mtn) - - related_manifest.short_description = "Manifest" - - -@admin.register(Handler) -class HandlerAdmin(admin.ModelAdmin): - list_display = ["__str__", "related_manifest"] - search_fields = ["handler__epa_id"] - - def related_manifest(self, obj: Handler): - if obj.generator: - return obj.generator.get() - if obj.designated_facility: - return obj.designated_facility.get() - - related_manifest.short_description = "Manifest" - - -# Register models That should only be edited within the context of another form here. -admin.site.register(ManifestPhone, HiddenListView) -admin.site.register(ESignature, HiddenListView) -admin.site.register(Signer, HiddenListView) diff --git a/server/handler/apps.py b/server/handler/apps.py deleted file mode 100644 index f4db87f6e..000000000 --- a/server/handler/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class TrakConfig(AppConfig): - default_auto_field = "django.db.models.BigAutoField" - name = "handler" diff --git a/server/handler/migrations/0001_initial.py b/server/handler/migrations/0001_initial.py deleted file mode 100644 index fc03a627c..000000000 --- a/server/handler/migrations/0001_initial.py +++ /dev/null @@ -1,201 +0,0 @@ -# Generated by Django 4.2.10 on 2024-02-21 22:17 - -import django.db.models.deletion -import handler.models.contact -from django.db import migrations, models - - -class Migration(migrations.Migration): - initial = True - - dependencies = [ - ("rcrasite", "0001_initial"), - ] - - operations = [ - migrations.CreateModel( - name="Handler", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ], - options={ - "ordering": ["rcra_site"], - }, - ), - migrations.CreateModel( - name="ManifestPhone", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("number", handler.models.contact.ManifestPhoneNumber(max_length=12)), - ("extension", models.CharField(blank=True, max_length=6, null=True)), - ], - options={ - "ordering": ["number"], - }, - ), - migrations.CreateModel( - name="PaperSignature", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("printed_name", models.CharField(max_length=255)), - ("sign_date", models.DateTimeField()), - ], - options={ - "ordering": ["pk"], - "abstract": False, - }, - ), - migrations.CreateModel( - name="Transporter", - fields=[ - ( - "handler_ptr", - models.OneToOneField( - auto_created=True, - on_delete=django.db.models.deletion.CASCADE, - parent_link=True, - primary_key=True, - serialize=False, - to="handler.handler", - ), - ), - ("order", models.PositiveIntegerField()), - ], - options={ - "ordering": ["manifest__mtn"], - }, - bases=("handler.handler",), - ), - migrations.CreateModel( - name="Signer", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("rcra_user_id", models.CharField(blank=True, max_length=100, null=True)), - ("first_name", models.CharField(blank=True, max_length=38, null=True)), - ("middle_initial", models.CharField(blank=True, max_length=1, null=True)), - ("last_name", models.CharField(blank=True, max_length=38, null=True)), - ("email", models.CharField(blank=True, max_length=38, null=True)), - ("company_name", models.CharField(blank=True, max_length=80, null=True)), - ( - "contact_type", - models.CharField( - blank=True, - choices=[("email", "Email"), ("voice", "Voice"), ("text", "Text")], - max_length=5, - null=True, - ), - ), - ( - "signer_role", - models.CharField( - choices=[ - ("Industry", "Industry"), - ("PPC", "Ppc"), - ("EPA", "Epa"), - ("State", "State"), - ], - max_length=10, - null=True, - ), - ), - ( - "phone", - models.ForeignKey( - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="handler.manifestphone", - ), - ), - ], - options={ - "ordering": ["first_name"], - }, - ), - migrations.AddField( - model_name="handler", - name="emergency_phone", - field=models.ForeignKey( - blank=True, - help_text="Emergency phone number for the hazardous waste rcra_site", - null=True, - on_delete=django.db.models.deletion.PROTECT, - to="handler.manifestphone", - ), - ), - migrations.AddField( - model_name="handler", - name="paper_signature", - field=models.OneToOneField( - blank=True, - help_text="The signature associated with hazardous waste custody exchange", - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="handler.papersignature", - ), - ), - migrations.AddField( - model_name="handler", - name="rcra_site", - field=models.ForeignKey( - help_text="Hazardous waste rcra_site associated with the manifest", - on_delete=django.db.models.deletion.CASCADE, - to="rcrasite.rcrasite", - ), - ), - migrations.CreateModel( - name="ESignature", - fields=[ - ( - "id", - models.BigAutoField( - auto_created=True, primary_key=True, serialize=False, verbose_name="ID" - ), - ), - ("sign_date", models.DateTimeField(blank=True, null=True)), - ("cromerr_activity_id", models.CharField(blank=True, max_length=100, null=True)), - ("cromerr_document_id", models.CharField(blank=True, max_length=100, null=True)), - ("on_behalf", models.BooleanField(blank=True, default=False, null=True)), - ( - "manifest_handler", - models.ForeignKey( - on_delete=django.db.models.deletion.CASCADE, - related_name="e_signatures", - to="handler.handler", - ), - ), - ( - "signer", - models.OneToOneField( - blank=True, - null=True, - on_delete=django.db.models.deletion.CASCADE, - to="handler.signer", - ), - ), - ], - options={ - "verbose_name": "e-Signature", - "ordering": ["sign_date"], - }, - ), - ] diff --git a/server/handler/migrations/0002_initial.py b/server/handler/migrations/0002_initial.py deleted file mode 100644 index 28a65cfbd..000000000 --- a/server/handler/migrations/0002_initial.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.10 on 2024-02-21 22:17 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('manifest', '0001_initial'), - ('handler', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='transporter', - name='manifest', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='transporters', to='manifest.manifest'), - ), - ] diff --git a/server/handler/migrations/0003_alter_papersignature_options.py b/server/handler/migrations/0003_alter_papersignature_options.py deleted file mode 100644 index a630ebc0b..000000000 --- a/server/handler/migrations/0003_alter_papersignature_options.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.0.4 on 2024-06-03 02:04 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('handler', '0002_initial'), - ] - - operations = [ - migrations.AlterModelOptions( - name='papersignature', - options={}, - ), - ] diff --git a/server/handler/serializers/base_serializer.py b/server/handler/serializers/base_serializer.py deleted file mode 100644 index f43b6940d..000000000 --- a/server/handler/serializers/base_serializer.py +++ /dev/null @@ -1,27 +0,0 @@ -from rest_framework import serializers - - -class HandlerBaseSerializer(serializers.ModelSerializer): - """ - The Django Trak app base serializers class used to share functionality - across trak app serializers universally. - """ - - def __str__(self): - return f"{self.__class__.__name__}" - - def __repr__(self): - return f"<{self.__class__.__name__}({self.data})>" - - def to_representation(self, instance): - """ - Remove empty fields when serializing - """ - data = super().to_representation(instance) - for field in self.fields: - try: - if data[field] is None: - data.pop(field) - except KeyError: - pass - return data diff --git a/server/handler/tests/conftest.py b/server/handler/tests/conftest.py deleted file mode 100644 index 94865b1e4..000000000 --- a/server/handler/tests/conftest.py +++ /dev/null @@ -1,111 +0,0 @@ -from datetime import UTC, datetime -from typing import Optional - -import pytest -from faker import Faker - -from handler.models import ( - ESignature, - Handler, - PaperSignature, - Signer, - Transporter, -) -from manifest.models import Manifest -from rcrasite.models import RcraSite - - -@pytest.fixture -def manifest_handler_factory(db, rcra_site_factory, paper_signature_factory): - """Abstract factory for Haztrak Handler model""" - - def create_manifest_handler( - rcra_site: Optional[RcraSite] = None, - paper_signature: Optional[PaperSignature] = None, - ) -> Handler: - return Handler.objects.create( - rcra_site=rcra_site or rcra_site_factory(), - paper_signature=paper_signature or paper_signature_factory(), - ) - - return create_manifest_handler - - -@pytest.fixture -def manifest_transporter_factory(db, rcra_site_factory, paper_signature_factory): - """Abstract factory for Haztrak Handler model""" - - def create_manifest_handler( - rcra_site: Optional[RcraSite] = None, - paper_signature: Optional[PaperSignature] = None, - manifest: Manifest = None, - order: Optional[int] = 1, - ) -> Transporter: - return Transporter.objects.create( - manifest=manifest, - order=order, - rcra_site=rcra_site or rcra_site_factory(), - paper_signature=paper_signature or paper_signature_factory(), - ) - - return create_manifest_handler - - -@pytest.fixture -def paper_signature_factory(db, faker: Faker): - """Abstract factory for Paper Signature""" - - def create_signature( - printed_name: Optional[str] = None, - sign_date: Optional[datetime] = None, - ) -> PaperSignature: - return PaperSignature.objects.create( - printed_name=printed_name or faker.name(), - sign_date=sign_date or datetime.now(UTC), - ) - - return create_signature - - -@pytest.fixture -def e_signature_factory(db, signer_factory, manifest_handler_factory, faker: Faker): - """Abstract factory for Haztrak Handler model""" - - def create_e_signature( - signer: Optional[Signer] = None, - manifest_handler: Optional[Handler] = None, - ) -> ESignature: - return ESignature.objects.create( - signer=signer or signer_factory(), - manifest_handler=manifest_handler or manifest_handler_factory(), - sign_date=datetime.now(UTC), - cromerr_activity_id=faker.pystr(max_chars=10), - cromerr_document_id=faker.pystr(max_chars=10), - on_behalf=False, - ) - - return create_e_signature - - -@pytest.fixture -def signer_factory(db, faker: Faker): - """Abstract factory for Haztrak Signer model""" - - def creat_signer( - first_name: Optional[str] = None, - middle_initial: Optional[str] = None, - last_name: Optional[str] = None, - signer_role: Optional[str] = "EP", - company_name: Optional[str] = None, - rcra_user_id: Optional[str] = None, - ) -> Signer: - return Signer.objects.create( - first_name=first_name or faker.first_name(), - middle_initial=middle_initial or faker.pystr(max_chars=1), - last_name=last_name or faker.last_name(), - signer_role=signer_role, - company_name=company_name or faker.company(), - rcra_user_id=rcra_user_id or faker.user_name(), - ) - - return creat_signer diff --git a/server/haztrak/settings/base.py b/server/haztrak/settings/base.py index 9ee69655b..7a3ce5c74 100644 --- a/server/haztrak/settings/base.py +++ b/server/haztrak/settings/base.py @@ -56,7 +56,6 @@ "django_celery_results", "django_celery_beat", "drf_spectacular", - "handler", "rcrasite", "core", "manifest", @@ -263,4 +262,3 @@ TRAK_MANIFEST_MODEL = "manifest.Manifest" TRAK_SITE_MODEL = "org.Site" TRAK_WASTELINE_MODEL = "wasteline.Wasteline" -TRAK_HANDLER_MODEL = "handler.Handler" diff --git a/server/manage.py b/server/manage.py index 014ac6f33..510907acb 100755 --- a/server/manage.py +++ b/server/manage.py @@ -1,12 +1,13 @@ #!/usr/bin/env python """Django's command-line utility for administrative tasks.""" + import os import sys def main(): """Run administrative tasks.""" - os.environ.setdefault("DJANGO_SETTINGS_MODULE", "haztrak.settings") + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "haztrak.settings.dev") try: from django.core.management import execute_from_command_line except ImportError as exc: diff --git a/server/manifest/admin.py b/server/manifest/admin.py index d084487e4..a2efbf72b 100644 --- a/server/manifest/admin.py +++ b/server/manifest/admin.py @@ -1,9 +1,19 @@ +from core.admin import HiddenListView from django.contrib import admin from django.db.models import Q, QuerySet +from django.urls import reverse +from django.utils.html import format_html, urlencode +from wasteline.admin import WasteLineInline -from handler.models import Transporter from manifest.models import Manifest -from wasteline.admin import WasteLineInline + +from .models import ( + ESignature, + Handler, + ManifestPhone, + Signer, + Transporter, +) class IsDraftMtn(admin.SimpleListFilter): @@ -33,3 +43,55 @@ class ManifestAdmin(admin.ModelAdmin): def transporter_count(self, manifest): # ToDo: this will result in additional DB hit for every Manifest in the list rendered. return Transporter.objects.filter(manifest=manifest).count() + + +class IsApiUser(admin.SimpleListFilter): + title = "API User" + parameter_name = "has_rcrainfo_api_id_key" + + def lookups(self, request, model_admin): + return ("True", True), ("False", False) + + def queryset(self, request, queryset: QuerySet): + if self.value() == "True": + return queryset.filter(mtn__iendswith="DFT") + elif self.value() == "False": + return queryset.filter(~Q(mtn__iendswith="DFT")) + else: + return queryset + + +@admin.register(Transporter) +class TransporterAdmin(admin.ModelAdmin): + list_display = ["__str__", "related_manifest", "order"] + search_fields = ["handler__epa_id", "manifest__mtn"] + + def related_manifest(self, obj): + url = ( + reverse("admin:trak_manifest_changelist") + + "?" + + urlencode({"mtn": str(obj.manifest.mtn)}) + ) + return format_html("{}", url, obj.manifest.mtn) + + related_manifest.short_description = "Manifest" + + +@admin.register(Handler) +class HandlerAdmin(admin.ModelAdmin): + list_display = ["__str__", "related_manifest"] + search_fields = ["handler__epa_id"] + + def related_manifest(self, obj: Handler): + if obj.generator: + return obj.generator.get() + if obj.designated_facility: + return obj.designated_facility.get() + + related_manifest.short_description = "Manifest" + + +# Register models That should only be edited within the context of another form here. +admin.site.register(ManifestPhone, HiddenListView) +admin.site.register(ESignature, HiddenListView) +admin.site.register(Signer, HiddenListView) diff --git a/server/manifest/migrations/0001_initial.py b/server/manifest/migrations/0001_initial.py index 33da08327..bd7ae4490 100644 --- a/server/manifest/migrations/0001_initial.py +++ b/server/manifest/migrations/0001_initial.py @@ -1,7 +1,8 @@ -# Generated by Django 4.2.10 on 2024-02-21 22:17 +# Generated by Django 5.0.8 on 2024-08-22 16:38 import django.db.models.deletion -import manifest.models +import manifest.models.contact +import manifest.models.manifest from django.db import migrations, models @@ -9,7 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("handler", "0001_initial"), + ("rcrasite", "0001_initial"), ] operations = [ @@ -28,7 +29,7 @@ class Migration(migrations.Migration): blank=True, help_text="Original manifest tracking number of rejected manifestRegex expression validation: [0-9]{9}[A-Z]{3}", null=True, - validators=[manifest.models.validate_mtn], + validators=[manifest.models.manifest.validate_mtn], ), ), ( @@ -58,6 +59,57 @@ class Migration(migrations.Migration): "verbose_name_plural": "Additional Info", }, ), + migrations.CreateModel( + name="Handler", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ( + "rcra_site", + models.ForeignKey( + help_text="Hazardous waste rcra_site associated with the manifest", + on_delete=django.db.models.deletion.CASCADE, + to="rcrasite.rcrasite", + ), + ), + ], + options={ + "ordering": ["rcra_site"], + }, + ), + migrations.CreateModel( + name="ManifestPhone", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("number", manifest.models.contact.ManifestPhoneNumber(max_length=12)), + ("extension", models.CharField(blank=True, max_length=6, null=True)), + ], + options={ + "ordering": ["number"], + }, + ), + migrations.CreateModel( + name="PaperSignature", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("printed_name", models.CharField(max_length=255)), + ("sign_date", models.DateTimeField()), + ], + ), migrations.CreateModel( name="PortOfEntry", fields=[ @@ -163,10 +215,10 @@ class Migration(migrations.Migration): ( "mtn", models.CharField( - default=manifest.models.draft_mtn, + default=manifest.models.manifest.draft_mtn, max_length=30, unique=True, - validators=[manifest.models.validate_mtn], + validators=[manifest.models.manifest.validate_mtn], verbose_name="manifest Tracking Number", ), ), @@ -302,7 +354,7 @@ class Migration(migrations.Migration): models.ForeignKey( on_delete=django.db.models.deletion.PROTECT, related_name="generator", - to="handler.handler", + to="manifest.handler", ), ), ( @@ -310,7 +362,7 @@ class Migration(migrations.Migration): models.ForeignKey( on_delete=django.db.models.deletion.PROTECT, related_name="designated_facility", - to="handler.handler", + to="manifest.handler", verbose_name="designated facility", ), ), @@ -319,4 +371,141 @@ class Migration(migrations.Migration): "ordering": ["update_date", "mtn"], }, ), + migrations.AddField( + model_name="handler", + name="emergency_phone", + field=models.ForeignKey( + blank=True, + help_text="Emergency phone number for the hazardous waste rcra_site", + null=True, + on_delete=django.db.models.deletion.PROTECT, + to="manifest.manifestphone", + ), + ), + migrations.AddField( + model_name="handler", + name="paper_signature", + field=models.OneToOneField( + blank=True, + help_text="The signature associated with hazardous waste custody exchange", + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="manifest.papersignature", + ), + ), + migrations.CreateModel( + name="Signer", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("rcra_user_id", models.CharField(blank=True, max_length=100, null=True)), + ("first_name", models.CharField(blank=True, max_length=38, null=True)), + ("middle_initial", models.CharField(blank=True, max_length=1, null=True)), + ("last_name", models.CharField(blank=True, max_length=38, null=True)), + ("email", models.CharField(blank=True, max_length=38, null=True)), + ("company_name", models.CharField(blank=True, max_length=80, null=True)), + ( + "contact_type", + models.CharField( + blank=True, + choices=[("email", "Email"), ("voice", "Voice"), ("text", "Text")], + max_length=5, + null=True, + ), + ), + ( + "signer_role", + models.CharField( + choices=[ + ("Industry", "Industry"), + ("PPC", "Ppc"), + ("EPA", "Epa"), + ("State", "State"), + ], + max_length=10, + null=True, + ), + ), + ( + "phone", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="manifest.manifestphone", + ), + ), + ], + options={ + "ordering": ["first_name"], + }, + ), + migrations.CreateModel( + name="ESignature", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("sign_date", models.DateTimeField(blank=True, null=True)), + ("cromerr_activity_id", models.CharField(blank=True, max_length=100, null=True)), + ("cromerr_document_id", models.CharField(blank=True, max_length=100, null=True)), + ("on_behalf", models.BooleanField(blank=True, default=False, null=True)), + ( + "manifest_handler", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="e_signatures", + to="manifest.handler", + ), + ), + ( + "signer", + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="manifest.signer", + ), + ), + ], + options={ + "verbose_name": "e-Signature", + "ordering": ["sign_date"], + }, + ), + migrations.CreateModel( + name="Transporter", + fields=[ + ( + "handler_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="manifest.handler", + ), + ), + ("order", models.PositiveIntegerField()), + ( + "manifest", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="transporters", + to="manifest.manifest", + ), + ), + ], + options={ + "ordering": ["manifest__mtn"], + }, + bases=("manifest.handler",), + ), ] diff --git a/server/handler/models/__init__.py b/server/manifest/models/__init__.py similarity index 52% rename from server/handler/models/__init__.py rename to server/manifest/models/__init__.py index bbe8277ea..0c45b8437 100644 --- a/server/handler/models/__init__.py +++ b/server/manifest/models/__init__.py @@ -1,7 +1,11 @@ -""" -Model definitions for the trak domain -""" - from .contact import ManifestPhone from .handler import Handler, Transporter +from .manifest import ( + AdditionalInfo, + Manifest, + PortOfEntry, + draft_mtn, + manifest_factory, + validate_mtn, +) from .signature import ESignature, PaperSignature, QuickerSign, Signer diff --git a/server/handler/models/contact.py b/server/manifest/models/contact.py similarity index 100% rename from server/handler/models/contact.py rename to server/manifest/models/contact.py diff --git a/server/handler/models/handler.py b/server/manifest/models/handler.py similarity index 99% rename from server/handler/models/handler.py rename to server/manifest/models/handler.py index c935af8d8..6df9ab1e4 100644 --- a/server/handler/models/handler.py +++ b/server/manifest/models/handler.py @@ -4,7 +4,6 @@ from django.conf import settings from django.core.exceptions import ValidationError from django.db import models - from rcrasite.models import RcraSite from .contact import ManifestPhone diff --git a/server/manifest/models.py b/server/manifest/models/manifest.py similarity index 98% rename from server/manifest/models.py rename to server/manifest/models/manifest.py index 6aa66b3db..d980ec2da 100644 --- a/server/manifest/models.py +++ b/server/manifest/models/manifest.py @@ -3,16 +3,15 @@ from abc import ABC, abstractmethod from typing import List, Literal, Optional -from django.conf import settings from django.core.exceptions import ValidationError from django.db import models from django.db.models import Q, QuerySet from django.utils.translation import gettext_lazy as _ - -from handler.models import Handler, Transporter from rcrasite.models import RcraSiteType, RcraStates from wasteline.models import WasteLine +from .handler import Handler, Transporter + logger = logging.getLogger(__name__) @@ -247,13 +246,13 @@ class Status(models.TextChoices): blank=True, ) generator = models.ForeignKey( - settings.TRAK_HANDLER_MODEL, + "Handler", on_delete=models.PROTECT, related_name="generator", ) # transporters - one-to-many relationship, a manifest can have many transporters tsdf = models.ForeignKey( - settings.TRAK_HANDLER_MODEL, + "Handler", verbose_name="designated facility", on_delete=models.PROTECT, related_name="designated_facility", diff --git a/server/handler/models/signature.py b/server/manifest/models/signature.py similarity index 98% rename from server/handler/models/signature.py rename to server/manifest/models/signature.py index f8372655b..15bc94ffe 100644 --- a/server/handler/models/signature.py +++ b/server/manifest/models/signature.py @@ -2,7 +2,6 @@ from datetime import datetime, timezone from typing import List, Literal, Optional -from django.conf import settings from django.db import models logger = logging.getLogger(__name__) @@ -103,7 +102,7 @@ class Meta: objects = ESignatureManager() manifest_handler = models.ForeignKey( - settings.TRAK_HANDLER_MODEL, + "Handler", related_name="e_signatures", on_delete=models.CASCADE, ) diff --git a/server/handler/serializers/__init__.py b/server/manifest/serializers/__init__.py similarity index 74% rename from server/handler/serializers/__init__.py rename to server/manifest/serializers/__init__.py index 85b78d627..ec0da33b2 100644 --- a/server/handler/serializers/__init__.py +++ b/server/manifest/serializers/__init__.py @@ -1,2 +1,3 @@ from .handler_serializer import HandlerSerializer, TransporterSerializer +from .manifest import ManifestSerializer, MtnSerializer from .signatures import ESignatureSerializer, PaperSignatureSerializer, QuickerSignSerializer diff --git a/server/handler/serializers/handler_serializer.py b/server/manifest/serializers/handler_serializer.py similarity index 97% rename from server/handler/serializers/handler_serializer.py rename to server/manifest/serializers/handler_serializer.py index 3ccd3991b..03efbf483 100644 --- a/server/handler/serializers/handler_serializer.py +++ b/server/manifest/serializers/handler_serializer.py @@ -1,10 +1,10 @@ from typing import Dict +from rcrasite.serializers import RcraSiteSerializer from rest_framework import serializers from rest_framework.exceptions import ValidationError -from handler.models import Handler, ManifestPhone, Transporter -from rcrasite.serializers import RcraSiteSerializer +from manifest.models import Handler, ManifestPhone, Transporter from .signatures import ESignatureSerializer, PaperSignatureSerializer diff --git a/server/manifest/serializers.py b/server/manifest/serializers/manifest.py similarity index 99% rename from server/manifest/serializers.py rename to server/manifest/serializers/manifest.py index d11bb90d3..f73ad771a 100644 --- a/server/manifest/serializers.py +++ b/server/manifest/serializers/manifest.py @@ -1,21 +1,21 @@ import logging from typing import Dict, override +from rcrasite.models import RcraStates from rest_framework import serializers - -from handler.serializers import ( - HandlerSerializer, - TransporterSerializer, +from wasteline.serializers import ( + WasteLineSerializer, ) + from manifest.models import ( AdditionalInfo, Manifest, PortOfEntry, draft_mtn, ) -from rcrasite.models import RcraStates -from wasteline.serializers import ( - WasteLineSerializer, +from manifest.serializers import ( + HandlerSerializer, + TransporterSerializer, ) logger = logging.getLogger(__name__) diff --git a/server/handler/serializers/signatures.py b/server/manifest/serializers/signatures.py similarity index 88% rename from server/handler/serializers/signatures.py rename to server/manifest/serializers/signatures.py index e9d8fba16..2cb3cc243 100644 --- a/server/handler/serializers/signatures.py +++ b/server/manifest/serializers/signatures.py @@ -2,12 +2,33 @@ from datetime import timezone from typing import Dict +from rcrasite.serializers import RcraPhoneSerializer from rest_framework import serializers -from handler.models import ESignature, PaperSignature, QuickerSign, Signer -from rcrasite.serializers import RcraPhoneSerializer +from manifest.models import ESignature, PaperSignature, QuickerSign, Signer + + +class HandlerBaseSerializer(serializers.ModelSerializer): + # ToDo: remove -from .base_serializer import HandlerBaseSerializer + def __str__(self): + return f"{self.__class__.__name__}" + + def __repr__(self): + return f"<{self.__class__.__name__}({self.data})>" + + def to_representation(self, instance): + """ + Remove empty fields when serializing + """ + data = super().to_representation(instance) + for field in self.fields: + try: + if data[field] is None: + data.pop(field) + except KeyError: + pass + return data class QuickerSignSerializer(serializers.Serializer): diff --git a/server/manifest/services/emanifest.py b/server/manifest/services/emanifest.py index e10c0ef0a..0533cab42 100644 --- a/server/manifest/services/emanifest.py +++ b/server/manifest/services/emanifest.py @@ -2,16 +2,14 @@ from datetime import datetime from typing import List, Literal, NotRequired, Optional, TypedDict +from core.services import RcraClient, get_rcra_client from django.db import transaction from django.db.models import QuerySet from emanifest import RcrainfoResponse from requests import RequestException -from core.services import RcraClient, get_rcra_client -from handler.models import QuickerSign -from handler.serializers import QuickerSignSerializer -from manifest.models import Manifest -from manifest.serializers import ManifestSerializer +from manifest.models import Manifest, QuickerSign +from manifest.serializers import ManifestSerializer, QuickerSignSerializer from manifest.services.emanifest_search import EmanifestSearch from manifest.tasks import pull_manifest, sign_manifest diff --git a/server/manifest/tests/conftest.py b/server/manifest/tests/conftest.py index b580f8c25..d5426f71a 100644 --- a/server/manifest/tests/conftest.py +++ b/server/manifest/tests/conftest.py @@ -7,11 +7,113 @@ from django.db import IntegrityError from faker import Faker from faker.providers import BaseProvider - -from handler.models import Handler, PaperSignature, Transporter -from manifest.models import Manifest from rcrasite.models import RcraSite, RcraSiteType +from manifest.models import ( + ESignature, + Handler, + Manifest, + PaperSignature, + Signer, + Transporter, +) + + +@pytest.fixture +def manifest_handler_factory(db, rcra_site_factory, paper_signature_factory): + """Abstract factory for Haztrak Handler model""" + + def create_manifest_handler( + rcra_site: Optional[RcraSite] = None, + paper_signature: Optional[PaperSignature] = None, + ) -> Handler: + return Handler.objects.create( + rcra_site=rcra_site or rcra_site_factory(), + paper_signature=paper_signature or paper_signature_factory(), + ) + + return create_manifest_handler + + +@pytest.fixture +def manifest_transporter_factory(db, rcra_site_factory, paper_signature_factory): + """Abstract factory for Haztrak Handler model""" + + def create_manifest_handler( + rcra_site: Optional[RcraSite] = None, + paper_signature: Optional[PaperSignature] = None, + manifest: Manifest = None, + order: Optional[int] = 1, + ) -> Transporter: + return Transporter.objects.create( + manifest=manifest, + order=order, + rcra_site=rcra_site or rcra_site_factory(), + paper_signature=paper_signature or paper_signature_factory(), + ) + + return create_manifest_handler + + +@pytest.fixture +def paper_signature_factory(db, faker: Faker): + """Abstract factory for Paper Signature""" + + def create_signature( + printed_name: Optional[str] = None, + sign_date: Optional[datetime] = None, + ) -> PaperSignature: + return PaperSignature.objects.create( + printed_name=printed_name or faker.name(), + sign_date=sign_date or datetime.now(UTC), + ) + + return create_signature + + +@pytest.fixture +def e_signature_factory(db, signer_factory, manifest_handler_factory, faker: Faker): + """Abstract factory for Haztrak Handler model""" + + def create_e_signature( + signer: Optional[Signer] = None, + manifest_handler: Optional[Handler] = None, + ) -> ESignature: + return ESignature.objects.create( + signer=signer or signer_factory(), + manifest_handler=manifest_handler or manifest_handler_factory(), + sign_date=datetime.now(UTC), + cromerr_activity_id=faker.pystr(max_chars=10), + cromerr_document_id=faker.pystr(max_chars=10), + on_behalf=False, + ) + + return create_e_signature + + +@pytest.fixture +def signer_factory(db, faker: Faker): + """Abstract factory for Haztrak Signer model""" + + def creat_signer( + first_name: Optional[str] = None, + middle_initial: Optional[str] = None, + last_name: Optional[str] = None, + signer_role: Optional[str] = "EP", + company_name: Optional[str] = None, + rcra_user_id: Optional[str] = None, + ) -> Signer: + return Signer.objects.create( + first_name=first_name or faker.first_name(), + middle_initial=middle_initial or faker.pystr(max_chars=1), + last_name=last_name or faker.last_name(), + signer_role=signer_role, + company_name=company_name or faker.company(), + rcra_user_id=rcra_user_id or faker.user_name(), + ) + + return creat_signer + class MtnProvider(BaseProvider): SUFFIXES = ["ELC", "JJK", "FLE"] @@ -70,55 +172,3 @@ def create_manifest( ) return create_manifest - - -@pytest.fixture -def manifest_handler_factory(db, rcra_site_factory, paper_signature_factory): - """Abstract factory for manifest Handler model""" - - def create_manifest_handler( - rcra_site: Optional[RcraSite] = None, - paper_signature: Optional[PaperSignature] = None, - ) -> Handler: - return Handler.objects.create( - rcra_site=rcra_site or rcra_site_factory(), - paper_signature=paper_signature or paper_signature_factory(), - ) - - return create_manifest_handler - - -@pytest.fixture -def manifest_transporter_factory(db, rcra_site_factory, paper_signature_factory): - """Abstract factory for the manifest transporter model""" - - def create_manifest_handler( - rcra_site: Optional[RcraSite] = None, - paper_signature: Optional[PaperSignature] = None, - manifest: Manifest = None, - order: Optional[int] = 1, - ) -> Transporter: - return Transporter.objects.create( - manifest=manifest, - order=order, - rcra_site=rcra_site or rcra_site_factory(), - paper_signature=paper_signature or paper_signature_factory(), - ) - - return create_manifest_handler - - -@pytest.fixture -def paper_signature_factory(db, faker: Faker): - """Abstract factory for Paper Signature""" - - def create_signature( - printed_name: Optional[str] = None, - sign_date: Optional[datetime] = None, - ) -> PaperSignature: - return PaperSignature.objects.create( - printed_name=printed_name or faker.name(), - sign_date=sign_date or datetime.now(UTC), - ) - - return create_signature diff --git a/server/handler/__init__.py b/server/manifest/tests/models/__init__.py similarity index 100% rename from server/handler/__init__.py rename to server/manifest/tests/models/__init__.py diff --git a/server/handler/tests/test_handler_models.py b/server/manifest/tests/models/test_handler_models.py similarity index 98% rename from server/handler/tests/test_handler_models.py rename to server/manifest/tests/models/test_handler_models.py index bd5091b4b..8da2d8900 100644 --- a/server/handler/tests/test_handler_models.py +++ b/server/manifest/tests/models/test_handler_models.py @@ -1,6 +1,6 @@ import pytest -from handler.models import Handler +from manifest.models import Handler @pytest.mark.django_db diff --git a/server/manifest/tests/test_models.py b/server/manifest/tests/models/test_manifest_models.py similarity index 99% rename from server/manifest/tests/test_models.py rename to server/manifest/tests/models/test_manifest_models.py index 8f5f847c0..44dd5d7d9 100644 --- a/server/manifest/tests/test_models.py +++ b/server/manifest/tests/models/test_manifest_models.py @@ -3,10 +3,10 @@ import pytest from django.core.exceptions import ValidationError +from rcrasite.models import RcraSiteType -from handler.serializers import HandlerSerializer from manifest.models import Manifest, draft_mtn, manifest_factory, validate_mtn -from rcrasite.models import RcraSiteType +from manifest.serializers import HandlerSerializer @pytest.mark.django_db diff --git a/server/handler/tests/test_signature_models.py b/server/manifest/tests/models/test_signature_models.py similarity index 94% rename from server/handler/tests/test_signature_models.py rename to server/manifest/tests/models/test_signature_models.py index b8a6859f8..9a293df40 100644 --- a/server/handler/tests/test_signature_models.py +++ b/server/manifest/tests/models/test_signature_models.py @@ -3,7 +3,7 @@ import pytest from django.db import IntegrityError -from handler.models import PaperSignature +from manifest.models import PaperSignature @pytest.mark.django_db diff --git a/server/handler/migrations/__init__.py b/server/manifest/tests/serializers/__init__.py similarity index 100% rename from server/handler/migrations/__init__.py rename to server/manifest/tests/serializers/__init__.py diff --git a/server/handler/tests/test_handler_serializer.py b/server/manifest/tests/serializers/test_handler.py similarity index 94% rename from server/handler/tests/test_handler_serializer.py rename to server/manifest/tests/serializers/test_handler.py index ac388c4e9..ff50af2d5 100644 --- a/server/handler/tests/test_handler_serializer.py +++ b/server/manifest/tests/serializers/test_handler.py @@ -1,7 +1,7 @@ import pytest -from handler.models import Handler, PaperSignature -from handler.serializers import HandlerSerializer +from manifest.models import Handler, PaperSignature +from manifest.serializers import HandlerSerializer @pytest.mark.django_db diff --git a/server/manifest/tests/test_serializers.py b/server/manifest/tests/serializers/test_manifest.py similarity index 100% rename from server/manifest/tests/test_serializers.py rename to server/manifest/tests/serializers/test_manifest.py index 267c93d81..a6149f22c 100644 --- a/server/manifest/tests/test_serializers.py +++ b/server/manifest/tests/serializers/test_manifest.py @@ -1,8 +1,8 @@ import pytest +from wasteline.models import WasteLine from manifest.models import AdditionalInfo, Manifest from manifest.serializers import ManifestSerializer -from wasteline.models import WasteLine @pytest.fixture diff --git a/server/handler/tests/test_signature_serializer.py b/server/manifest/tests/serializers/test_signature.py similarity index 92% rename from server/handler/tests/test_signature_serializer.py rename to server/manifest/tests/serializers/test_signature.py index 3813c0c32..2e6c83b81 100644 --- a/server/handler/tests/test_signature_serializer.py +++ b/server/manifest/tests/serializers/test_signature.py @@ -1,7 +1,7 @@ import pytest -from handler.models import Signer -from handler.serializers import ESignatureSerializer +from manifest.models import Signer +from manifest.serializers import ESignatureSerializer @pytest.fixture diff --git a/server/handler/tests/__init__.py b/server/manifest/tests/services/__init__.py similarity index 100% rename from server/handler/tests/__init__.py rename to server/manifest/tests/services/__init__.py diff --git a/server/manifest/tests/test_emanifest_service.py b/server/manifest/tests/services/test_emanifest.py similarity index 100% rename from server/manifest/tests/test_emanifest_service.py rename to server/manifest/tests/services/test_emanifest.py index e22bc99a0..b9670d943 100644 --- a/server/manifest/tests/test_emanifest_service.py +++ b/server/manifest/tests/services/test_emanifest.py @@ -1,8 +1,8 @@ import pytest import pytest_mock +from core.services import RcraClient, get_rcra_client from rest_framework import status -from core.services import RcraClient, get_rcra_client from manifest.services import EManifest diff --git a/server/handler/tests/test_handler_services.py b/server/manifest/tests/services/test_handler.py similarity index 99% rename from server/handler/tests/test_handler_services.py rename to server/manifest/tests/services/test_handler.py index 7efa3a56a..e136008b4 100644 --- a/server/handler/tests/test_handler_services.py +++ b/server/manifest/tests/services/test_handler.py @@ -1,5 +1,4 @@ import pytest - from core.services import RcraClient from rcrasite.models import RcraSite from rcrasite.services import RcraSiteService diff --git a/server/manifest/tests/test_manifest_services.py b/server/manifest/tests/services/test_manifest.py similarity index 99% rename from server/manifest/tests/test_manifest_services.py rename to server/manifest/tests/services/test_manifest.py index 8438451bc..68f9370d6 100644 --- a/server/manifest/tests/test_manifest_services.py +++ b/server/manifest/tests/services/test_manifest.py @@ -4,6 +4,7 @@ class TestGetManifestService: + # ToDo: fix transaction related to this test def test_returns_manifests_from_all_user_sites_by_default( self, manifest_factory, diff --git a/server/manifest/tests/test_search_emanifest.py b/server/manifest/tests/services/test_search_emanifest.py similarity index 100% rename from server/manifest/tests/test_search_emanifest.py rename to server/manifest/tests/services/test_search_emanifest.py index b13f97bb3..59fb9c914 100644 --- a/server/manifest/tests/test_search_emanifest.py +++ b/server/manifest/tests/services/test_search_emanifest.py @@ -2,8 +2,8 @@ from datetime import UTC, datetime import pytest - from core.services import RcraClient + from manifest.services.emanifest_search import EmanifestSearch diff --git a/server/manifest/views.py b/server/manifest/views.py index 423c6fdeb..c3df83519 100644 --- a/server/manifest/views.py +++ b/server/manifest/views.py @@ -1,15 +1,15 @@ import logging from drf_spectacular.utils import OpenApiResponse, extend_schema, inline_serializer +from org.services import sync_site_manifest_with_rcrainfo from rest_framework import mixins, serializers, status, viewsets from rest_framework.generics import GenericAPIView, ListAPIView from rest_framework.request import Request from rest_framework.response import Response from rest_framework.views import APIView -from handler.serializers import QuickerSignSerializer from manifest.models import Manifest -from manifest.serializers import ManifestSerializer, MtnSerializer +from manifest.serializers import ManifestSerializer, MtnSerializer, QuickerSignSerializer from manifest.services import ( EManifest, TaskResponse, @@ -18,7 +18,6 @@ save_emanifest, update_manifest, ) -from org.services import sync_site_manifest_with_rcrainfo logger = logging.getLogger(__name__) diff --git a/server/org/fixtures/org_permissions.yaml b/server/org/fixtures/org_dev.yaml similarity index 67% rename from server/org/fixtures/org_permissions.yaml rename to server/org/fixtures/org_dev.yaml index 822e77a7c..2ab89481f 100644 --- a/server/org/fixtures/org_permissions.yaml +++ b/server/org/fixtures/org_dev.yaml @@ -1,3 +1,26 @@ +- model: org.org + pk: efb9e104-7f61-4365-a9af-9d7b55c854c4 + fields: + name: Generators Org LLC + admin: 8062d496-15f1-485d-961c-a8e5fa118dde + slug: generators-org-llc +- model: org.site + pk: 1 + fields: + name: VA TEST GEN 2021 + rcra_site: 1 + last_rcrainfo_manifest_sync: null + org: efb9e104-7f61-4365-a9af-9d7b55c854c4 +- model: org.siteuserobjectpermission + pk: 1 + fields: + permission: + - view_site + - org + - site + user: + - testuser1 + content_object: 1 - model: auth.group fields: name: Org admin diff --git a/server/profile/fixtures/profile_dev.yaml b/server/profile/fixtures/profile_dev.yaml new file mode 100644 index 000000000..8dd01c7d0 --- /dev/null +++ b/server/profile/fixtures/profile_dev.yaml @@ -0,0 +1,44 @@ +- model: profile.rcrainfoprofile + pk: d74f904a-7843-4a60-862c-3b94b6051359 + fields: + rcra_username: dpgraham4401 + phone_number: null + email: orgadmin@generator.com +- model: profile.rcrainfoprofile + pk: 1fd27bec-8743-4eb3-a44c-fd063ea62021 + fields: + rcra_username: "" + phone_number: null + email: superadmin@gmail.com +- model: profile.rcrainfoprofile + pk: 192c73f4-24f1-4f21-8239-dee2da43c547 + fields: + rcra_username: emanifestpyuser1 + phone_number: null + email: testuser1@haztrak.net +- model: profile.profile + pk: c65dbee9-b6bf-400e-93e0-90a749cc2939 + fields: + user: 8062d496-15f1-485d-961c-a8e5fa118dde + rcrainfo_profile: d74f904a-7843-4a60-862c-3b94b6051359 +- model: profile.profile + pk: 186642a9-7b5f-4bcb-b328-0fdf8b43f191 + fields: + user: a0ba4966-aa53-44c8-be1a-0a0d2d6b6acd + rcrainfo_profile: 1fd27bec-8743-4eb3-a44c-fd063ea62021 +- model: profile.profile + pk: 87e355dd-1898-4a0a-81c3-1e9ac8473143 + fields: + user: 4ac96f68-42cf-47ea-bffb-f24d423dbc35 + rcrainfo_profile: 192c73f4-24f1-4f21-8239-dee2da43c547 +- model: profile.rcrainfositeaccess + pk: 1 + fields: + site: 1 + profile: 192c73f4-24f1-4f21-8239-dee2da43c547 + site_manager: true + annual_report: Certifier + biennial_report: Certifier + e_manifest: Certifier + my_rcra_id: Certifier + wiets: Certifier diff --git a/server/rcrasite/fixtures/rcrasite_dev.yaml b/server/rcrasite/fixtures/rcrasite_dev.yaml new file mode 100644 index 000000000..88b0b323b --- /dev/null +++ b/server/rcrasite/fixtures/rcrasite_dev.yaml @@ -0,0 +1,93 @@ +- model: rcrasite.address + pk: 1 + fields: + street_number: null + address1: 123 VA TEST GEN 2021 WAY + address2: null + city: ARLINGTON + state: VA + country: US + zip: "22202" +- model: manifest.manifestphone + pk: 1 + fields: + number: 321-321-3214 + extension: null +- model: rcrasite.rcraphone + pk: 1 + fields: + number: 321-321-3214 + extension: null +- model: rcrasite.contact + pk: 1 + fields: + first_name: David + middle_initial: P + last_name: Graham + phone: 1 + email: testuser1@haztrak.net + company_name: haztrak +- model: rcrasite.rcrasite + pk: 1 + fields: + site_type: Generator + epa_id: VATESTGEN001 + name: VA TEST GEN 2021 + site_address: 1 + mail_address: 1 + modified: false + registered: false + contact: 1 + emergency_phone: null + gis_primary: false + can_esign: true + limited_esign: true + registered_emanifest_user: true +- model: rcrasite.rcrasite + pk: 2 + fields: + site_type: Transporter + epa_id: MOCKTRANS001 + name: Mock Transporter 01 + site_address: 1 + mail_address: 1 + modified: false + registered: false + contact: 1 + emergency_phone: null + gis_primary: false + can_esign: true + limited_esign: true + registered_emanifest_user: true +- model: rcrasite.rcrasite + pk: 3 + fields: + site_type: Transporter + epa_id: MOCKTRANS002 + name: Mock Transporter 02 + site_address: 1 + mail_address: 1 + modified: false + registered: false + contact: 1 + emergency_phone: null + gis_primary: false + can_esign: true + limited_esign: true + registered_emanifest_user: true +- model: rcrasite.rcrasite + pk: 4 + fields: + site_type: Tsdf + epa_id: MOCKTSDFS001 + name: Mock haztrak TSDF 01 + site_address: 1 + mail_address: 1 + modified: false + registered: false + contact: 1 + emergency_phone: null + gis_primary: false + can_esign: true + limited_esign: true + registered_emanifest_user: true diff --git a/server/wasteline/migrations/0001_initial.py b/server/wasteline/migrations/0001_initial.py index 182020625..1f77d1c39 100644 --- a/server/wasteline/migrations/0001_initial.py +++ b/server/wasteline/migrations/0001_initial.py @@ -1,66 +1,182 @@ -# Generated by Django 4.2.10 on 2024-02-21 22:17 +# Generated by Django 5.0.8 on 2024-08-22 16:38 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): - initial = True dependencies = [ - ('manifest', '0001_initial'), + ("manifest", "0001_initial"), ] operations = [ migrations.CreateModel( - name='DotLookup', + name="DotLookup", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('value', models.CharField(max_length=255)), - ('value_type', models.CharField(choices=[('ID', 'Id'), ('GROUP', 'Group'), ('NAME', 'Name'), ('CLASS', 'Class')], max_length=5)), + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("value", models.CharField(max_length=255)), + ( + "value_type", + models.CharField( + choices=[ + ("ID", "Id"), + ("GROUP", "Group"), + ("NAME", "Name"), + ("CLASS", "Class"), + ], + max_length=5, + ), + ), ], options={ - 'verbose_name': 'DOT lookup', - 'verbose_name_plural': 'DOT lookups', - 'ordering': ['value_type', 'value'], + "verbose_name": "DOT lookup", + "verbose_name_plural": "DOT lookups", + "ordering": ["value_type", "value"], }, ), migrations.CreateModel( - name='WasteCode', + name="WasteCode", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(max_length=6, unique=True)), - ('description', models.TextField(blank=True, null=True)), - ('code_type', models.CharField(choices=[('ST', 'State'), ('FD', 'Federal')], max_length=2)), - ('state_id', models.CharField(blank=True, choices=[('AK', 'Alaska'), ('AL', 'Alabama'), ('AP', 'Armed Forces Pacific'), ('AR', 'Arkansas'), ('AZ', 'Arizona'), ('CA', 'California'), ('CO', 'Colorado'), ('CT', 'Connecticut'), ('DC', 'District of Columbia'), ('DE', 'Delaware'), ('FL', 'Florida'), ('GA', 'Georgia'), ('GU', 'Guam'), ('HI', 'Hawaii'), ('IA', 'Iowa'), ('ID', 'Idaho'), ('IL', 'Illinois'), ('IN', 'Indiana'), ('KS', 'Kansas'), ('KY', 'Kentucky'), ('LA', 'Louisiana'), ('MA', 'Massachusetts'), ('MD', 'Maryland'), ('ME', 'Maine'), ('MI', 'Michigan'), ('MN', 'Minnesota'), ('MO', 'Missouri'), ('MS', 'Mississippi'), ('MT', 'Montana'), ('NC', 'North Carolina'), ('ND', 'North Dakota'), ('NE', 'Nebraska'), ('NH', 'New Hampshire'), ('NJ', 'New Jersey'), ('NM', 'New Mexico'), ('NV', 'Nevada'), ('NY', 'New York'), ('OH', 'Ohio'), ('OK', 'Oklahoma'), ('OR', 'Oregon'), ('PA', 'Pennsylvania'), ('PR', 'Puerto Rico'), ('RI', 'Rhode Island'), ('SC', 'South Carolina'), ('SD', 'South Dakota'), ('TN', 'Tennessee'), ('TX', 'Texas'), ('UT', 'Utah'), ('VA', 'Virginia'), ('VI', 'Virgin Islands'), ('VT', 'Vermont'), ('WA', 'Washington'), ('WI', 'Wisconsin'), ('WV', 'West Virginia'), ('WY', 'Wyoming')], max_length=3, null=True)), + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("code", models.CharField(max_length=6, unique=True)), + ("description", models.TextField(blank=True, null=True)), + ( + "code_type", + models.CharField(choices=[("ST", "State"), ("FD", "Federal")], max_length=2), + ), + ( + "state_id", + models.CharField( + blank=True, + choices=[ + ("AK", "Alaska"), + ("AL", "Alabama"), + ("AP", "Armed Forces Pacific"), + ("AR", "Arkansas"), + ("AZ", "Arizona"), + ("CA", "California"), + ("CO", "Colorado"), + ("CT", "Connecticut"), + ("DC", "District of Columbia"), + ("DE", "Delaware"), + ("FL", "Florida"), + ("GA", "Georgia"), + ("GU", "Guam"), + ("HI", "Hawaii"), + ("IA", "Iowa"), + ("ID", "Idaho"), + ("IL", "Illinois"), + ("IN", "Indiana"), + ("KS", "Kansas"), + ("KY", "Kentucky"), + ("LA", "Louisiana"), + ("MA", "Massachusetts"), + ("MD", "Maryland"), + ("ME", "Maine"), + ("MI", "Michigan"), + ("MN", "Minnesota"), + ("MO", "Missouri"), + ("MS", "Mississippi"), + ("MT", "Montana"), + ("NC", "North Carolina"), + ("ND", "North Dakota"), + ("NE", "Nebraska"), + ("NH", "New Hampshire"), + ("NJ", "New Jersey"), + ("NM", "New Mexico"), + ("NV", "Nevada"), + ("NY", "New York"), + ("OH", "Ohio"), + ("OK", "Oklahoma"), + ("OR", "Oregon"), + ("PA", "Pennsylvania"), + ("PR", "Puerto Rico"), + ("RI", "Rhode Island"), + ("SC", "South Carolina"), + ("SD", "South Dakota"), + ("TN", "Tennessee"), + ("TX", "Texas"), + ("UT", "Utah"), + ("VA", "Virginia"), + ("VI", "Virgin Islands"), + ("VT", "Vermont"), + ("WA", "Washington"), + ("WI", "Wisconsin"), + ("WV", "West Virginia"), + ("WY", "Wyoming"), + ], + max_length=3, + null=True, + ), + ), ], options={ - 'ordering': ['code'], + "ordering": ["code"], }, ), migrations.CreateModel( - name='WasteLine', + name="WasteLine", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('line_number', models.PositiveIntegerField(verbose_name='waste line number')), - ('dot_hazardous', models.BooleanField(verbose_name='DOT hazardous')), - ('dot_info', models.JSONField(blank=True, null=True, verbose_name='DOT information')), - ('quantity', models.JSONField(blank=True, null=True)), - ('hazardous_waste', models.JSONField(blank=True, null=True)), - ('br', models.BooleanField(verbose_name='BR info provided')), - ('br_info', models.JSONField(blank=True, null=True, verbose_name='BR information')), - ('management_method', models.JSONField(blank=True, null=True, verbose_name='management method code')), - ('pcb', models.BooleanField(verbose_name='contains PCBs')), - ('pcb_infos', models.JSONField(blank=True, null=True, verbose_name='PCB information')), - ('discrepancy_info', models.JSONField(blank=True, null=True, verbose_name='discrepancy-residue information')), - ('epa_waste', models.BooleanField(verbose_name='EPA waste')), - ('additional_info', models.JSONField(blank=True, null=True)), - ('manifest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wastes', to='manifest.manifest')), + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("line_number", models.PositiveIntegerField(verbose_name="waste line number")), + ("dot_hazardous", models.BooleanField(verbose_name="DOT hazardous")), + ( + "dot_info", + models.JSONField(blank=True, null=True, verbose_name="DOT information"), + ), + ("quantity", models.JSONField(blank=True, null=True)), + ("hazardous_waste", models.JSONField(blank=True, null=True)), + ("br", models.BooleanField(verbose_name="BR info provided")), + ( + "br_info", + models.JSONField(blank=True, null=True, verbose_name="BR information"), + ), + ( + "management_method", + models.JSONField(blank=True, null=True, verbose_name="management method code"), + ), + ("pcb", models.BooleanField(verbose_name="contains PCBs")), + ( + "pcb_infos", + models.JSONField(blank=True, null=True, verbose_name="PCB information"), + ), + ( + "discrepancy_info", + models.JSONField( + blank=True, null=True, verbose_name="discrepancy-residue information" + ), + ), + ("epa_waste", models.BooleanField(verbose_name="EPA waste")), + ("additional_info", models.JSONField(blank=True, null=True)), + ( + "manifest", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="wastes", + to="manifest.manifest", + ), + ), ], options={ - 'ordering': ['manifest__mtn', 'line_number'], - 'unique_together': {('manifest', 'line_number')}, + "ordering": ["manifest__mtn", "line_number"], + "unique_together": {("manifest", "line_number")}, }, ), ]