diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 00000000..67060712 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,26 @@ +name: Lint and format code + +on: + pull_request: + schedule: + # run once a week on early monday mornings + - cron: '22 2 * * 1' + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - uses: actions/setup-node@v4 + with: + node-version: 18 + - name: Install dependencies + run: | + npm i + python -m pip install --upgrade pip wheel + pip install pre-commit==3.6.2 + - name: Run pre-commit + run: pre-commit run --all-files diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6c81b5ba..84b7d71f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -name: Lint and Test code +name: Test and build code on: pull_request: @@ -8,7 +8,7 @@ on: jobs: test: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest env: DJANGO_SETTINGS_MODULE: config.settings.test services: @@ -44,11 +44,6 @@ jobs: restore-keys: | ${{ runner.os }}-docker- ${{ runner.os }}- - - name: Run eslint + format - run: | - npm i - npm run lint - npx prettier --check . - name: Build Docker Deploy Image uses: docker/build-push-action@v5 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a31b6809..fb85ec4d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,13 +4,22 @@ repos: hooks: - id: django-upgrade args: [--target-version, "4.2"] - # - repo: https://github.com/python/black - # rev: 22.3.0 - # hooks: - # - id: black - # language_version: python3 - - repo: https://github.com/pre-commit/mirrors-prettier - rev: "v3.1.0" + - repo: https://github.com/python/black + rev: "23.12.1" hooks: - - id: prettier - args: [--config=./.prettierrc] + - id: black + language_version: python3.12 + args: [--config=./pyproject.toml] + - repo: local + hooks: + - id: format + name: Run formatter (prettier) + language: system + entry: npx prettier --write --ignore-unknown + files: ".*\\.(js|jsx)$" + - id: lint + name: Run linter (eslint) + language: system + entry: npx eslint --fix + files: ".*\\.(js|jsx)$" + diff --git a/bin/get_annotations.py b/bin/get_annotations.py index 3ded9e1e..de06c24f 100644 --- a/bin/get_annotations.py +++ b/bin/get_annotations.py @@ -18,8 +18,9 @@ def get_annotations(template): annotations = pdf.pages[0]["/Annots"] print("Here is a list of annotations in the document.\n") for annotation in annotations: - annotation_name = annotation['/T'] + annotation_name = annotation["/T"] print(annotation_name) -if __name__ == '__main__': - sys.exit(get_annotations()) \ No newline at end of file + +if __name__ == "__main__": + sys.exit(get_annotations()) diff --git a/config/settings/base.py b/config/settings/base.py index a525eb70..33300a70 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -148,9 +148,7 @@ ] # https://docs.djangoproject.com/en/dev/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ - { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator" - }, + {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"}, {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"}, {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"}, {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, @@ -246,9 +244,7 @@ # EMAIL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#email-backend -EMAIL_BACKEND = env( - "DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend" -) +EMAIL_BACKEND = env("DJANGO_EMAIL_BACKEND", default="django.core.mail.backends.smtp.EmailBackend") # ADMIN # ------------------------------------------------------------------------------ @@ -322,6 +318,4 @@ ] SENDGRID_ALLOWED_SENDERS = env.list("SENDGRID_ALLOWED_SENDERS", default=[]) -SENDGRID_WEBHOOK_LISTENERS = ( - "dear_petition.petition.etl.email.sendgrid_webhook_listener", -) +SENDGRID_WEBHOOK_LISTENERS = ("dear_petition.petition.etl.email.sendgrid_webhook_listener",) diff --git a/config/settings/local.py b/config/settings/local.py index e648724b..ed2947b9 100644 --- a/config/settings/local.py +++ b/config/settings/local.py @@ -75,8 +75,7 @@ "disable_existing_loggers": False, "formatters": { "verbose": { - "format": "%(levelname)s %(asctime)s %(name)s " - "%(process)d %(thread)d %(message)s" + "format": "%(levelname)s %(asctime)s %(name)s " "%(process)d %(thread)d %(message)s" } }, "handlers": { diff --git a/config/settings/production.py b/config/settings/production.py index 58bfbe19..485e3e03 100644 --- a/config/settings/production.py +++ b/config/settings/production.py @@ -62,15 +62,11 @@ # TODO: set this to 60 seconds first and then to 518400 once you prove the former works SECURE_HSTS_SECONDS = 60 # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-include-subdomains -SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool( - "DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True -) +SECURE_HSTS_INCLUDE_SUBDOMAINS = env.bool("DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS", default=True) # https://docs.djangoproject.com/en/dev/ref/settings/#secure-hsts-preload SECURE_HSTS_PRELOAD = env.bool("DJANGO_SECURE_HSTS_PRELOAD", default=True) # https://docs.djangoproject.com/en/dev/ref/middleware/#x-content-type-options-nosniff -SECURE_CONTENT_TYPE_NOSNIFF = env.bool( - "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True -) +SECURE_CONTENT_TYPE_NOSNIFF = env.bool("DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True) # STORAGES # ------------------------------------------------------------------------------ @@ -146,9 +142,7 @@ class MediaRootS3Boto3Storage(S3Boto3Storage): # EMAIL # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#default-from-email -DEFAULT_FROM_EMAIL = env( - "DJANGO_DEFAULT_FROM_EMAIL", default=f"DEAR Petition <{ALLOWED_HOSTS[0]}>" -) +DEFAULT_FROM_EMAIL = env("DJANGO_DEFAULT_FROM_EMAIL", default=f"DEAR Petition <{ALLOWED_HOSTS[0]}>") # https://docs.djangoproject.com/en/dev/ref/settings/#server-email SERVER_EMAIL = env("DJANGO_SERVER_EMAIL", default=DEFAULT_FROM_EMAIL) # https://docs.djangoproject.com/en/dev/ref/settings/#email-subject-prefix @@ -183,8 +177,7 @@ class MediaRootS3Boto3Storage(S3Boto3Storage): "disable_existing_loggers": True, "formatters": { "verbose": { - "format": "%(levelname)s %(asctime)s %(name)s " - "%(process)d %(thread)d %(message)s" + "format": "%(levelname)s %(asctime)s %(name)s " "%(process)d %(thread)d %(message)s" } }, "handlers": { diff --git a/config/wsgi.py b/config/wsgi.py index 2fd55e0e..774061d2 100644 --- a/config/wsgi.py +++ b/config/wsgi.py @@ -20,9 +20,7 @@ # This allows easy placement of apps within the interior # dear_petition directory. -app_path = os.path.abspath( - os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) -) +app_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)) sys.path.append(os.path.join(app_path, "dear_petition")) # We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks # if running multiple sites in the same mod_wsgi process. To fix this, use diff --git a/dear_petition/__init__.py b/dear_petition/__init__.py index 8efa8c0e..8a6c4ad7 100644 --- a/dear_petition/__init__.py +++ b/dear_petition/__init__.py @@ -2,10 +2,7 @@ __version__ = "0.1.0" __version_info__ = tuple( - [ - int(num) if num.isdigit() else num - for num in __version__.replace("-", ".", 1).split(".") - ] + [int(num) if num.isdigit() else num for num in __version__.replace("-", ".", 1).split(".")] ) __all__ = ("celery_app",) diff --git a/dear_petition/contrib/sites/migrations/0001_initial.py b/dear_petition/contrib/sites/migrations/0001_initial.py index 304cd6d7..59647c85 100644 --- a/dear_petition/contrib/sites/migrations/0001_initial.py +++ b/dear_petition/contrib/sites/migrations/0001_initial.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [] operations = [ diff --git a/dear_petition/contrib/sites/migrations/0002_alter_domain_unique.py b/dear_petition/contrib/sites/migrations/0002_alter_domain_unique.py index 2c8d6dac..4359049f 100644 --- a/dear_petition/contrib/sites/migrations/0002_alter_domain_unique.py +++ b/dear_petition/contrib/sites/migrations/0002_alter_domain_unique.py @@ -3,7 +3,6 @@ class Migration(migrations.Migration): - dependencies = [("sites", "0001_initial")] operations = [ diff --git a/dear_petition/contrib/sites/migrations/0003_set_site_domain_and_name.py b/dear_petition/contrib/sites/migrations/0003_set_site_domain_and_name.py index 94295d46..9b534198 100644 --- a/dear_petition/contrib/sites/migrations/0003_set_site_domain_and_name.py +++ b/dear_petition/contrib/sites/migrations/0003_set_site_domain_and_name.py @@ -24,7 +24,6 @@ def update_site_backward(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [("sites", "0002_alter_domain_unique")] operations = [migrations.RunPython(update_site_forward, update_site_backward)] diff --git a/dear_petition/contrib/sites/migrations/0004_alter_site_options.py b/dear_petition/contrib/sites/migrations/0004_alter_site_options.py index 686a8ddc..56b13616 100644 --- a/dear_petition/contrib/sites/migrations/0004_alter_site_options.py +++ b/dear_petition/contrib/sites/migrations/0004_alter_site_options.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("sites", "0003_set_site_domain_and_name"), ] diff --git a/dear_petition/petition/admin.py b/dear_petition/petition/admin.py index 9b65f89c..ccdacab4 100644 --- a/dear_petition/petition/admin.py +++ b/dear_petition/petition/admin.py @@ -8,7 +8,6 @@ @admin.register(models.CIPRSRecord) class CIPRSRecordAdmin(admin.ModelAdmin): - list_display = ( "pk", "label", @@ -160,6 +159,7 @@ class ContactAdmin(admin.ModelAdmin): list_filter = ("category",) ordering = ("category", "name") + @admin.register(models.Agency) class AgencyAdmin(ImportExportModelAdmin): resource_classes = [resources.AgencyResource] @@ -168,6 +168,7 @@ class AgencyAdmin(ImportExportModelAdmin): list_filter = ("category",) ordering = ("category", "name") + @admin.register(models.Client) class ClientAdmin(admin.ModelAdmin): list_display = ("pk", "name", "category", "address1") @@ -177,7 +178,6 @@ class ClientAdmin(admin.ModelAdmin): @admin.register(models.Comment) class CommentAdmin(admin.ModelAdmin): - list_display = ("pk", "user", "batch", "time") search_fields = ("batch__label",) date_hierarchy = "time" @@ -187,7 +187,6 @@ class CommentAdmin(admin.ModelAdmin): @admin.register(models.Petition) class PetitionAdmin(admin.ModelAdmin): - list_display = ("pk", "batch", "form_type", "county", "jurisdiction") search_fields = ("batch__label",) list_filter = ("form_type", "county", "jurisdiction") @@ -197,7 +196,6 @@ class PetitionAdmin(admin.ModelAdmin): @admin.register(models.PetitionDocument) class PetitionDocumentAdmin(admin.ModelAdmin): - list_display = ( "id", "batch", @@ -215,9 +213,7 @@ class PetitionDocumentAdmin(admin.ModelAdmin): def get_queryset(self, request): queryset = super().get_queryset(request) - queryset = queryset.annotate( - _offense_record_count=Count("offense_records", distinct=True) - ) + queryset = queryset.annotate(_offense_record_count=Count("offense_records", distinct=True)) return queryset def offense_record_count(self, obj): @@ -234,7 +230,6 @@ def is_an_attachment(self, obj): @admin.register(models.GeneratedPetition) class GeneratedPetitionAdmin(admin.ModelAdmin): - date_hierarchy = "created" list_display = constants.GENERATED_PETITION_ADMIN_FIELDS list_filter = ("form_type", "created", "username") diff --git a/dear_petition/petition/api/fields.py b/dear_petition/petition/api/fields.py index 87eeb493..ed794dce 100644 --- a/dear_petition/petition/api/fields.py +++ b/dear_petition/petition/api/fields.py @@ -1,5 +1,6 @@ from rest_framework import serializers + class ValidationField(serializers.SerializerMethodField): def __init__(self, serializer, **kwargs): self.serializer_class = serializer @@ -13,12 +14,12 @@ def bind(self, field_name, parent): super().bind(field_name, parent) if self.serializer_class == self.parent: - raise ValueError('Validation serializer must not be parent of this serializer field') + raise ValueError("Validation serializer must not be parent of this serializer field") def to_representation(self, value): # handle case where serializer is creating new value # TODO: Figure out how to get instance/native values for a new instance - if not hasattr(value, 'pk'): + if not hasattr(value, "pk"): return None method = getattr(self.parent, self.method_name) try: @@ -27,4 +28,3 @@ def to_representation(self, value): return {} except serializers.ValidationError as exc: return exc.detail - diff --git a/dear_petition/petition/api/serializers.py b/dear_petition/petition/api/serializers.py index 6b2063e7..3c522ae4 100644 --- a/dear_petition/petition/api/serializers.py +++ b/dear_petition/petition/api/serializers.py @@ -49,9 +49,7 @@ def get_admin_url(self, user_obj): def create(self, validated_data): random_pw = User.objects.make_random_password() is_admin = validated_data.get("is_staff", False) - return User.objects.create_user( - password=random_pw, is_superuser=is_admin, **validated_data - ) + return User.objects.create_user(password=random_pw, is_superuser=is_admin, **validated_data) class OffenseRecordSerializer(serializers.ModelSerializer): @@ -141,6 +139,7 @@ class Meta: "zipcode", ] + class AgencySerializer(ContactSerializer): class Meta: model = Agency @@ -185,7 +184,6 @@ class Meta: class GeneratePetitionSerializer(serializers.Serializer): - documents = serializers.PrimaryKeyRelatedField( many=True, queryset=PetitionDocument.objects.all() ) @@ -200,29 +198,33 @@ def validate_documents(self, value): raise serializers.ValidationError( "There are no documents selected for download for the petition document." ) - petition_id = self.get_initial().get('petition') + petition_id = self.get_initial().get("petition") for doc in value: if doc.petition.pk != petition_id: - raise serializers.ValidationError('Documents must be associated with this petition.') + raise serializers.ValidationError( + "Documents must be associated with this petition." + ) return value def validate_petition(self, value): errors = {} if not value.batch.client: - errors['client'] = ["A client has not been selected for this batch."] + errors["client"] = ["A client has not been selected for this batch."] if not value.batch.attorney: - errors['attorney'] = ["An attorney has not been selected for this batch."] + errors["attorney"] = ["An attorney has not been selected for this batch."] if not value.agencies.exists(): - errors['agencies'] = ["There are no agencies selected for the petition."] - if not value.get_all_offense_records(filter_active=True, include_annotations=False).exists(): + errors["agencies"] = ["There are no agencies selected for the petition."] + if not value.get_all_offense_records( + filter_active=True, include_annotations=False + ).exists(): if value.form_type == UNDERAGED_CONVICTIONS: errors[UNDERAGED_CONVICTIONS] = [ - 'Additional verification is needed to include offense records in this petition form' + "Additional verification is needed to include offense records in this petition form" ] else: - errors['offense records'] = [ - 'There are no records selected for the petition document.', - 'Please review the list of offense records and update the petition to include offense records if needed.' + errors["offense records"] = [ + "There are no records selected for the petition document.", + "Please review the list of offense records and update the petition to include offense records if needed.", ] if errors: raise serializers.ValidationError(errors) @@ -233,7 +235,7 @@ class PetitionSerializer(serializers.ModelSerializer): generation_errors = ValidationField(serializer=GeneratePetitionSerializer) def get_generation_errors_data(self, obj): - return {'documents': obj.documents.all().values_list('pk', flat=True), 'petition': obj.pk} + return {"documents": obj.documents.all().values_list("pk", flat=True), "petition": obj.pk} class Meta: model = Petition @@ -282,9 +284,7 @@ class Meta(PetitionSerializer.Meta): def get_base_document(self, instance): return PetitionDocumentSerializer( - PetitionDocument.objects.get( - petition_id=instance.id, previous_document__isnull=True - ) + PetitionDocument.objects.get(petition_id=instance.id, previous_document__isnull=True) ).data def get_attachments(self, instance): @@ -300,13 +300,12 @@ def get_offense_records(self, petition): return OffenseRecordSerializer(offense_records, many=True).data def get_active_records(self, petition): - return petition.offense_records.filter( - petitionoffenserecord__active=True - ).values_list("id", flat=True) + return petition.offense_records.filter(petitionoffenserecord__active=True).values_list( + "id", flat=True + ) class GenerateDocumentSerializer(serializers.Serializer): - batch = serializers.PrimaryKeyRelatedField(queryset=Batch.objects.all()) def validate_batch(self, value): @@ -322,11 +321,15 @@ def validate_batch(self, value): class BatchSerializer(serializers.ModelSerializer): records = CIPRSRecordSerializer(many=True, read_only=True) petitions = PetitionSerializer(many=True, read_only=True) - generate_letter_errors = ValidationField(method_name='get_generate_errors_data', serializer=GenerateDocumentSerializer) - generate_summary_errors = ValidationField(method_name='get_generate_errors_data', serializer=GenerateDocumentSerializer) - + generate_letter_errors = ValidationField( + method_name="get_generate_errors_data", serializer=GenerateDocumentSerializer + ) + generate_summary_errors = ValidationField( + method_name="get_generate_errors_data", serializer=GenerateDocumentSerializer + ) + def get_generate_errors_data(self, obj): - return {'batch': obj.pk} + return {"batch": obj.pk} class Meta: model = Batch @@ -348,20 +351,27 @@ class BatchDetailSerializer(serializers.ModelSerializer): records = CIPRSRecordSerializer(many=True, read_only=True) petitions = serializers.SerializerMethodField() attorney_id = serializers.PrimaryKeyRelatedField( - source='attorney', queryset=Contact.objects.filter(category='attorney'), write_only=True, required=False + source="attorney", + queryset=Contact.objects.filter(category="attorney"), + write_only=True, + required=False, ) attorney = ContactSerializer(read_only=True) client_id = serializers.PrimaryKeyRelatedField( - source='client', queryset=Client.objects.all(), write_only=True, required=False + source="client", queryset=Client.objects.all(), write_only=True, required=False ) client = ClientSerializer(read_only=True) client_errors = serializers.SerializerMethodField() - generate_letter_errors = ValidationField(method_name='get_generate_errors_data', serializer=GenerateDocumentSerializer) - generate_summary_errors = ValidationField(method_name='get_generate_errors_data', serializer=GenerateDocumentSerializer) + generate_letter_errors = ValidationField( + method_name="get_generate_errors_data", serializer=GenerateDocumentSerializer + ) + generate_summary_errors = ValidationField( + method_name="get_generate_errors_data", serializer=GenerateDocumentSerializer + ) def get_generate_errors_data(self, obj): - return {'batch': obj.pk} + return {"batch": obj.pk} class Meta: model = Batch @@ -378,7 +388,7 @@ class Meta: "client_id", "generate_letter_errors", "generate_summary_errors", - "client_errors" + "client_errors", ] read_only_fields = ["user", "pk", "date_uploaded", "records", "petitions"] @@ -388,13 +398,15 @@ def get_petitions(self, instance): batch=instance.pk, ).order_by("county", "jurisdiction") return ParentPetitionSerializer(parent_petitions, many=True).data - + def get_client_errors(self, instance): errors = [] if not instance.client: return errors if not instance.client.dob: - errors.append("Date of birth missing. The petition generator will try its best to identify a date of birth from the records at time of petition creation.") + errors.append( + "Date of birth missing. The petition generator will try its best to identify a date of birth from the records at time of petition creation." + ) return errors @@ -441,7 +453,6 @@ def validate(self, attrs): class DataPetitionSerializer(serializers.Serializer): - form_type = serializers.ChoiceField( choices=((DISMISSED, DISMISSED), (ATTACHMENT, ATTACHMENT)), initial=DISMISSED ) diff --git a/dear_petition/petition/api/tests/conftest.py b/dear_petition/petition/api/tests/conftest.py index 3ed136b6..1b7797a1 100644 --- a/dear_petition/petition/api/tests/conftest.py +++ b/dear_petition/petition/api/tests/conftest.py @@ -18,9 +18,7 @@ def api_client(api_client_anon, user): @pytest.fixture def mock_import(): - with mock.patch( - "dear_petition.petition.api.viewsets.import_ciprs_records" - ) as mock_: + with mock.patch("dear_petition.petition.api.viewsets.import_ciprs_records") as mock_: batch = mock_.return_value batch.pk = batch.id = 99 yield mock_ diff --git a/dear_petition/petition/api/tests/test_batch.py b/dear_petition/petition/api/tests/test_batch.py index cc87ac71..26c9004d 100644 --- a/dear_petition/petition/api/tests/test_batch.py +++ b/dear_petition/petition/api/tests/test_batch.py @@ -7,7 +7,13 @@ from rest_framework import status -from dear_petition.petition.tests.factories import BatchFactory, CIPRSRecordFactory, OffenseFactory, ClientFactory, OffenseRecordFactory +from dear_petition.petition.tests.factories import ( + BatchFactory, + CIPRSRecordFactory, + OffenseFactory, + ClientFactory, + OffenseRecordFactory, +) pytestmark = pytest.mark.django_db @@ -34,37 +40,36 @@ def test_batch_post_multiple_files(api_client, fake_pdf, fake_pdf2, mock_import) assert mock_import.assert_called_once assert "id" in response.data + def test_adjust_for_new_client_dob(): """Test that when a DOB is added or updated on the client, the batch is updated accordingly.""" batch = BatchFactory() - record = CIPRSRecordFactory(batch=batch, offense_date=datetime.date(2000,1,1), dob=None) - offense = OffenseFactory(ciprs_record=record, disposition_method="OTHER") # Conviction charge - offense_record = OffenseRecordFactory( - action="CONVICTED", offense=offense - ) + record = CIPRSRecordFactory(batch=batch, offense_date=datetime.date(2000, 1, 1), dob=None) + offense = OffenseFactory(ciprs_record=record, disposition_method="OTHER") # Conviction charge + offense_record = OffenseRecordFactory(action="CONVICTED", offense=offense) - client = ClientFactory(dob=timezone.now().date()) # Create a youngster + client = ClientFactory(dob=timezone.now().date()) # Create a youngster batch.client = client batch.save() batch.adjust_for_new_client_dob() assert offense_record in batch.underaged_conviction_records() - batch.client.dob = datetime.date(1800,1,1) # Update the youngster to be an elder + batch.client.dob = datetime.date(1800, 1, 1) # Update the youngster to be an elder batch.client.save() - batch.refresh_from_db() # adjust_for_new_client_dob should get automatically called in Client save + batch.refresh_from_db() # adjust_for_new_client_dob should get automatically called in Client save assert offense_record not in batch.underaged_conviction_records() - client = ClientFactory(dob=datetime.date(1800,1,1)) # Create an elder + client = ClientFactory(dob=datetime.date(1800, 1, 1)) # Create an elder batch.client = client batch.save() batch.adjust_for_new_client_dob() assert offense_record not in batch.underaged_conviction_records() - batch.client.dob = timezone.now().date() # Update the elder to be a youngster + batch.client.dob = timezone.now().date() # Update the elder to be a youngster batch.client.save() - batch.refresh_from_db() # adjust_for_new_client_dob should get automatically called in Client save + batch.refresh_from_db() # adjust_for_new_client_dob should get automatically called in Client save assert offense_record in batch.underaged_conviction_records() # try un-setting client to test default behavior when no DOB known diff --git a/dear_petition/petition/api/tests/test_serializers.py b/dear_petition/petition/api/tests/test_serializers.py index 17b9793c..d051218b 100644 --- a/dear_petition/petition/api/tests/test_serializers.py +++ b/dear_petition/petition/api/tests/test_serializers.py @@ -9,10 +9,7 @@ class TestOffenseRecordSerializer: def test_offense_date(self): record = OffenseRecordFactory() serializer = OffenseRecordSerializer(record) - assert ( - serializer.data["offense_date"] - == record.offense.ciprs_record.offense_date.date() - ) + assert serializer.data["offense_date"] == record.offense.ciprs_record.offense_date.date() def test_offense_date_none(self): record = OffenseRecordFactory(offense__ciprs_record__offense_date=None) diff --git a/dear_petition/petition/api/tests/test_viewsets.py b/dear_petition/petition/api/tests/test_viewsets.py index 40342030..2a0f6ca8 100644 --- a/dear_petition/petition/api/tests/test_viewsets.py +++ b/dear_petition/petition/api/tests/test_viewsets.py @@ -48,9 +48,7 @@ def test_user_permissions(self): batch_list_user_owns = [self.batch_1, self.batch_2, self.batch_3] batch_list_user_owns_labels = [batch.label for batch in batch_list_user_owns] batch_list_other_user_owns = [self.batch_4, self.batch_5] - batch_list_other_user_owns_labels = [ - batch.label for batch in batch_list_other_user_owns - ] + batch_list_other_user_owns_labels = [batch.label for batch in batch_list_other_user_owns] self.client.force_authenticate(user=self.user) response = self.client.get(self.list_url) # assert that the result count equals the amount of batches the user owns @@ -73,9 +71,7 @@ def test_superuser_permissions(self): self.batch_4, self.batch_5, ] - batch_list_for_superuser_labels = [ - batch.label for batch in batch_list_for_superuser - ] + batch_list_for_superuser_labels = [batch.label for batch in batch_list_for_superuser] self.client.force_authenticate(user=self.user) response = self.client.get(self.list_url) # assert that the result count equals the amount of batches the superuser "owns" diff --git a/dear_petition/petition/api/viewsets.py b/dear_petition/petition/api/viewsets.py index 0b42c0a8..16dae2da 100644 --- a/dear_petition/petition/api/viewsets.py +++ b/dear_petition/petition/api/viewsets.py @@ -45,7 +45,6 @@ class UserViewSet(viewsets.ModelViewSet): - queryset = User.objects.all() serializer_class = serializers.UserSerializer filter_backends = [filters.OrderingFilter, filters.SearchFilter] @@ -77,7 +76,6 @@ def perform_create(self, serializer): class CIPRSRecordViewSet(viewsets.ModelViewSet): - queryset = pm.CIPRSRecord.objects.all() serializer_class = serializers.CIPRSRecordSerializer permission_classes = [permissions.IsAuthenticated] @@ -101,9 +99,7 @@ class OffenseRecordViewSet(viewsets.ModelViewSet): def get_petition_records(self, request): petition_id = request.GET.get("petition") if not petition_id: - return Response( - "No petition id provided.", status=status.HTTP_400_BAD_REQUEST - ) + return Response("No petition id provided.", status=status.HTTP_400_BAD_REQUEST) try: pet = pm.Petition.objects.get(id=petition_id) @@ -115,9 +111,7 @@ def get_petition_records(self, request): offense_records = pet.get_all_offense_records(filter_active=False) active_records = list( - offense_records.filter(petitionoffenserecord__active=True).values_list( - "id", flat=True - ) + offense_records.filter(petitionoffenserecord__active=True).values_list("id", flat=True) ) serialized_data = { "offense_records": self.get_serializer(offense_records, many=True).data, @@ -136,8 +130,9 @@ def get_search_fields(self, view, request): temp_files = {} -class ContactViewSet(viewsets.ModelViewSet): + +class ContactViewSet(viewsets.ModelViewSet): queryset = pm.Contact.objects.all() permission_classes = [permissions.IsAuthenticated] filter_backends = [filters.OrderingFilter, DjangoFilterBackend, ContactSearchFilter] @@ -211,7 +206,7 @@ def get_queryset(self): @action(detail=False, methods=["put"]) def preview_import_agencies(self, request): - file_data = request.data.get('file') + file_data = request.data.get("file") dataset = tablib.Dataset().load(file_data) resource = resources.AgencyResource() result = resource.import_data(dataset, dry_run=True) @@ -220,42 +215,64 @@ def preview_import_agencies(self, request): for row_index, row_errors in result.row_errors(): row_number = row_index + 1 row_errors_dict[row_number] = [str(e.error) for e in row_errors] - + row_diffs = [] for row_result in result.valid_rows(): - address = f"{row_result.instance.address1}, {row_result.instance.address2}" if row_result.instance.address2 else row_result.instance.address1 + address = ( + f"{row_result.instance.address1}, {row_result.instance.address2}" + if row_result.instance.address2 + else row_result.instance.address1 + ) row_diff = { - 'name': row_result.instance.name, - 'address': address, - 'city': row_result.instance.city, - 'state': row_result.instance.state, - 'zipcode': row_result.instance.zipcode, - 'county': row_result.instance.county, - 'is_sheriff': row_result.instance.is_sheriff, + "name": row_result.instance.name, + "address": address, + "city": row_result.instance.city, + "state": row_result.instance.state, + "zipcode": row_result.instance.zipcode, + "county": row_result.instance.county, + "is_sheriff": row_result.instance.is_sheriff, } if row_result.import_type == RowResult.IMPORT_TYPE_SKIP: continue elif row_result.import_type == RowResult.IMPORT_TYPE_NEW: - row_diff['new_fields'] = ['name', 'address', 'city', 'state', 'zipcode', 'county', 'is_sheriff'] + row_diff["new_fields"] = [ + "name", + "address", + "city", + "state", + "zipcode", + "county", + "is_sheriff", + ] else: - original_address = f"{row_result.original.address1}, {row_result.original.address2}" if row_result.instance.address2 else row_result.original.address1 - row_diff['new_fields'] = [] + original_address = ( + f"{row_result.original.address1}, {row_result.original.address2}" + if row_result.instance.address2 + else row_result.original.address1 + ) + row_diff["new_fields"] = [] if original_address != address: - row_diff['new_fields'].append('address') + row_diff["new_fields"].append("address") - for field in ['name', 'city', 'state', 'zipcode', 'county', 'is_sheriff']: + for field in ["name", "city", "state", "zipcode", "county", "is_sheriff"]: if getattr(row_result.original, field) != getattr(row_result.instance, field): - row_diff['new_fields'].append(field) - - if len(row_diff['new_fields']) > 0: + row_diff["new_fields"].append(field) + + if len(row_diff["new_fields"]) > 0: row_diffs.append(row_diff) - return Response({'has_errors': result.has_errors(), 'row_errors': row_errors_dict, 'row_diffs': row_diffs}) + return Response( + { + "has_errors": result.has_errors(), + "row_errors": row_errors_dict, + "row_diffs": row_diffs, + } + ) @action(detail=False, methods=["put"]) def import_agencies(self, request): - file_data = request.data.get('file') + file_data = request.data.get("file") dataset = tablib.Dataset().load(file_data) resources.AgencyResource().import_data(dataset, raise_errors=True) return Response({}) @@ -273,9 +290,7 @@ def get_queryset(self): class BatchViewSet(viewsets.ModelViewSet): - queryset = pm.Batch.objects.prefetch_related( - "petitions", "records__offenses__offense_records" - ) + queryset = pm.Batch.objects.prefetch_related("petitions", "records__offenses__offense_records") permission_classes = [permissions.IsAuthenticated] parser_classes = (parsers.MultiPartParser, parsers.FormParser, parsers.JSONParser) filter_backends = [filters.OrderingFilter, DjangoFilterBackend] @@ -363,7 +378,7 @@ def generate_summary(self, request, pk): ] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" resp["Content-Disposition"] = 'attachment; filename="Records Summary.docx"' return resp - + @action( detail=True, methods=[ @@ -391,8 +406,8 @@ def generate_spreadsheet(self, request, pk): ], ) def combine_batches(self, request): - batch_ids = request.data['batchIds'] - label = request.data['label'] + batch_ids = request.data["batchIds"] + label = request.data["label"] user_id = request.user.id if not batch_ids: @@ -401,12 +416,13 @@ def combine_batches(self, request): ) if not label: return Response( - "A new label needs to be included for the client.", status=status.HTTP_400_BAD_REQUEST + "A new label needs to be included for the client.", + status=status.HTTP_400_BAD_REQUEST, ) new_batch = combine_batches(batch_ids, label, user_id) return Response(self.get_serializer(new_batch).data) - + @action( detail=True, methods=[ @@ -414,20 +430,18 @@ def combine_batches(self, request): ], ) def assign_client_to_batch(self, request, pk): - client_id = request.data['client_id'] + client_id = request.data["client_id"] try: client = pm.Client.objects.get(pk=client_id) except pm.Client.DoesNotExist: - return Response( - "Unknown client.", status=status.HTTP_400_BAD_REQUEST - ) + return Response("Unknown client.", status=status.HTTP_400_BAD_REQUEST) batch = self.get_object() batch.client = client batch.save() batch.adjust_for_new_client_dob() return Response({"batch_id": batch.pk}) - + @action( detail=False, methods=[ @@ -441,7 +455,7 @@ def import_spreadsheet(self, request): for file in files: label = os.path.basename(file.name) batch = pm.Batch.objects.create(label=label, user=user) - batch.files.create(file=file) + batch.files.create(file=file) file.seek(0) workbook = load_workbook(filename=file) resource.import_data(workbook, batch) @@ -471,9 +485,7 @@ def create(self, request, *args, **kwargs): serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) - return Response( - serializer.data, status=status.HTTP_201_CREATED, headers=headers - ) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) @action( detail=True, @@ -536,9 +548,7 @@ def generate_petition_pdf(self, request, pk=None): pk__in=serializer.data["documents"], form_type__in=constants.PETITION_FORM_TYPES._db_values, ).order_by("pk") - assert ( - len(petition_documents) > 0 - ), "Petition documents could not be found for petition" + assert len(petition_documents) > 0, "Petition documents could not be found for petition" form_context = serializer.validated_data.copy() form_context["client"] = client @@ -589,7 +599,6 @@ def generate_petition_pdf(self, request, pk=None): class GenerateDataPetitionView(viewsets.ModelViewSet): - serializer_class = serializers.DataPetitionSerializer permission_classes = [permissions.IsAuthenticated] @@ -607,7 +616,6 @@ def create(self, request): class GeneratedPetitionViewSet(viewsets.GenericViewSet): - queryset = pm.GeneratedPetition.objects.all() permission_classes = [permissions.IsAuthenticated, permissions.IsAdminUser] @@ -659,9 +667,7 @@ def get(self, request): return Response(status=status.HTTP_401_UNAUTHORIZED) try: - validated_user, _ = JWTHttpOnlyCookieAuthentication().authenticate_token( - access_token - ) + validated_user, _ = JWTHttpOnlyCookieAuthentication().authenticate_token(access_token) except: validated_user = None if validated_user is None: @@ -685,9 +691,7 @@ def post(self, request, *args, **kwargs): response.set_cookie( settings.AUTH_COOKIE_KEY, # get cookie key from settings - serializer.validated_data[ - "access" - ], # pull access token out of validated_data + serializer.validated_data["access"], # pull access token out of validated_data max_age=settings.SIMPLE_JWT["ACCESS_TOKEN_LIFETIME"].total_seconds(), domain=getattr( settings, "AUTH_COOKIE_DOMAIN", None @@ -758,9 +762,7 @@ def post(self, request, *args, **kwargs): response.set_cookie( settings.AUTH_COOKIE_KEY, # get cookie key from settings - serializer.validated_data[ - "access" - ], # pull access token out of validated_data + serializer.validated_data["access"], # pull access token out of validated_data max_age=settings.SIMPLE_JWT["ACCESS_TOKEN_LIFETIME"].total_seconds(), domain=getattr( settings, "AUTH_COOKIE_DOMAIN", None diff --git a/dear_petition/petition/conftest.py b/dear_petition/petition/conftest.py index eaf5e8dd..71b76c80 100644 --- a/dear_petition/petition/conftest.py +++ b/dear_petition/petition/conftest.py @@ -157,16 +157,17 @@ def contact3(): zipcode="27703", ) + @pytest.fixture def client(): return ClientFactory( - name='Test Name', - address1='123 Test Ct', - address2='Apt A', - city='Durham', - state='NC', - zipcode='27701', - dob = timezone.now().date() # I wasn't born yesterday + name="Test Name", + address1="123 Test Ct", + address2="Apt A", + city="Durham", + state="NC", + zipcode="27701", + dob=timezone.now().date(), # I wasn't born yesterday ) diff --git a/dear_petition/petition/constants.py b/dear_petition/petition/constants.py index f85b2276..86047a33 100644 --- a/dear_petition/petition/constants.py +++ b/dear_petition/petition/constants.py @@ -23,18 +23,11 @@ FEMALE = "F" UNKNOWN = "U" -SEX_MAP = { - "Male": MALE, - "Female": FEMALE, - "Unknown": UNKNOWN, - "NOT AVAILABLE": NOT_AVAILABLE -} +SEX_MAP = {"Male": MALE, "Female": FEMALE, "Unknown": UNKNOWN, "NOT AVAILABLE": NOT_AVAILABLE} SEX_CHOICES = Choices(*[(v, k) for k, v in SEX_MAP.items()]) -CONTACT_CATEGORIES = Choices( - ("agency", "Agency"), ("attorney", "Attorney"), ("client", "Client") -) +CONTACT_CATEGORIES = Choices(("agency", "Agency"), ("attorney", "Attorney"), ("client", "Client")) DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S" DATE_FORMAT = "%m/%d/%Y" @@ -54,7 +47,9 @@ COMMENT_MAX_LENGTH = 8192 NEW_COMMENT_EMAIL_SUBJECT = "New comment available for batch #{batch}" -NEW_COMMENT_EMAIL_MESSAGE = "There is a new comment available for batch#{batch}.{user}\n\n\n{text}\n\nSee it here:{link}" +NEW_COMMENT_EMAIL_MESSAGE = ( + "There is a new comment available for batch#{batch}.{user}\n\n\n{text}\n\nSee it here:{link}" +) DATA_PETITION = "DATA-PETITION" diff --git a/dear_petition/petition/etl/email.py b/dear_petition/petition/etl/email.py index 5dee1991..8579c65b 100644 --- a/dear_petition/petition/etl/email.py +++ b/dear_petition/petition/etl/email.py @@ -10,11 +10,13 @@ logger = logging.getLogger(__name__) -EMAIL_SPACE_CHARACTER = '_' +EMAIL_SPACE_CHARACTER = "_" + def parse_label_from_address(label: str) -> str: """Convert special character into spaces""" - return label.replace(EMAIL_SPACE_CHARACTER, ' ') + return label.replace(EMAIL_SPACE_CHARACTER, " ") + def extract_username_and_label(addr: str) -> Tuple[str, str]: """ diff --git a/dear_petition/petition/etl/extract.py b/dear_petition/petition/etl/extract.py index 0d7fae64..46c18b7c 100644 --- a/dear_petition/petition/etl/extract.py +++ b/dear_petition/petition/etl/extract.py @@ -16,7 +16,9 @@ logger = logging.getLogger(__name__) -def transform_ciprs_document(saved_file_path, parser_mode, save_source=settings.CIPRS_READER_SOURCE): +def transform_ciprs_document( + saved_file_path, parser_mode, save_source=settings.CIPRS_READER_SOURCE +): """Run PDF extraction and return entity-extracted JSON data.""" reader = PDFToTextReader(saved_file_path, mode=parser_mode) try: diff --git a/dear_petition/petition/etl/load.py b/dear_petition/petition/etl/load.py index 7a0f4404..b7a914c9 100644 --- a/dear_petition/petition/etl/load.py +++ b/dear_petition/petition/etl/load.py @@ -39,9 +39,7 @@ def import_ciprs_records(files, user, parser_mode, batch_label=""): batch_file = batch.files.create(file=file_) for record_data in parse_ciprs_document(batch_file.file, parser_mode): - record = pm.CIPRSRecord( - batch=batch, batch_file=batch_file, data=record_data - ) + record = pm.CIPRSRecord(batch=batch, batch_file=batch_file, data=record_data) # Pass file numbers of CIPRS records that have already been saved in this batch of CIPRS records. # If this CIPRS record is in the list, it will not be saved again. record.refresh_record_from_data(saved_file_nos) @@ -81,17 +79,17 @@ def create_petitions_from_records(batch, form_type): jurisdiction=petition_type["jurisdiction"], county=petition_type["county"], ) - sheriff_agency = pm.Agency.get_sherriff_office_by_county( - petition_type["county"] - ) - + sheriff_agency = pm.Agency.get_sherriff_office_by_county(petition_type["county"]) + # petition arresting agencies - add agencies parsed from portal and assign sheriff's office for county if sheriff_agency is not None: logger.info( f"Detected {sheriff_agency.name} as {petition_type['county']} county's sherrif's office. Adding as default agency." ) petition.agencies.add(sheriff_agency) - offense_record_agencies = pm.Agency.objects.filter(pk__in=record_set.exclude(agency__isnull=True).values_list('agency')) + offense_record_agencies = pm.Agency.objects.filter( + pk__in=record_set.exclude(agency__isnull=True).values_list("agency") + ) petition.agencies.add(*offense_record_agencies) link_offense_records(petition) @@ -103,9 +101,7 @@ def create_petitions_from_records(batch, form_type): logger.info(f"Associated {petition.offense_records.count()} total records") if form_type in INACTIVE_BY_DEFAULT_FORM_TYPES: - pm.PetitionOffenseRecord.objects.filter(petition_id=petition.id).update( - active=False - ) + pm.PetitionOffenseRecord.objects.filter(petition_id=petition.id).update(active=False) def link_offense_records(petition): @@ -126,9 +122,7 @@ def create_documents(petition): ) base_document.offense_records.add(*paginator.petition_offense_records()) - logger.info( - f"Created {base_document} with {base_document.offense_records.count()} records" - ) + logger.info(f"Created {base_document} with {base_document.offense_records.count()} records") previous_document = base_document @@ -140,9 +134,7 @@ def create_documents(petition): ) attachment.offense_records.add(*attachment_records) previous_document = attachment - logger.info( - f"Created {attachment} with {attachment.offense_records.count()} records" - ) + logger.info(f"Created {attachment} with {attachment.offense_records.count()} records") create_addendum_documents(petition, previous_document) @@ -155,9 +147,7 @@ def assign_agencies_to_documents(petition): first_iteration = True i = 0 while True: - current_document_agencies = agencies[ - i : (i + 3) - ] # 3 boxes for agencies per document + current_document_agencies = agencies[i : (i + 3)] # 3 boxes for agencies per document if not current_document_agencies: break diff --git a/dear_petition/petition/etl/paginator.py b/dear_petition/petition/etl/paginator.py index 55c642cf..9bc98c68 100644 --- a/dear_petition/petition/etl/paginator.py +++ b/dear_petition/petition/etl/paginator.py @@ -48,9 +48,7 @@ def __init__( else PAGE_SIZES[ATTACHMENT] ) self.petition = petition - self.queryset = self.petition.get_all_offense_records( - filter_active=filter_active - ) + self.queryset = self.petition.get_all_offense_records(filter_active=filter_active) def query(self, start, size): """Slice query aginst petition offense records.""" diff --git a/dear_petition/petition/etl/refresh.py b/dear_petition/petition/etl/refresh.py index 8e7cc087..a091c8ed 100644 --- a/dear_petition/petition/etl/refresh.py +++ b/dear_petition/petition/etl/refresh.py @@ -21,7 +21,7 @@ def get_jurisdiction(record): return constants.NOT_AVAILABLE -def refresh_record_from_data(record, exclude_file_nos = []): +def refresh_record_from_data(record, exclude_file_nos=[]): """ Transform record.data (JSONField) into model data. Refresh the CIPRS record from its JSON data. Optionally pass in a list of CIPRS record file numbers. @@ -30,9 +30,7 @@ def refresh_record_from_data(record, exclude_file_nos = []): record.label = record.data.get("Defendant", {}).get("Name", "") record.file_no = record.data.get("General", {}).get("File No", "") record.county = record.data.get("General", {}).get("County", "") - record.dob = record.data.get("Defendant", {}).get( - "Date of Birth/Estimated Age", None - ) + record.dob = record.data.get("Defendant", {}).get("Date of Birth/Estimated Age", None) record.sex = record.data.get("Defendant", {}).get("Sex", constants.NOT_AVAILABLE) record.race = record.data.get("Defendant", {}).get("Race", "") record.case_status = record.data.get("Case Information", {}).get("Case Status", "") @@ -43,10 +41,14 @@ def refresh_record_from_data(record, exclude_file_nos = []): "Arrest Date", dt_obj_to_date(record.offense_date) ) record.jurisdiction = get_jurisdiction(record) - record.has_additional_offenses = "Additional offenses exist" in record.data.get("_meta", {}).get("source", {}) + record.has_additional_offenses = "Additional offenses exist" in record.data.get( + "_meta", {} + ).get("source", {}) if exclude_file_nos and record.file_no in exclude_file_nos: - logger.warning(f"Not saving ciprs record {record.file_no} (most likely because it's a duplicate).") + logger.warning( + f"Not saving ciprs record {record.file_no} (most likely because it's a duplicate)." + ) return logger.info(f"Saving ciprs record {record.file_no}") @@ -72,7 +74,9 @@ def refresh_offenses(record): agency = Agency.objects.none() agency_name = data_offense_record.get("Agency", "") if agency_name: - agency = Agency.agencies_with_clean_name.filter(clean_name__icontains=agency_name) + agency = Agency.agencies_with_clean_name.filter( + clean_name__icontains=agency_name + ) if agency.exists(): logger.info(f"Matched agency '{agency.first().name}' to offense") diff --git a/dear_petition/petition/etl/tests/conftest.py b/dear_petition/petition/etl/tests/conftest.py index 6eb03f4c..cea74da0 100644 --- a/dear_petition/petition/etl/tests/conftest.py +++ b/dear_petition/petition/etl/tests/conftest.py @@ -11,7 +11,5 @@ def mock_ciprs_reader(): @pytest.fixture def mock_transform_ciprs_document(): - with mock.patch( - "dear_petition.petition.etl.extract.transform_ciprs_document" - ) as mock_: + with mock.patch("dear_petition.petition.etl.extract.transform_ciprs_document") as mock_: yield mock_ diff --git a/dear_petition/petition/etl/tests/test_load.py b/dear_petition/petition/etl/tests/test_load.py index a8aea319..f873937a 100644 --- a/dear_petition/petition/etl/tests/test_load.py +++ b/dear_petition/petition/etl/tests/test_load.py @@ -63,9 +63,7 @@ def test_save_pdf(fake_pdf, user, mock_transform_ciprs_document, parser_mode): @pytest.mark.parametrize("parser_mode", [1, 2]) -def test_save_pdf__multiple( - fake_pdf, fake_pdf2, user, mock_transform_ciprs_document, parser_mode -): +def test_save_pdf__multiple(fake_pdf, fake_pdf2, user, mock_transform_ciprs_document, parser_mode): record = [{"Defendant": {"Name": "Jon Doe"}}] mock_transform_ciprs_document.return_value = record batch = import_ciprs_records([fake_pdf, fake_pdf2], user, parser_mode) @@ -73,9 +71,7 @@ def test_save_pdf__multiple( @pytest.mark.parametrize("parser_mode", [1, 2]) -def test_save_pdf__duplicate( - fake_pdf, fake_pdf2, user, mock_transform_ciprs_document, parser_mode -): +def test_save_pdf__duplicate(fake_pdf, fake_pdf2, user, mock_transform_ciprs_document, parser_mode): """ Test that duplicate CIPRS records, both within the same file and in separate files, are not saved. In this case, the same CIPRS record (as determined by the file no) is uploaded twice in the first pdf file and twice in the second @@ -83,7 +79,7 @@ def test_save_pdf__duplicate( """ record = [ {"Defendant": {"Name": "Dee Fendant"}, "General": {"File No": "00CR123456"}}, - {"Defendant": {"Name": "Dee Fendant"}, "General": {"File No": "00CR123456"}} + {"Defendant": {"Name": "Dee Fendant"}, "General": {"File No": "00CR123456"}}, ] mock_transform_ciprs_document.return_value = record batch = import_ciprs_records([fake_pdf, fake_pdf2], user, parser_mode) diff --git a/dear_petition/petition/etl/tests/test_petition_offenses.py b/dear_petition/petition/etl/tests/test_petition_offenses.py index 2e834ab2..5f383c0d 100644 --- a/dear_petition/petition/etl/tests/test_petition_offenses.py +++ b/dear_petition/petition/etl/tests/test_petition_offenses.py @@ -67,14 +67,9 @@ def test_paginator_default_page_size(petition, form_type, expected): assert paginator.initial_page_size == expected -@pytest.mark.parametrize( - "attachment_page_size,expected", [[10, 10], [0, 20], [-10, 20]] -) +@pytest.mark.parametrize("attachment_page_size,expected", [[10, 10], [0, 20], [-10, 20]]) def test_paginator_attachment_page_size(petition, attachment_page_size, expected): - - paginator = OffenseRecordPaginator( - petition, attachment_page_size=attachment_page_size - ) + paginator = OffenseRecordPaginator(petition, attachment_page_size=attachment_page_size) assert paginator.attachment_page_size == expected @@ -129,9 +124,7 @@ def test_link_offense_records__25(petition, records_35): create_documents(petition) # two attachments assert petition.documents.count() == 3 - attachments = petition.documents.filter(previous_document__isnull=False).order_by( - "id" - ) + attachments = petition.documents.filter(previous_document__isnull=False).order_by("id") # first attachment has 20 records assert attachments[0].offense_records.count() == 20 # 2nd attachment has 5 records @@ -154,11 +147,7 @@ def test_paginator_same_record_number_order(petition, records_10): ) link_offense_records(petition) create_documents(petition) - attachment = ( - petition.documents.filter(previous_document__isnull=False) - .order_by("pk") - .first() - ) + attachment = petition.documents.filter(previous_document__isnull=False).order_by("pk").first() # the 1st charge should always be on the first petition assert charge_1.pk in petition.offense_records.values_list("pk", flat=True) # the 2nd charge should always be on the attachment @@ -225,18 +214,10 @@ def create_new_ciprs_record(file_no): ) assert ( - list( - main_petition_form.get_ordered_offense_records().values_list( - "id", flat=True - ) - ) + list(main_petition_form.get_ordered_offense_records().values_list("id", flat=True)) == EXPECTED_ORDER_FIRST_FORM ) assert ( - list( - attachment_petition_form.get_ordered_offense_records().values_list( - "id", flat=True - ) - ) + list(attachment_petition_form.get_ordered_offense_records().values_list("id", flat=True)) == EXPECTED_ORDER_SECOND_FORM ) diff --git a/dear_petition/petition/etl/tests/test_refresh.py b/dear_petition/petition/etl/tests/test_refresh.py index 8e7dc4de..ddaf07a2 100644 --- a/dear_petition/petition/etl/tests/test_refresh.py +++ b/dear_petition/petition/etl/tests/test_refresh.py @@ -24,8 +24,7 @@ def test_defendant_dob(record1): record1.refresh_record_from_data() record1.refresh_from_db() assert ( - record1.dob.strftime("%Y-%m-%d") - == record1.data["Defendant"]["Date of Birth/Estimated Age"] + record1.dob.strftime("%Y-%m-%d") == record1.data["Defendant"]["Date of Birth/Estimated Age"] ) @@ -63,8 +62,7 @@ def test_case_information_arrest_date(record1): record1.refresh_record_from_data() record1.refresh_from_db() assert ( - record1.arrest_date.strftime("%Y-%m-%d") - == record1.data["Case Information"]["Arrest Date"] + record1.arrest_date.strftime("%Y-%m-%d") == record1.data["Case Information"]["Arrest Date"] ) diff --git a/dear_petition/petition/etl/tests/test_refresh_offense.py b/dear_petition/petition/etl/tests/test_refresh_offense.py index 134fd52c..682fa020 100644 --- a/dear_petition/petition/etl/tests/test_refresh_offense.py +++ b/dear_petition/petition/etl/tests/test_refresh_offense.py @@ -50,7 +50,7 @@ def data(): ], "Disposed On": "2001-03-01", "Disposition Method": "DISPOSED BY JUDGE", - "Verdict": "GUILTY" + "Verdict": "GUILTY", }, ], "Superior Court Offense Information": [], @@ -95,4 +95,3 @@ def test_offense_record(record): def test_offense_record__multi(record): offense = record.offenses.get(disposed_on="2001-03-01") assert offense.offense_records.count() == 2 - diff --git a/dear_petition/petition/etl/tests/test_transform.py b/dear_petition/petition/etl/tests/test_transform.py index 9e8abf51..2109268f 100644 --- a/dear_petition/petition/etl/tests/test_transform.py +++ b/dear_petition/petition/etl/tests/test_transform.py @@ -20,9 +20,7 @@ def test_recalculate_petitions(petition): batch = petition.batch - record = CIPRSRecordFactory( - batch=batch, jurisdiction=constants.DISTRICT_COURT, county="DURHAM" - ) + record = CIPRSRecordFactory(batch=batch, jurisdiction=constants.DISTRICT_COURT, county="DURHAM") offense = OffenseFactory( disposition_method="Dismissed by Court", ciprs_record=record, @@ -37,24 +35,15 @@ def test_recalculate_petitions(petition): link_offense_records(petition) create_documents(petition) - assert ( - petition.offense_records.filter(petitionoffenserecord__active=True).count() - == 12 - ) + assert petition.offense_records.filter(petitionoffenserecord__active=True).count() == 12 assert petition.has_attachments() recalculate_petitions(petition.id, offense_record_ids) - assert ( - petition.offense_records.filter(petitionoffenserecord__active=True).count() == 5 - ) + assert petition.offense_records.filter(petitionoffenserecord__active=True).count() == 5 assert not petition.has_attachments() - - def test_combine_batches(batch, batch_file, fake_pdf): - record = CIPRSRecordFactory( - batch=batch, jurisdiction=constants.DISTRICT_COURT, county="DURHAM" - ) + record = CIPRSRecordFactory(batch=batch, jurisdiction=constants.DISTRICT_COURT, county="DURHAM") record.refresh_record_from_data() second_batch = BatchFactory() @@ -97,17 +86,21 @@ def test_combine_batches(batch, batch_file, fake_pdf): ], "Disposed On": "2018-02-01", "Disposition Method": "DISPOSED BY JUDGE", - } + }, ], "Superior Court Offense Information": [], } second_batch_file = BatchFileFactory(batch=second_batch, file=fake_pdf) second_record = CIPRSRecordFactory( - batch=second_batch, data = second_record_data, batch_file=second_batch_file, jurisdiction=constants.DISTRICT_COURT, county="DURHAM" + batch=second_batch, + data=second_record_data, + batch_file=second_batch_file, + jurisdiction=constants.DISTRICT_COURT, + county="DURHAM", ) second_record.refresh_record_from_data() - + assert batch.records.count() == 1 assert pm.Offense.objects.filter(ciprs_record__batch__id=batch.id).count() == 1 assert pm.Offense.objects.filter(ciprs_record__batch__id=second_batch.id).count() == 2 @@ -119,8 +112,9 @@ def test_combine_batches(batch, batch_file, fake_pdf): assert new_batch.records.count() == 2 assert pm.Offense.objects.filter(ciprs_record__batch__id=new_batch.id).count() == 3 - assert pm.OffenseRecord.objects.filter(offense__ciprs_record__batch__id=new_batch.id).count() == 4 + assert ( + pm.OffenseRecord.objects.filter(offense__ciprs_record__batch__id=new_batch.id).count() == 4 + ) assert new_batch.files.count() == 2 assert new_batch.label == new_label assert new_batch.user_id == user_id - \ No newline at end of file diff --git a/dear_petition/petition/etl/transform.py b/dear_petition/petition/etl/transform.py index 2aa8e5ed..cbe01b22 100644 --- a/dear_petition/petition/etl/transform.py +++ b/dear_petition/petition/etl/transform.py @@ -13,9 +13,7 @@ def recalculate_petitions(petition_id, offense_record_ids): petition = pm.Petition.objects.get(id=petition_id) with transaction.atomic(): - pm.PetitionOffenseRecord.objects.filter(petition_id=petition.id).update( - active=False - ) + pm.PetitionOffenseRecord.objects.filter(petition_id=petition.id).update(active=False) pm.PetitionOffenseRecord.objects.filter( petition_id=petition.id, offense_record_id__in=offense_record_ids ).update(active=True) @@ -26,7 +24,6 @@ def recalculate_petitions(petition_id, offense_record_ids): def combine_batches(batch_ids: List[int], label: str, user_id: int): - client_resource = pr.ClientResource() record_resource = pr.RecordResource() offense_resource = pr.OffenseResource() @@ -40,14 +37,13 @@ def combine_batches(batch_ids: List[int], label: str, user_id: int): saved_batch_files = {} for batch in batches: for record in batch.records.iterator(): - if record.file_no in saved_file_nos: - continue # Duplicate record of one already imported + continue # Duplicate record of one already imported if record.batch_file: file = record.batch_file.file.file file_name = os.path.basename(file.name) - + if saved_batch_files.get(file_name): new_batch_file = saved_batch_files[file_name] else: @@ -55,12 +51,19 @@ def combine_batches(batch_ids: List[int], label: str, user_id: int): new_batch_file = new_batch.files.create(file=file) saved_batch_files[file_name] = new_batch_file else: - new_batch_file=None + new_batch_file = None - export_record_dataset = record_resource.export(queryset=pm.CIPRSRecord.objects.filter(id=record.id)) + export_record_dataset = record_resource.export( + queryset=pm.CIPRSRecord.objects.filter(id=record.id) + ) import_record_dataset = tablib.Dataset() - import_record_dataset.headers = [col.column_name for col in record_resource.get_import_fields()] - import_record_dataset.append([new_batch.id] + [value if value else None for value in export_record_dataset[0]]) + import_record_dataset.headers = [ + col.column_name for col in record_resource.get_import_fields() + ] + import_record_dataset.append( + [new_batch.id] + + [value if value else None for value in export_record_dataset[0]] + ) record_resource.import_data(import_record_dataset) record_id = record_resource.saved_instance_ids[-1] @@ -70,23 +73,36 @@ def combine_batches(batch_ids: List[int], label: str, user_id: int): new_record.save() for offense in record.offenses.all(): - export_offense_dataset = offense_resource.export(queryset=pm.Offense.objects.filter(id=offense.id)) + export_offense_dataset = offense_resource.export( + queryset=pm.Offense.objects.filter(id=offense.id) + ) import_offense_dataset = tablib.Dataset() - import_offense_dataset.headers = [col.column_name for col in offense_resource.get_import_fields()] - import_offense_dataset.append([record_id] + [value if value else None for value in export_offense_dataset[0]]) + import_offense_dataset.headers = [ + col.column_name for col in offense_resource.get_import_fields() + ] + import_offense_dataset.append( + [record_id] + + [value if value else None for value in export_offense_dataset[0]] + ) offense_resource.import_data(import_offense_dataset) offense_id = offense_resource.saved_instance_ids[-1] - export_offense_record_dataset = offense_record_resource.export(queryset=pm.OffenseRecord.objects.filter(offense_id=offense.id)) + export_offense_record_dataset = offense_record_resource.export( + queryset=pm.OffenseRecord.objects.filter(offense_id=offense.id) + ) import_offense_record_dataset = tablib.Dataset() - import_offense_record_dataset.headers = [col.column_name for col in offense_record_resource.get_import_fields()] + import_offense_record_dataset.headers = [ + col.column_name for col in offense_record_resource.get_import_fields() + ] for row in export_offense_record_dataset.dict: - import_offense_record_dataset.append([offense_id] + [value if value else None for value in row.values()]) + import_offense_record_dataset.append( + [offense_id] + [value if value else None for value in row.values()] + ) offense_record_resource.import_data(import_offense_record_dataset) saved_file_nos.append(record.file_no) - + create_batch_petitions(new_batch) return new_batch diff --git a/dear_petition/petition/export/documents/addendums/addendum_3b.py b/dear_petition/petition/export/documents/addendums/addendum_3b.py index 42b63a2f..492787bd 100644 --- a/dear_petition/petition/export/documents/addendums/addendum_3b.py +++ b/dear_petition/petition/export/documents/addendums/addendum_3b.py @@ -28,7 +28,6 @@ def generate_context(petition_document): def generate_3b_addendum(petition_document): - context = generate_context(petition_document) doc = DocxTemplate(settings.TEMPLATE_DIR.path(TEMPLATE)) doc.render(context) diff --git a/dear_petition/petition/export/documents/advice_letter.py b/dear_petition/petition/export/documents/advice_letter.py index 74b787be..888759dd 100644 --- a/dear_petition/petition/export/documents/advice_letter.py +++ b/dear_petition/petition/export/documents/advice_letter.py @@ -29,9 +29,7 @@ def get_county_string(counties: list): def generate_context(batch, attorney, client): context = {} - context["first_name"], context["last_name"] = utils.split_first_and_last_name( - client.name - ) + context["first_name"], context["last_name"] = utils.split_first_and_last_name(client.name) context["sex"] = batch.sex context["address"] = client.address1 context["address_second_line"] = client.address2 @@ -68,9 +66,7 @@ def generate_context(batch, attorney, client): dismissals = get_dismissed_records(batch) context["dismissed"] = list(dismissals) - dismissed_counties = list( - set(dismissal.county.capitalize() for dismissal in dismissals) - ) + dismissed_counties = list(set(dismissal.county.capitalize() for dismissal in dismissals)) context["dismissed_counties_string"] = get_county_string(dismissed_counties) context["phone_number"] = attorney.phone_number @@ -81,7 +77,9 @@ def generate_context(batch, attorney, client): def generate_advice_letter(batch): - assert batch.client is not None and batch.attorney is not None, 'Client and attorney must be set for batch before generating document' + assert ( + batch.client is not None and batch.attorney is not None + ), "Client and attorney must be set for batch before generating document" context = generate_context(batch, batch.attorney, batch.client) doc = DocxTemplate(settings.TEMPLATE_DIR.path(TEMPLATE)) diff --git a/dear_petition/petition/export/documents/records_summary.py b/dear_petition/petition/export/documents/records_summary.py index ebbb93d5..8d107dd3 100644 --- a/dear_petition/petition/export/documents/records_summary.py +++ b/dear_petition/petition/export/documents/records_summary.py @@ -9,7 +9,7 @@ from dear_petition.petition.constants import ( DISPOSITION_METHOD_CODE_MAP, VERDICT_CODE_MAP, - JURISDICTION_MAP + JURISDICTION_MAP, ) @@ -19,7 +19,9 @@ def generate_summary(batch): - assert batch.client is not None and batch.attorney is not None, 'Client and attorney must be set for batch before generating document' + assert ( + batch.client is not None and batch.attorney is not None + ), "Client and attorney must be set for batch before generating document" context = generate_context(batch, batch.attorney, batch.client) doc = DocxTemplate(settings.TEMPLATE_DIR.path(TEMPLATE)) @@ -71,7 +73,7 @@ def generate_context(batch, attorney, client): "jurisdiction": table_key[1], "idx": table_index, "offense_records": offense_records, - "addl_offense_file_nos": ', '.join(sorted(addl_offense_file_nos)) + "addl_offense_file_nos": ", ".join(sorted(addl_offense_file_nos)), } tables.append(table) @@ -89,9 +91,9 @@ def __get_offenses(batch): """ Get offenses for the batch. """ - offenses = pm.Offense.objects.filter( - ciprs_record__batch=batch - ).select_related("ciprs_record__batch") + offenses = pm.Offense.objects.filter(ciprs_record__batch=batch).select_related( + "ciprs_record__batch" + ) return offenses @@ -105,7 +107,6 @@ def __create_tables_data(offenses): table_data = {} for offense in offenses: - county = offense.ciprs_record.county jurisdiction = JURISDICTION_MAP[offense.jurisdiction] key = (county, jurisdiction) @@ -136,9 +137,9 @@ def __create_offense_record_data(offense_record): map. If that fails, use disposition (not the abbreviation). """ disposition = DISPOSITION_METHOD_CODE_MAP.get( - offense_record.disposition, - VERDICT_CODE_MAP.get(offense_record.disposition, offense_record.disposition) - ) + offense_record.disposition, + VERDICT_CODE_MAP.get(offense_record.disposition, offense_record.disposition), + ) offense_record_data = { "file_no": ciprs_record.file_no, @@ -148,7 +149,7 @@ def __create_offense_record_data(offense_record): "offense_date": __format_date(ciprs_record.offense_date), "disposition": disposition, "disposed_on": __format_date(offense.disposed_on), - "has_additional_offenses": ciprs_record.has_additional_offenses + "has_additional_offenses": ciprs_record.has_additional_offenses, } return offense_record_data diff --git a/dear_petition/petition/export/documents/tests/test_advice_letter.py b/dear_petition/petition/export/documents/tests/test_advice_letter.py index 4e7757b3..6626ee42 100644 --- a/dear_petition/petition/export/documents/tests/test_advice_letter.py +++ b/dear_petition/petition/export/documents/tests/test_advice_letter.py @@ -1,7 +1,12 @@ import pytest from dear_petition.petition.export.documents.advice_letter import generate_context -from dear_petition.petition.tests.factories import AttorneyFactory, BatchFactory, ClientFactory, CIPRSRecordFactory +from dear_petition.petition.tests.factories import ( + AttorneyFactory, + BatchFactory, + ClientFactory, + CIPRSRecordFactory, +) pytestmark = pytest.mark.django_db @@ -27,8 +32,8 @@ def test_advice_letter_context(): "city": "Faketown", "state": "NC", "zipcode": "11111", - "phone_number": '123-456-7890', - "email": 'attorney@example.com', + "phone_number": "123-456-7890", + "email": "attorney@example.com", } attorney = AttorneyFactory(**ATTORNEY_INFO) @@ -48,9 +53,9 @@ def test_advice_letter_context(): "underaged_conviction_counties_string": "", "dismissed": [], "dismissed_counties_string": "", - "phone_number": ATTORNEY_INFO['phone_number'], - "email": ATTORNEY_INFO['email'], - "attorney_name": ATTORNEY_INFO['name'], + "phone_number": ATTORNEY_INFO["phone_number"], + "email": ATTORNEY_INFO["email"], + "attorney_name": ATTORNEY_INFO["name"], } context = generate_context(batch, attorney, client) diff --git a/dear_petition/petition/export/documents/tests/test_records_summary.py b/dear_petition/petition/export/documents/tests/test_records_summary.py index e652db0a..eb433173 100644 --- a/dear_petition/petition/export/documents/tests/test_records_summary.py +++ b/dear_petition/petition/export/documents/tests/test_records_summary.py @@ -5,7 +5,11 @@ from dear_petition.petition.export.documents.records_summary import generate_context, __format_date from dear_petition.petition.tests.factories import ( - AttorneyFactory, CIPRSRecordFactory, ClientFactory, OffenseRecordFactory, OffenseFactory, + AttorneyFactory, + CIPRSRecordFactory, + ClientFactory, + OffenseRecordFactory, + OffenseFactory, ) from dear_petition.petition.constants import ( DISP_METHOD_SUPERSEDING_INDICTMENT, @@ -21,23 +25,30 @@ pytestmark = pytest.mark.django_db -PETITIONER_INFO = { - "name": "Pete Petitioner" -} +PETITIONER_INFO = {"name": "Pete Petitioner"} def test_records_summary_context__one_table_one_row(batch): """ Test generate_context method with one table and one row. Test all data """ - offense = create_offense(batch, "DURHAM", DISTRICT_COURT, "10CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "10CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") attorney = AttorneyFactory(name="A. Tourney") client = ClientFactory(**PETITIONER_INFO) context = generate_context(batch, attorney, client) - assert context["attorney"] == 'A. Tourney' + assert context["attorney"] == "A. Tourney" assert context["petitioner"] == PETITIONER_INFO["name"] assert context["dob"] == "12/31/1972" assert context["birthday_18th"] == "12/31/1990" @@ -65,20 +76,45 @@ def test_records_summary_context__many_tables(batch): """ Test generate_context method with many tables. Make sure correct number of tables and in correct order. """ - offense1 = create_offense(batch, "WAKE", SUPERIOR_COURT, - "11CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense1 = create_offense( + batch, "WAKE", SUPERIOR_COURT, "11CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False + ) create_offense_record(offense1, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense2 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "12CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense2 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "12CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense2, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense3 = create_offense(batch, "DURHAM", SUPERIOR_COURT, - "10CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense3 = create_offense( + batch, + "DURHAM", + SUPERIOR_COURT, + "10CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense3, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense4 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "12CR000002", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense4 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "12CR000002", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense4, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") attorney = AttorneyFactory(name="B. Tourney") @@ -112,20 +148,45 @@ def test_records_summary_context__many_offense_records(batch): Test generate_context method with many offense records in a table. Make sure correct number of offense records and in correct order. """ - offense1 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "12CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense1 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "12CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense1, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense2 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "10CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense2 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "10CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense2, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense3 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "11CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense3 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "11CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense3, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense4 = create_offense(batch, "WAKE", DISTRICT_COURT, - "13CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense4 = create_offense( + batch, "WAKE", DISTRICT_COURT, "13CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False + ) create_offense_record(offense4, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") attorney = AttorneyFactory(name="C. Tourney") @@ -149,7 +210,9 @@ def test_records_summary_context__many_offense_records(batch): assert offense_records[2]["idx"] == 3 -@pytest.mark.parametrize("disp_method", [DISP_METHOD_SUPERSEDING_INDICTMENT, DISP_METHOD_WAIVER_OF_PROBABLE_CAUSE]) +@pytest.mark.parametrize( + "disp_method", [DISP_METHOD_SUPERSEDING_INDICTMENT, DISP_METHOD_WAIVER_OF_PROBABLE_CAUSE] +) def test_records_summary_context__excluded_disp_method(batch, disp_method): """ Test generate_context method where one offense record belongs to an offense with an excluded disposition method. @@ -162,20 +225,16 @@ def test_records_summary_context__excluded_disp_method(batch, disp_method): dob="1972-12-31", batch=batch, offense_date="2001-09-30", - arrest_date="2001-10-01" + arrest_date="2001-10-01", ) offense_excluded = OffenseFactory( - ciprs_record=ciprs_record, - disposition_method=disp_method, - disposed_on="2003-10-02" + ciprs_record=ciprs_record, disposition_method=disp_method, disposed_on="2003-10-02" ) OffenseRecordFactory(offense=offense_excluded) offense_npc = OffenseFactory( - ciprs_record=ciprs_record, - disposition_method="NO PROBABLE CAUSE", - disposed_on="2004-11-03" + ciprs_record=ciprs_record, disposition_method="NO PROBABLE CAUSE", disposed_on="2004-11-03" ) OffenseRecordFactory(offense=offense_npc) @@ -199,8 +258,16 @@ def test_records_summary_context__duplicate(batch, contact1, client): Only one of the two offense records should be included. It doesn't matter which one since they are identical except for the offense records' action (eg CHARGED, CONVICTED) which isn't included in the result. """ - offense = create_offense(batch, "DURHAM", DISTRICT_COURT, - "10CR000001", "1972-12-31", VERDICT_GUILTY, "JURY TRIAL", False) + offense = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "10CR000001", + "1972-12-31", + VERDICT_GUILTY, + "JURY TRIAL", + False, + ) create_offense_record(offense, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") create_offense_record(offense, CONVICTED, "SIMPLE ASSAULT", "MISDEMEANOR") @@ -219,8 +286,16 @@ def test_records_summary_context__different_descriptions(batch, contact1, client part of same offense. The charged offense record's disposition should be guilty to lesser and the convicted offense record's disposition should be guilty. """ - offense1 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "10CR000001", "1972-12-31", VERDICT_GUILTY, "JURY TRIAL", False) + offense1 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "10CR000001", + "1972-12-31", + VERDICT_GUILTY, + "JURY TRIAL", + False, + ) create_offense_record(offense1, CHARGED, "PWIMSD SCH II CS", "MISDEMEANOR") create_offense_record(offense1, CONVICTED, "FELONY POSSESSION OF COCAINE", "MISDEMEANOR") @@ -246,8 +321,16 @@ def test_records_summary_context__different_severities(batch, contact1, client): part of same offense. The charged offense record's disposition should be guilty to lesser and the convicted offense record's disposition should be guilty. """ - offense1 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "10CR000001", "1972-12-31", VERDICT_GUILTY, "JURY TRIAL", False) + offense1 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "10CR000001", + "1972-12-31", + VERDICT_GUILTY, + "JURY TRIAL", + False, + ) create_offense_record(offense1, CHARGED, "FLEE/ELUDE ARREST W/MV", "FELONY") create_offense_record(offense1, CONVICTED, "FLEE/ELUDE ARREST W/MV", "MISDEMEANOR") @@ -272,16 +355,26 @@ def test_records_summary_context__disposition_codes(batch): Test generate_context method where the disposition code comes from the disposition map, the verdict map, and isn't found in either map. """ - offense1 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "01CR000001", "1972-12-31", "", "JURY TRIAL", False) + offense1 = create_offense( + batch, "DURHAM", DISTRICT_COURT, "01CR000001", "1972-12-31", "", "JURY TRIAL", False + ) create_offense_record(offense1, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense2 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "02CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense2 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "02CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense2, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense3 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "03CR000001", "1972-12-31", "", "not found", False) + offense3 = create_offense( + batch, "DURHAM", DISTRICT_COURT, "03CR000001", "1972-12-31", "", "not found", False + ) create_offense_record(offense3, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") attorney = AttorneyFactory(name="E. Tourney") @@ -298,22 +391,23 @@ def test_records_summary_context__disposition_codes(batch): assert offense_records[2]["disposition"] == "not found" -@pytest.mark.parametrize("dob, formatted_dob, formatted_18th_bday, formatted_22nd_bday", [ - (date(1972, 12, 31), "12/31/1972", "12/31/1990", "12/31/1994"), - # born in leap year - (date(1988, 2, 29), "02/29/1988", "03/01/2006", "03/01/2010"), -]) +@pytest.mark.parametrize( + "dob, formatted_dob, formatted_18th_bday, formatted_22nd_bday", + [ + (date(1972, 12, 31), "12/31/1972", "12/31/1990", "12/31/1994"), + # born in leap year + (date(1988, 2, 29), "02/29/1988", "03/01/2006", "03/01/2010"), + ], +) def test_records_summary_context__birthdays( - batch, - dob, - formatted_dob, - formatted_18th_bday, - formatted_22nd_bday + batch, dob, formatted_dob, formatted_18th_bday, formatted_22nd_bday ): """ Test generate_context method with different dates of birth """ - offense = create_offense(batch, "DURHAM", DISTRICT_COURT, "10CR000001", dob, "NOT GUILTY", "JURY TRIAL", False) + offense = create_offense( + batch, "DURHAM", DISTRICT_COURT, "10CR000001", dob, "NOT GUILTY", "JURY TRIAL", False + ) create_offense_record(offense, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") attorney = AttorneyFactory(name="E. Tourney") @@ -331,24 +425,64 @@ def test_records_summary_context__additional_offenses(batch): the correct file numbers in alphabetical order with no duplicates. Check that has_additional_offenses in each offense record is true if additional offenses exist and false otherwise. """ - offense1 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "12CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", True) + offense1 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "12CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + True, + ) create_offense_record(offense1, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense2 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "10CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", True) + offense2 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "10CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + True, + ) create_offense_record(offense2, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense3 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "10CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", True) + offense3 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "10CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + True, + ) create_offense_record(offense3, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense4 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "11CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", True) + offense4 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "11CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + True, + ) create_offense_record(offense4, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") - offense5 = create_offense(batch, "DURHAM", DISTRICT_COURT, - "13CR000001", "1972-12-31", "NOT GUILTY", "JURY TRIAL", False) + offense5 = create_offense( + batch, + "DURHAM", + DISTRICT_COURT, + "13CR000001", + "1972-12-31", + "NOT GUILTY", + "JURY TRIAL", + False, + ) create_offense_record(offense5, CHARGED, "SIMPLE ASSAULT", "MISDEMEANOR") attorney = AttorneyFactory(name="C. Tourney") @@ -371,12 +505,15 @@ def test_records_summary_context__additional_offenses(batch): assert not offense_records[4]["has_additional_offenses"] -@pytest.mark.parametrize("input_date, expected_output", [ - (datetime.datetime(2024, 1, 31, 11, 59, 59), "01/31/2024"), - (datetime.date(2024, 1, 31), "01/31/2024"), - (None, ""), - ("", ""), -]) +@pytest.mark.parametrize( + "input_date, expected_output", + [ + (datetime.datetime(2024, 1, 31, 11, 59, 59), "01/31/2024"), + (datetime.date(2024, 1, 31), "01/31/2024"), + (None, ""), + ("", ""), + ], +) def test_format_date(input_date, expected_output): assert __format_date(input_date) == expected_output @@ -387,15 +524,17 @@ def create_offense_record(offense, action, description, severity): """ offense_record = OffenseRecordFactory( offense=offense, - action = action, - description = description, - severity = severity, + action=action, + description=description, + severity=severity, ) return offense_record -def create_offense(batch, county, jurisdiction, file_no, dob, verdict, disposition_method, has_additional_offenses): +def create_offense( + batch, county, jurisdiction, file_no, dob, verdict, disposition_method, has_additional_offenses +): """ Create offense """ @@ -406,7 +545,7 @@ def create_offense(batch, county, jurisdiction, file_no, dob, verdict, dispositi dob=dob, offense_date="2001-09-30", arrest_date="2001-10-01", - has_additional_offenses=has_additional_offenses + has_additional_offenses=has_additional_offenses, ) offense = OffenseFactory( ciprs_record=ciprs_record, diff --git a/dear_petition/petition/export/forms.py b/dear_petition/petition/export/forms.py index 149ec7a5..53d3aaf2 100644 --- a/dear_petition/petition/export/forms.py +++ b/dear_petition/petition/export/forms.py @@ -147,12 +147,7 @@ def map_additional_forms(self): self.data["ChargedB"] = Checkbox("Yes") self.data["ChargedDesc"] = charged_desc_string self.data["ChargedDescCont"] = charged_desc_cont_string - elif ( - self.petition.offense_records.filter( - petitionoffenserecord__active=True - ).count() - > 1 - ): + elif self.petition.offense_records.filter(petitionoffenserecord__active=True).count() > 1: # Petition section says to check one of the checkboxes if petitioning to expunge MULTIPLE dismissals self.data["ChargedA"] = Checkbox("Yes") else: @@ -188,13 +183,9 @@ def map_petitioner(self): def map_agencies(self): agencies = self.petition_document.agencies.all() - assert ( - len(agencies) <= 3 - ), f"This form was given {len(agencies)} Three is the maximum." + assert len(agencies) <= 3, f"This form was given {len(agencies)} Three is the maximum." if len(agencies) > 0: - self.data["FormNo1"] = self.petition_document.petition.form_type.split("-")[ - -1 - ] + self.data["FormNo1"] = self.petition_document.petition.form_type.split("-")[-1] for i, agency in enumerate(agencies, 1): body = get_285_form_agency_address(agency) self.data[f"NameAddress{i}"] = body @@ -266,9 +257,7 @@ def map_offenses(self): self.data[f"FileNumber:{i}"] = ciprs_record.file_no self.data[f"ArrestDate:{i}"] = self.format_date(ciprs_record.arrest_date) self.data[f"OffenseDescription:{i}"] = offense_record.description - self.data[f"DateOfOffense:{i}"] = self.format_date( - ciprs_record.offense_date - ) + self.data[f"DateOfOffense:{i}"] = self.format_date(ciprs_record.offense_date) self.data[f"Disposition:{i}"] = self.disposition_code(offense) self.data[f"DispositionDate:{i}"] = self.format_date(offense.disposed_on) @@ -288,16 +277,9 @@ def map_petitioner(self): self.data["DOB"] = self.format_date(record.dob) def map_additional_forms(self): - if ( - self.petition.offense_records.filter( - petitionoffenserecord__active=True - ).count() - > 1 - ): + if self.petition.offense_records.filter(petitionoffenserecord__active=True).count() > 1: # Petition section says to check one of the checkboxes if petitioning to expunge MULTIPLE dismissals - self.data["TwoOrThreeNonviolentFeloniesWaitingPeriodCkBox"] = Checkbox( - "Yes" - ) + self.data["TwoOrThreeNonviolentFeloniesWaitingPeriodCkBox"] = Checkbox("Yes") else: self.data["OneNonviolentFelonyWaitingPeriodCkBox"] = Checkbox("Yes") @@ -314,9 +296,7 @@ def map_attorney(self): # self.data["PetitionerPetitionersAttorneySignedName"] = attorney.name self.data["PetitionersAttorneyCkBox"] = Checkbox("Yes") - self.data["PetitionerPetitionersAttorneySignedDate"] = self.format_date( - dt.datetime.today() - ) + self.data["PetitionerPetitionersAttorneySignedDate"] = self.format_date(dt.datetime.today()) class AOCFormCR298(AOCFormCR297): diff --git a/dear_petition/petition/export/main.py b/dear_petition/petition/export/main.py index 1a55ba99..d62b320f 100644 --- a/dear_petition/petition/export/main.py +++ b/dear_petition/petition/export/main.py @@ -73,13 +73,10 @@ def generate_petition_pdf(petition_documents, extra): add_additional_params_to_forms(petition_documents, extra) for petition_document in petition_documents: - doc_stream = io.BytesIO() context = build_pdf_template_context(petition_document, extra) add_pdf_template_annotations(context) - write_template_and_annotations_to_stream( - doc_stream, context, petition_document.form_type - ) + write_template_and_annotations_to_stream(doc_stream, context, petition_document.form_type) doc_streams.append(doc_stream) concatenate_pdf_streams(doc_streams, pdf_stream) @@ -89,17 +86,13 @@ def generate_petition_pdf(petition_documents, extra): ADDENDUM_DOCUMENT_GENERATION_MAP = { - constants.ADDENDUM_FORM_TYPES[ - constants.ADDENDUM_3B - ]: addendums.generate_3b_addendum, + constants.ADDENDUM_FORM_TYPES[constants.ADDENDUM_3B]: addendums.generate_3b_addendum, } def generate_addendum_document_file(petition_document): assert petition_document.form_type in constants.ADDENDUM_FORM_TYPES - addendum_document_file_generator = ADDENDUM_DOCUMENT_GENERATION_MAP[ - petition_document.form_type - ] + addendum_document_file_generator = ADDENDUM_DOCUMENT_GENERATION_MAP[petition_document.form_type] doc = addendum_document_file_generator(petition_document) file_stream = io.BytesIO() diff --git a/dear_petition/petition/export/tests/test_cr285.py b/dear_petition/petition/export/tests/test_cr285.py index b6d4e050..fd8c2769 100644 --- a/dear_petition/petition/export/tests/test_cr285.py +++ b/dear_petition/petition/export/tests/test_cr285.py @@ -94,9 +94,7 @@ def test_map_offenses__fileno(form, record2, offense_record1): def test_map_offenses__arrest_date(form, record2, offense_record1): form.map_offenses() - assert form.data["ArrestDateRow1"] == utils.format_petition_date( - record2.arrest_date - ) + assert form.data["ArrestDateRow1"] == utils.format_petition_date(record2.arrest_date) def test_map_offenses__description(form, record2, offense_record1): @@ -106,9 +104,7 @@ def test_map_offenses__description(form, record2, offense_record1): def test_map_offenses__offense_date(form, record2, offense_record1): form.map_offenses() - assert form.data["DateOfOffenseRow1"] == utils.format_petition_date( - record2.offense_date - ) + assert form.data["DateOfOffenseRow1"] == utils.format_petition_date(record2.offense_date) @pytest.mark.parametrize( @@ -139,6 +135,4 @@ def test_map_offenses__disposition_method( def test_map_offenses__disposition_date(form, offense1, offense_record1): form.map_offenses() - assert form.data["DispositionDateRow1"] == utils.format_petition_date( - offense1.disposed_on - ) + assert form.data["DispositionDateRow1"] == utils.format_petition_date(offense1.disposed_on) diff --git a/dear_petition/petition/export/tests/test_cr287.py b/dear_petition/petition/export/tests/test_cr287.py index 39780fda..19d383cd 100644 --- a/dear_petition/petition/export/tests/test_cr287.py +++ b/dear_petition/petition/export/tests/test_cr287.py @@ -169,9 +169,7 @@ def test_map_attorney__petition_attorney_cbx(form, contact1): def test_map_attorney__petition_not_filed_sign_date(form, contact1): form.extra["attorney"] = contact1 form.map_attorney() - assert form.data["PetitionNotFiledSignDate"] == utils.format_petition_date( - dt.datetime.today() - ) + assert form.data["PetitionNotFiledSignDate"] == utils.format_petition_date(dt.datetime.today()) # @@ -266,9 +264,7 @@ def test_map_offenses__offense_date(form, record2, offense_record1): def test_map_offenses__disposition_date(form, offense1, offense_record1): form.map_offenses() - assert form.data["DismissalDate:1"] == utils.format_petition_date( - offense1.disposed_on - ) + assert form.data["DismissalDate:1"] == utils.format_petition_date(offense1.disposed_on) # @@ -299,9 +295,7 @@ def test_checkmark_3b_checkmark_a_checked( def test_checkmark_3b_checkmark_b_checked(form): form.petition_document.form_specific_data["is_checkmark_3b_checked"] = True form.petition_document.form_specific_data["charged_desc_string"] = "Test string" - form.petition_document.form_specific_data[ - "charged_desc_cont_string" - ] = "Test string (cont.)" + form.petition_document.form_specific_data["charged_desc_cont_string"] = "Test string (cont.)" form.map_additional_forms() assert not form.data.get("ChargedA") assert form.data.get("ChargedB") diff --git a/dear_petition/petition/export/writer.py b/dear_petition/petition/export/writer.py index 6d960902..1fe101bb 100644 --- a/dear_petition/petition/export/writer.py +++ b/dear_petition/petition/export/writer.py @@ -8,13 +8,12 @@ def write_template_and_annotations_to_stream(bytes_stream, data, form_type): - template_path = os.path.join( - settings.APPS_DIR, "static", "templates", f"{form_type}.pdf" - ) + template_path = os.path.join(settings.APPS_DIR, "static", "templates", f"{form_type}.pdf") petition = Writer(data, template_path, bytes_stream) petition.set_annotations() petition.write() + def merge_acroforms(acroforms, output_form_fields): if not acroforms: return None @@ -25,9 +24,10 @@ def merge_acroforms(acroforms, output_form_fields): if key not in output_acroform: output_acroform[key] = source_acroform[key] - output_acroform[PdfName('Fields')] = output_form_fields + output_acroform[PdfName("Fields")] = output_form_fields return output_acroform + def concatenate_pdf_streams(paths, output): writer = PdfWriter() acroforms = [] @@ -40,32 +40,33 @@ def concatenate_pdf_streams(paths, output): reader = PdfReader(fdata=data_bytes) writer.addpages(reader.pages) - if PdfName('AcroForm') not in reader[PdfName('Root')].keys(): + if PdfName("AcroForm") not in reader[PdfName("Root")].keys(): continue # Extract PDF Acroform data and avoid form_field collisions # Note: This is needed to keep acroform data after merging # https://stackoverflow.com/a/57687160 - acroform = reader[PdfName('Root')][PdfName('AcroForm')] - form_fields = acroform[PdfName('Fields')] if PdfName('Fields') in acroform else [] + acroform = reader[PdfName("Root")][PdfName("AcroForm")] + form_fields = acroform[PdfName("Fields")] if PdfName("Fields") in acroform else [] for field_num, form_field in enumerate(form_fields): - key = PdfName('T') - old_name = form_field[key].replace('(','').replace(')','') # Field names are in the "(name)" format - form_field[key] = f'FILE_{file_num}_FIELD_{field_num}_{old_name}' + key = PdfName("T") + old_name = ( + form_field[key].replace("(", "").replace(")", "") + ) # Field names are in the "(name)" format + form_field[key] = f"FILE_{file_num}_FIELD_{field_num}_{old_name}" acroforms.append(acroform) output_form_fields.extend(form_fields) output_acroform = merge_acroforms(acroforms, output_form_fields) if output_acroform is not None: - writer.trailer[PdfName('Root')][PdfName('AcroForm')] = output_acroform + writer.trailer[PdfName("Root")][PdfName("AcroForm")] = output_acroform writer.write(output) output.seek(0) class Writer: - ANNOT_KEY = "/Annots" ANNOT_FIELD_KEY = "/T" ANNOT_VAL_KEY = "/V" @@ -80,9 +81,7 @@ def read_template(template_path): self.data = data self.output_path = output_path self.template = read_template(template_path) - self.template.Root.AcroForm.update( - PdfDict(NeedAppearances=PdfObject("true")) - ) + self.template.Root.AcroForm.update(PdfDict(NeedAppearances=PdfObject("true"))) self.annotations = [] def set_annotations(self): diff --git a/dear_petition/petition/management/commands/bootstrap-review-app.py b/dear_petition/petition/management/commands/bootstrap-review-app.py index 7b794bf1..61ac1e6d 100644 --- a/dear_petition/petition/management/commands/bootstrap-review-app.py +++ b/dear_petition/petition/management/commands/bootstrap-review-app.py @@ -14,5 +14,7 @@ def handle(self, *args, **options): if os.getenv("IS_REVIEW", "False") != "True" or qatester_exists: self.stdout.write("**Not running bootstrap tasks**") return - User.objects.create_superuser(username="qatester", email="qatester@example.com", password=settings.QATESTER_PASSWORD) + User.objects.create_superuser( + username="qatester", email="qatester@example.com", password=settings.QATESTER_PASSWORD + ) self.stdout.write(self.style.SUCCESS("Successfully created qatester")) diff --git a/dear_petition/petition/management/commands/convert_agency_table.py b/dear_petition/petition/management/commands/convert_agency_table.py index 9adc2740..357cf67b 100644 --- a/dear_petition/petition/management/commands/convert_agency_table.py +++ b/dear_petition/petition/management/commands/convert_agency_table.py @@ -5,15 +5,18 @@ from dear_petition.petition import models + def convert_contacts_to_agency_objects(current_cls, target_cls): # Migrate from Contact model to Agency model - agency_contacts = current_cls.objects.filter(category='agency') + agency_contacts = current_cls.objects.filter(category="agency") print() for agency_contact in agency_contacts.values(): with transaction.atomic(): - id = agency_contact.pop('id') + id = agency_contact.pop("id") agency = target_cls(**agency_contact) - if re.search(models.AGENCY_SHERRIFF_OFFICE_PATTERN, agency.name, re.IGNORECASE) or re.search(models.AGENCY_SHERRIFF_DEPARTMENT_PATTERN, agency.name, re.IGNORECASE): + if re.search( + models.AGENCY_SHERRIFF_OFFICE_PATTERN, agency.name, re.IGNORECASE + ) or re.search(models.AGENCY_SHERRIFF_DEPARTMENT_PATTERN, agency.name, re.IGNORECASE): agency.is_sheriff = True else: agency.is_sheriff = False @@ -23,6 +26,7 @@ def convert_contacts_to_agency_objects(current_cls, target_cls): print(f"Migrated Contact '{agency.name}' to Agency table") print() + """ # attempt to provide backwards migration for agencies, but it doesn't seem worth the effort def convert_agencies_to_contact_objects(current_cls, target_cls): @@ -45,8 +49,16 @@ def convert_agencies_to_contact_objects(current_cls, target_cls): class Command(BaseCommand): def add_arguments(self, parser): - parser.add_argument("--convert_contacts", action="store_true", help="Convert existing agencies in Contact table to Agency table") - parser.add_argument("--convert_agencies", action="store_true", help="Convert existing agencies in Agency table to Contact table") + parser.add_argument( + "--convert_contacts", + action="store_true", + help="Convert existing agencies in Contact table to Agency table", + ) + parser.add_argument( + "--convert_agencies", + action="store_true", + help="Convert existing agencies in Agency table to Contact table", + ) def handle(self, *args, **options): if options["convert_contacts"]: @@ -56,4 +68,6 @@ def handle(self, *args, **options): print("This operation is currently not supported") pass else: - raise CommandError('Did not provide one of `convert_contacts` or `convert_agencies` arguments') \ No newline at end of file + raise CommandError( + "Did not provide one of `convert_contacts` or `convert_agencies` arguments" + ) diff --git a/dear_petition/petition/migrations/0001_initial.py b/dear_petition/petition/migrations/0001_initial.py index f55d2392..b3d6668f 100644 --- a/dear_petition/petition/migrations/0001_initial.py +++ b/dear_petition/petition/migrations/0001_initial.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [] diff --git a/dear_petition/petition/migrations/0002_auto_20190518_1909.py b/dear_petition/petition/migrations/0002_auto_20190518_1909.py index c9f80bdd..81a20031 100644 --- a/dear_petition/petition/migrations/0002_auto_20190518_1909.py +++ b/dear_petition/petition/migrations/0002_auto_20190518_1909.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [("petition", "0001_initial")] operations = [ diff --git a/dear_petition/petition/migrations/0003_auto_20190518_1915.py b/dear_petition/petition/migrations/0003_auto_20190518_1915.py index 3a8f9577..677fc120 100644 --- a/dear_petition/petition/migrations/0003_auto_20190518_1915.py +++ b/dear_petition/petition/migrations/0003_auto_20190518_1915.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [("petition", "0002_auto_20190518_1909")] operations = [ diff --git a/dear_petition/petition/migrations/0004_auto_20190518_2129.py b/dear_petition/petition/migrations/0004_auto_20190518_2129.py index ec398e77..ca51eae5 100644 --- a/dear_petition/petition/migrations/0004_auto_20190518_2129.py +++ b/dear_petition/petition/migrations/0004_auto_20190518_2129.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [("petition", "0003_auto_20190518_1915")] operations = [ diff --git a/dear_petition/petition/migrations/0005_contact.py b/dear_petition/petition/migrations/0005_contact.py index 97a4dac8..ca65c93f 100644 --- a/dear_petition/petition/migrations/0005_contact.py +++ b/dear_petition/petition/migrations/0005_contact.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [("petition", "0004_auto_20190518_2129")] operations = [ diff --git a/dear_petition/petition/migrations/0006_auto_20191015_2329.py b/dear_petition/petition/migrations/0006_auto_20191015_2329.py index f150db0f..13fce948 100644 --- a/dear_petition/petition/migrations/0006_auto_20191015_2329.py +++ b/dear_petition/petition/migrations/0006_auto_20191015_2329.py @@ -4,37 +4,45 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0005_contact'), + ("petition", "0005_contact"), ] operations = [ migrations.AlterField( - model_name='contact', - name='address1', - field=models.CharField(blank=True, max_length=512, verbose_name='Address (Line 1)'), + model_name="contact", + name="address1", + field=models.CharField(blank=True, max_length=512, verbose_name="Address (Line 1)"), ), migrations.AlterField( - model_name='contact', - name='address2', - field=models.CharField(blank=True, max_length=512, verbose_name='Address (Line 2)'), + model_name="contact", + name="address2", + field=models.CharField(blank=True, max_length=512, verbose_name="Address (Line 2)"), ), migrations.AlterField( - model_name='contact', - name='category', - field=models.CharField(choices=[('agency', 'Agency'), ('attorney', 'Attorney')], default='agency', max_length=16), + model_name="contact", + name="category", + field=models.CharField( + choices=[("agency", "Agency"), ("attorney", "Attorney")], + default="agency", + max_length=16, + ), ), migrations.AlterField( - model_name='contact', - name='zipcode', - field=models.CharField(blank=True, max_length=16, verbose_name='ZIP Code'), + model_name="contact", + name="zipcode", + field=models.CharField(blank=True, max_length=16, verbose_name="ZIP Code"), ), migrations.CreateModel( - name='Batch', + name="Batch", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('records', models.ManyToManyField(to='petition.CIPRSRecord')), + ( + "id", + models.AutoField( + auto_created=True, primary_key=True, serialize=False, verbose_name="ID" + ), + ), + ("records", models.ManyToManyField(to="petition.CIPRSRecord")), ], ), ] diff --git a/dear_petition/petition/migrations/0007_auto_20200208_0221.py b/dear_petition/petition/migrations/0007_auto_20200208_0221.py index 3df47da6..6cbd485a 100644 --- a/dear_petition/petition/migrations/0007_auto_20200208_0221.py +++ b/dear_petition/petition/migrations/0007_auto_20200208_0221.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0006_auto_20191015_2329"), ] @@ -23,8 +22,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="batch", name="records", - field=models.ManyToManyField( - related_name="batches", to="petition.CIPRSRecord" - ), + field=models.ManyToManyField(related_name="batches", to="petition.CIPRSRecord"), ), ] diff --git a/dear_petition/petition/migrations/0008_auto_20200208_0222.py b/dear_petition/petition/migrations/0008_auto_20200208_0222.py index a2cef558..e288264e 100644 --- a/dear_petition/petition/migrations/0008_auto_20200208_0222.py +++ b/dear_petition/petition/migrations/0008_auto_20200208_0222.py @@ -17,7 +17,6 @@ def move_batch_fks(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("petition", "0007_auto_20200208_0221"), ] diff --git a/dear_petition/petition/migrations/0009_auto_20200208_0237.py b/dear_petition/petition/migrations/0009_auto_20200208_0237.py index 0ca352ef..c6043354 100644 --- a/dear_petition/petition/migrations/0009_auto_20200208_0237.py +++ b/dear_petition/petition/migrations/0009_auto_20200208_0237.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0008_auto_20200208_0222"), ] diff --git a/dear_petition/petition/migrations/0010_auto_20200208_0238.py b/dear_petition/petition/migrations/0010_auto_20200208_0238.py index 85886f4b..16558141 100644 --- a/dear_petition/petition/migrations/0010_auto_20200208_0238.py +++ b/dear_petition/petition/migrations/0010_auto_20200208_0238.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0009_auto_20200208_0237"), ] diff --git a/dear_petition/petition/migrations/0011_batch_label.py b/dear_petition/petition/migrations/0011_batch_label.py index 07ee4310..34013256 100644 --- a/dear_petition/petition/migrations/0011_batch_label.py +++ b/dear_petition/petition/migrations/0011_batch_label.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0010_auto_20200208_0238"), ] diff --git a/dear_petition/petition/migrations/0012_auto_20200208_0240.py b/dear_petition/petition/migrations/0012_auto_20200208_0240.py index 6e09f053..838a23b2 100644 --- a/dear_petition/petition/migrations/0012_auto_20200208_0240.py +++ b/dear_petition/petition/migrations/0012_auto_20200208_0240.py @@ -14,7 +14,6 @@ def add_labels(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("petition", "0011_batch_label"), ] diff --git a/dear_petition/petition/migrations/0013_batch_date_uploaded.py b/dear_petition/petition/migrations/0013_batch_date_uploaded.py index cde59d88..6316e159 100644 --- a/dear_petition/petition/migrations/0013_batch_date_uploaded.py +++ b/dear_petition/petition/migrations/0013_batch_date_uploaded.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0012_auto_20200208_0240"), ] @@ -14,9 +13,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="batch", name="date_uploaded", - field=models.DateTimeField( - auto_now_add=True, default=django.utils.timezone.now - ), + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), preserve_default=False, ), ] diff --git a/dear_petition/petition/migrations/0014_auto_20200209_0207.py b/dear_petition/petition/migrations/0014_auto_20200209_0207.py index 123e8d59..74007b65 100644 --- a/dear_petition/petition/migrations/0014_auto_20200209_0207.py +++ b/dear_petition/petition/migrations/0014_auto_20200209_0207.py @@ -14,7 +14,6 @@ def add_dates(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("petition", "0013_batch_date_uploaded"), ] diff --git a/dear_petition/petition/migrations/0015_auto_20200209_0226.py b/dear_petition/petition/migrations/0015_auto_20200209_0226.py index 08f182f7..9dc2db3d 100644 --- a/dear_petition/petition/migrations/0015_auto_20200209_0226.py +++ b/dear_petition/petition/migrations/0015_auto_20200209_0226.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("petition", "0014_auto_20200209_0207"), diff --git a/dear_petition/petition/migrations/0016_auto_20200209_0226.py b/dear_petition/petition/migrations/0016_auto_20200209_0226.py index 6b8ba500..a20bec7b 100644 --- a/dear_petition/petition/migrations/0016_auto_20200209_0226.py +++ b/dear_petition/petition/migrations/0016_auto_20200209_0226.py @@ -14,7 +14,6 @@ def add_user(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("petition", "0015_auto_20200209_0226"), ] diff --git a/dear_petition/petition/migrations/0017_auto_20200209_0229.py b/dear_petition/petition/migrations/0017_auto_20200209_0229.py index c509205f..2cbf8029 100644 --- a/dear_petition/petition/migrations/0017_auto_20200209_0229.py +++ b/dear_petition/petition/migrations/0017_auto_20200209_0229.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0016_auto_20200209_0226"), ] diff --git a/dear_petition/petition/migrations/0018_auto_20200407_1720.py b/dear_petition/petition/migrations/0018_auto_20200407_1720.py index 1abc20bf..ab4d51ad 100644 --- a/dear_petition/petition/migrations/0018_auto_20200407_1720.py +++ b/dear_petition/petition/migrations/0018_auto_20200407_1720.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0017_auto_20200209_0229"), ] diff --git a/dear_petition/petition/migrations/0019_auto_20200407_1720.py b/dear_petition/petition/migrations/0019_auto_20200407_1720.py index 746b4146..7ae8db59 100644 --- a/dear_petition/petition/migrations/0019_auto_20200407_1720.py +++ b/dear_petition/petition/migrations/0019_auto_20200407_1720.py @@ -27,9 +27,7 @@ def refresh_record_from_data(record): """ record.file_no = record.data.get("General", {}).get("File No", "") record.county = record.data.get("General", {}).get("County", "") - record.dob = record.data.get("Defendant", {}).get( - "Date of Birth/Estimated Age", None - ) + record.dob = record.data.get("Defendant", {}).get("Date of Birth/Estimated Age", None) record.sex = record.data.get("Defendant", {}).get("Sex", "") record.race = record.data.get("Defendant", {}).get("Race", "") record.case_status = record.data.get("Case Information", {}).get("Case Status", "") @@ -55,11 +53,8 @@ def get_jurisdiction(record): class Migration(migrations.Migration): - dependencies = [ ("petition", "0018_auto_20200407_1720"), ] - operations = [ - migrations.RunPython(update_existing_ciprs_records, migrations.RunPython.noop) - ] + operations = [migrations.RunPython(update_existing_ciprs_records, migrations.RunPython.noop)] diff --git a/dear_petition/petition/migrations/0020_offense_offenserecord.py b/dear_petition/petition/migrations/0020_offense_offenserecord.py index 643cd82e..b8048772 100644 --- a/dear_petition/petition/migrations/0020_offense_offenserecord.py +++ b/dear_petition/petition/migrations/0020_offense_offenserecord.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0019_auto_20200407_1720"), ] diff --git a/dear_petition/petition/migrations/0021_comment.py b/dear_petition/petition/migrations/0021_comment.py index 5503ed41..995899b1 100644 --- a/dear_petition/petition/migrations/0021_comment.py +++ b/dear_petition/petition/migrations/0021_comment.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("petition", "0020_offense_offenserecord"), diff --git a/dear_petition/petition/migrations/0022_remove_comment_parent.py b/dear_petition/petition/migrations/0022_remove_comment_parent.py index cd20f939..0b1ba49f 100644 --- a/dear_petition/petition/migrations/0022_remove_comment_parent.py +++ b/dear_petition/petition/migrations/0022_remove_comment_parent.py @@ -4,11 +4,13 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0021_comment"), ] operations = [ - migrations.RemoveField(model_name="comment", name="parent",), + migrations.RemoveField( + model_name="comment", + name="parent", + ), ] diff --git a/dear_petition/petition/migrations/0023_comment_time.py b/dear_petition/petition/migrations/0023_comment_time.py index 5f17949a..9de0a971 100644 --- a/dear_petition/petition/migrations/0023_comment_time.py +++ b/dear_petition/petition/migrations/0023_comment_time.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0022_remove_comment_parent"), ] @@ -14,9 +13,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="comment", name="time", - field=models.DateTimeField( - auto_now_add=True, default=django.utils.timezone.now - ), + field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now), preserve_default=False, ), ] diff --git a/dear_petition/petition/migrations/0024_auto_20200507_1941.py b/dear_petition/petition/migrations/0024_auto_20200507_1941.py index fe7bea03..b642a08a 100644 --- a/dear_petition/petition/migrations/0024_auto_20200507_1941.py +++ b/dear_petition/petition/migrations/0024_auto_20200507_1941.py @@ -5,14 +5,15 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0023_comment_time"), ] operations = [ migrations.AlterField( - model_name="comment", name="text", field=models.TextField(), + model_name="comment", + name="text", + field=models.TextField(), ), migrations.CreateModel( name="Petition", diff --git a/dear_petition/petition/migrations/0025_auto_20200520_0120.py b/dear_petition/petition/migrations/0025_auto_20200520_0120.py index 3677c3ce..972cb210 100644 --- a/dear_petition/petition/migrations/0025_auto_20200520_0120.py +++ b/dear_petition/petition/migrations/0025_auto_20200520_0120.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0024_auto_20200507_1941"), ] diff --git a/dear_petition/petition/migrations/0025_auto_20200521_1343.py b/dear_petition/petition/migrations/0025_auto_20200521_1343.py index c24ab5c1..d0567f2a 100644 --- a/dear_petition/petition/migrations/0025_auto_20200521_1343.py +++ b/dear_petition/petition/migrations/0025_auto_20200521_1343.py @@ -5,15 +5,18 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0024_auto_20200507_1941'), + ("petition", "0024_auto_20200507_1941"), ] operations = [ migrations.AlterField( - model_name='petition', - name='batch', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='petitions', to='petition.Batch'), + model_name="petition", + name="batch", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="petitions", + to="petition.Batch", + ), ), ] diff --git a/dear_petition/petition/migrations/0026_auto_20200521_1624.py b/dear_petition/petition/migrations/0026_auto_20200521_1624.py index 29e0b40f..e98f9216 100644 --- a/dear_petition/petition/migrations/0026_auto_20200521_1624.py +++ b/dear_petition/petition/migrations/0026_auto_20200521_1624.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0025_auto_20200520_0120"), ] diff --git a/dear_petition/petition/migrations/0027_auto_20200521_1703.py b/dear_petition/petition/migrations/0027_auto_20200521_1703.py index 9f6712b4..ae262e43 100644 --- a/dear_petition/petition/migrations/0027_auto_20200521_1703.py +++ b/dear_petition/petition/migrations/0027_auto_20200521_1703.py @@ -20,7 +20,6 @@ def use_states_choices(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("petition", "0026_auto_20200521_1624"), ] diff --git a/dear_petition/petition/migrations/0028_merge_20200526_1514.py b/dear_petition/petition/migrations/0028_merge_20200526_1514.py index 5d4d83ca..852b66a2 100644 --- a/dear_petition/petition/migrations/0028_merge_20200526_1514.py +++ b/dear_petition/petition/migrations/0028_merge_20200526_1514.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0027_auto_20200521_1703'), - ('petition', '0025_auto_20200521_1343'), + ("petition", "0027_auto_20200521_1703"), + ("petition", "0025_auto_20200521_1343"), ] - operations = [ - ] + operations = [] diff --git a/dear_petition/petition/migrations/0029_offense_jurisdiction.py b/dear_petition/petition/migrations/0029_offense_jurisdiction.py index cfd3ee23..348190b4 100644 --- a/dear_petition/petition/migrations/0029_offense_jurisdiction.py +++ b/dear_petition/petition/migrations/0029_offense_jurisdiction.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0028_merge_20200526_1514"), ] diff --git a/dear_petition/petition/migrations/0030_petition_parent.py b/dear_petition/petition/migrations/0030_petition_parent.py index 68bd530f..09359d99 100644 --- a/dear_petition/petition/migrations/0030_petition_parent.py +++ b/dear_petition/petition/migrations/0030_petition_parent.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0029_offense_jurisdiction"), ] diff --git a/dear_petition/petition/migrations/0031_petition_offense_records.py b/dear_petition/petition/migrations/0031_petition_offense_records.py index 80c785da..3c8cc3e2 100644 --- a/dear_petition/petition/migrations/0031_petition_offense_records.py +++ b/dear_petition/petition/migrations/0031_petition_offense_records.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0030_petition_parent"), ] @@ -13,8 +12,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="petition", name="offense_records", - field=models.ManyToManyField( - related_name="petitions", to="petition.OffenseRecord" - ), + field=models.ManyToManyField(related_name="petitions", to="petition.OffenseRecord"), ), ] diff --git a/dear_petition/petition/migrations/0032_auto_20200709_1834.py b/dear_petition/petition/migrations/0032_auto_20200709_1834.py index 84d0bd93..ec2963d5 100644 --- a/dear_petition/petition/migrations/0032_auto_20200709_1834.py +++ b/dear_petition/petition/migrations/0032_auto_20200709_1834.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0031_petition_offense_records"), ] diff --git a/dear_petition/petition/migrations/0033_batchfile.py b/dear_petition/petition/migrations/0033_batchfile.py index 1ed48020..2baf04db 100644 --- a/dear_petition/petition/migrations/0033_batchfile.py +++ b/dear_petition/petition/migrations/0033_batchfile.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0032_auto_20200709_1834"), ] diff --git a/dear_petition/petition/migrations/0034_auto_20200802_1419.py b/dear_petition/petition/migrations/0034_auto_20200802_1419.py index d5aacf2b..9601cdf2 100644 --- a/dear_petition/petition/migrations/0034_auto_20200802_1419.py +++ b/dear_petition/petition/migrations/0034_auto_20200802_1419.py @@ -7,9 +7,9 @@ def add_files(apps, schema_editor): CIPRSRecord = apps.get_model("petition", "CIPRSRecord") BatchFile = apps.get_model("petition", "BatchFile") - records = CIPRSRecord.objects.exclude( - Q(report_pdf=None) | Q(report_pdf="") - ).select_related("batch") + records = CIPRSRecord.objects.exclude(Q(report_pdf=None) | Q(report_pdf="")).select_related( + "batch" + ) for record in records: batch_file = record.batch.files.create(file=record.report_pdf) print(f"Added batch file {batch_file.file.name}") @@ -21,7 +21,6 @@ def remove_files(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ ("petition", "0033_batchfile"), ] diff --git a/dear_petition/petition/migrations/0035_remove_ciprsrecord_report_pdf.py b/dear_petition/petition/migrations/0035_remove_ciprsrecord_report_pdf.py index c337b7c9..e67ca199 100644 --- a/dear_petition/petition/migrations/0035_remove_ciprsrecord_report_pdf.py +++ b/dear_petition/petition/migrations/0035_remove_ciprsrecord_report_pdf.py @@ -4,11 +4,13 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0034_auto_20200802_1419"), ] operations = [ - migrations.RemoveField(model_name="ciprsrecord", name="report_pdf",), + migrations.RemoveField( + model_name="ciprsrecord", + name="report_pdf", + ), ] diff --git a/dear_petition/petition/migrations/0036_auto_20200807_1344.py b/dear_petition/petition/migrations/0036_auto_20200807_1344.py index dda1b2de..f0a6f777 100644 --- a/dear_petition/petition/migrations/0036_auto_20200807_1344.py +++ b/dear_petition/petition/migrations/0036_auto_20200807_1344.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0035_remove_ciprsrecord_report_pdf"), ] diff --git a/dear_petition/petition/migrations/0037_auto_20200926_2311.py b/dear_petition/petition/migrations/0037_auto_20200926_2311.py index d364ad11..be5f7680 100644 --- a/dear_petition/petition/migrations/0037_auto_20200926_2311.py +++ b/dear_petition/petition/migrations/0037_auto_20200926_2311.py @@ -4,12 +4,17 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0036_auto_20200807_1344"), ] operations = [ - migrations.RemoveField(model_name="offenserecord", name="plea",), - migrations.RemoveField(model_name="offenserecord", name="verdict",), + migrations.RemoveField( + model_name="offenserecord", + name="plea", + ), + migrations.RemoveField( + model_name="offenserecord", + name="verdict", + ), ] diff --git a/dear_petition/petition/migrations/0038_auto_20210412_0353.py b/dear_petition/petition/migrations/0038_auto_20210412_0353.py index 5972adbf..966b064f 100644 --- a/dear_petition/petition/migrations/0038_auto_20210412_0353.py +++ b/dear_petition/petition/migrations/0038_auto_20210412_0353.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0037_auto_20200926_2311"), ] diff --git a/dear_petition/petition/migrations/0039_auto_20210714_0348.py b/dear_petition/petition/migrations/0039_auto_20210714_0348.py index c86aa6cb..78fe2462 100644 --- a/dear_petition/petition/migrations/0039_auto_20210714_0348.py +++ b/dear_petition/petition/migrations/0039_auto_20210714_0348.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0038_auto_20210412_0353"), ] diff --git a/dear_petition/petition/migrations/0039_auto_20210721_0031.py b/dear_petition/petition/migrations/0039_auto_20210721_0031.py index e703b170..85055c6e 100644 --- a/dear_petition/petition/migrations/0039_auto_20210721_0031.py +++ b/dear_petition/petition/migrations/0039_auto_20210721_0031.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0038_auto_20210412_0353"), ] diff --git a/dear_petition/petition/migrations/0040_generatedpetition.py b/dear_petition/petition/migrations/0040_generatedpetition.py index f2a2063d..31f568f9 100644 --- a/dear_petition/petition/migrations/0040_generatedpetition.py +++ b/dear_petition/petition/migrations/0040_generatedpetition.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0039_auto_20210714_0348"), ] diff --git a/dear_petition/petition/migrations/0040_merge_20211210_0152.py b/dear_petition/petition/migrations/0040_merge_20211210_0152.py index d1227e0a..ea3ade57 100644 --- a/dear_petition/petition/migrations/0040_merge_20211210_0152.py +++ b/dear_petition/petition/migrations/0040_merge_20211210_0152.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0039_auto_20210714_0348'), - ('petition', '0039_auto_20210721_0031'), + ("petition", "0039_auto_20210714_0348"), + ("petition", "0039_auto_20210721_0031"), ] - operations = [ - ] + operations = [] diff --git a/dear_petition/petition/migrations/0041_merge_20211212_2109.py b/dear_petition/petition/migrations/0041_merge_20211212_2109.py index 817b5b47..8cf2f7b0 100644 --- a/dear_petition/petition/migrations/0041_merge_20211212_2109.py +++ b/dear_petition/petition/migrations/0041_merge_20211212_2109.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0040_generatedpetition'), - ('petition', '0040_merge_20211210_0152'), + ("petition", "0040_generatedpetition"), + ("petition", "0040_merge_20211210_0152"), ] - operations = [ - ] + operations = [] diff --git a/dear_petition/petition/migrations/0042_auto_20220123_0109.py b/dear_petition/petition/migrations/0042_auto_20220123_0109.py index 718ec57f..d5caab67 100644 --- a/dear_petition/petition/migrations/0042_auto_20220123_0109.py +++ b/dear_petition/petition/migrations/0042_auto_20220123_0109.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0041_merge_20211212_2109"), ] diff --git a/dear_petition/petition/migrations/0043_auto_20220319_2224.py b/dear_petition/petition/migrations/0043_auto_20220319_2224.py index 156de6e5..794be845 100644 --- a/dear_petition/petition/migrations/0043_auto_20220319_2224.py +++ b/dear_petition/petition/migrations/0043_auto_20220319_2224.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0042_auto_20220123_0109"), ] @@ -59,9 +58,7 @@ class Migration(migrations.Migration): ), ( "offense_records", - models.ManyToManyField( - related_name="documents", to="petition.OffenseRecord" - ), + models.ManyToManyField(related_name="documents", to="petition.OffenseRecord"), ), ( "petition", diff --git a/dear_petition/petition/migrations/0044_auto_20220320_1736.py b/dear_petition/petition/migrations/0044_auto_20220320_1736.py index 654abd7a..e22dfdae 100644 --- a/dear_petition/petition/migrations/0044_auto_20220320_1736.py +++ b/dear_petition/petition/migrations/0044_auto_20220320_1736.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0043_auto_20220319_2224"), ] diff --git a/dear_petition/petition/migrations/0045_remove_petition_parent.py b/dear_petition/petition/migrations/0045_remove_petition_parent.py index f4ce2ebe..8dea5fa1 100644 --- a/dear_petition/petition/migrations/0045_remove_petition_parent.py +++ b/dear_petition/petition/migrations/0045_remove_petition_parent.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0044_auto_20220320_1736"), ] diff --git a/dear_petition/petition/migrations/0046_auto_20220703_2250.py b/dear_petition/petition/migrations/0046_auto_20220703_2250.py index e73b2ba4..c37163fa 100644 --- a/dear_petition/petition/migrations/0046_auto_20220703_2250.py +++ b/dear_petition/petition/migrations/0046_auto_20220703_2250.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0045_remove_petition_parent"), ] diff --git a/dear_petition/petition/migrations/0047_alter_petitiondocument_previous_document.py b/dear_petition/petition/migrations/0047_alter_petitiondocument_previous_document.py index 37d84236..744fe190 100644 --- a/dear_petition/petition/migrations/0047_alter_petitiondocument_previous_document.py +++ b/dear_petition/petition/migrations/0047_alter_petitiondocument_previous_document.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0046_auto_20220703_2250"), ] diff --git a/dear_petition/petition/migrations/0048_auto_20221012_0454.py b/dear_petition/petition/migrations/0048_auto_20221012_0454.py index e65552de..6d5259c0 100644 --- a/dear_petition/petition/migrations/0048_auto_20221012_0454.py +++ b/dear_petition/petition/migrations/0048_auto_20221012_0454.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0047_alter_petitiondocument_previous_document"), ] diff --git a/dear_petition/petition/migrations/0048_ciprsrecord_batch_file.py b/dear_petition/petition/migrations/0048_ciprsrecord_batch_file.py index f41e8312..be41bb9d 100644 --- a/dear_petition/petition/migrations/0048_ciprsrecord_batch_file.py +++ b/dear_petition/petition/migrations/0048_ciprsrecord_batch_file.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0047_alter_petitiondocument_previous_document"), ] diff --git a/dear_petition/petition/migrations/0049_auto_20221127_0002.py b/dear_petition/petition/migrations/0049_auto_20221127_0002.py index 8132acc6..d4a49b11 100644 --- a/dear_petition/petition/migrations/0049_auto_20221127_0002.py +++ b/dear_petition/petition/migrations/0049_auto_20221127_0002.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0048_auto_20221012_0454"), ] diff --git a/dear_petition/petition/migrations/0049_batch_emails.py b/dear_petition/petition/migrations/0049_batch_emails.py index f9f4992b..ae5a40f1 100644 --- a/dear_petition/petition/migrations/0049_batch_emails.py +++ b/dear_petition/petition/migrations/0049_batch_emails.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("sendgrid", "0003_alter_email_spam_score"), ("petition", "0048_ciprsrecord_batch_file"), @@ -14,8 +13,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name="batch", name="emails", - field=models.ManyToManyField( - blank=True, related_name="batches", to="sendgrid.Email" - ), + field=models.ManyToManyField(blank=True, related_name="batches", to="sendgrid.Email"), ), ] diff --git a/dear_petition/petition/migrations/0050_alter_batchfile_file.py b/dear_petition/petition/migrations/0050_alter_batchfile_file.py index f5360af1..23ab658a 100644 --- a/dear_petition/petition/migrations/0050_alter_batchfile_file.py +++ b/dear_petition/petition/migrations/0050_alter_batchfile_file.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0049_batch_emails"), ] diff --git a/dear_petition/petition/migrations/0051_merge_20230103_1758.py b/dear_petition/petition/migrations/0051_merge_20230103_1758.py index 1f725f37..fc973249 100644 --- a/dear_petition/petition/migrations/0051_merge_20230103_1758.py +++ b/dear_petition/petition/migrations/0051_merge_20230103_1758.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0049_auto_20221127_0002"), ("petition", "0050_alter_batchfile_file"), diff --git a/dear_petition/petition/migrations/0052_auto_20230305_1344.py b/dear_petition/petition/migrations/0052_auto_20230305_1344.py index 31149ea9..b98c58da 100644 --- a/dear_petition/petition/migrations/0052_auto_20230305_1344.py +++ b/dear_petition/petition/migrations/0052_auto_20230305_1344.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0051_merge_20230103_1758"), ] diff --git a/dear_petition/petition/migrations/0052_auto_20230319_1810.py b/dear_petition/petition/migrations/0052_auto_20230319_1810.py index dcb71f36..10788eea 100644 --- a/dear_petition/petition/migrations/0052_auto_20230319_1810.py +++ b/dear_petition/petition/migrations/0052_auto_20230319_1810.py @@ -6,31 +6,54 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('petition', '0051_merge_20230103_1758'), + ("petition", "0051_merge_20230103_1758"), ] operations = [ migrations.AddField( - model_name='batch', - name='attorney', - field=models.ForeignKey(default=None, limit_choices_to={'category': 'attorney'}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='petition.contact'), + model_name="batch", + name="attorney", + field=models.ForeignKey( + default=None, + limit_choices_to={"category": "attorney"}, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="+", + to="petition.contact", + ), ), migrations.AddField( - model_name='batch', - name='client', - field=models.ForeignKey(default=None, limit_choices_to={'category': 'client'}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='batches', to='petition.contact'), + model_name="batch", + name="client", + field=models.ForeignKey( + default=None, + limit_choices_to={"category": "client"}, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="batches", + to="petition.contact", + ), ), migrations.AddField( - model_name='contact', - name='user', - field=models.ForeignKey(default=None, help_text='The user associated with this contact, if applicable', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='clients', to=settings.AUTH_USER_MODEL), + model_name="contact", + name="user", + field=models.ForeignKey( + default=None, + help_text="The user associated with this contact, if applicable", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="clients", + to=settings.AUTH_USER_MODEL, + ), ), migrations.AlterField( - model_name='contact', - name='category', - field=models.CharField(choices=[('agency', 'Agency'), ('attorney', 'Attorney'), ('client', 'Client')], max_length=16), + model_name="contact", + name="category", + field=models.CharField( + choices=[("agency", "Agency"), ("attorney", "Attorney"), ("client", "Client")], + max_length=16, + ), ), ] diff --git a/dear_petition/petition/migrations/0052_auto_20230328_2224.py b/dear_petition/petition/migrations/0052_auto_20230328_2224.py index abe1c124..14476b00 100644 --- a/dear_petition/petition/migrations/0052_auto_20230328_2224.py +++ b/dear_petition/petition/migrations/0052_auto_20230328_2224.py @@ -4,20 +4,19 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0051_merge_20230103_1758'), + ("petition", "0051_merge_20230103_1758"), ] operations = [ migrations.AddField( - model_name='offenserecord', - name='disposition', + model_name="offenserecord", + name="disposition", field=models.CharField(blank=True, max_length=256), ), migrations.AddField( - model_name='offenserecord', - name='is_visible', + model_name="offenserecord", + name="is_visible", field=models.BooleanField(default=True), ), ] diff --git a/dear_petition/petition/migrations/0053_alter_batch_client.py b/dear_petition/petition/migrations/0053_alter_batch_client.py index 1d36edd4..048c345a 100644 --- a/dear_petition/petition/migrations/0053_alter_batch_client.py +++ b/dear_petition/petition/migrations/0053_alter_batch_client.py @@ -5,15 +5,20 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0052_auto_20230319_1810'), + ("petition", "0052_auto_20230319_1810"), ] operations = [ migrations.AlterField( - model_name='batch', - name='client', - field=models.ForeignKey(limit_choices_to={'category': 'client'}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='batches', to='petition.contact'), + model_name="batch", + name="client", + field=models.ForeignKey( + limit_choices_to={"category": "client"}, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="batches", + to="petition.contact", + ), ), ] diff --git a/dear_petition/petition/migrations/0053_auto_20230407_1702.py b/dear_petition/petition/migrations/0053_auto_20230407_1702.py index c11e53c3..9bd09f92 100644 --- a/dear_petition/petition/migrations/0053_auto_20230407_1702.py +++ b/dear_petition/petition/migrations/0053_auto_20230407_1702.py @@ -4,18 +4,17 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0052_auto_20230328_2224'), + ("petition", "0052_auto_20230328_2224"), ] operations = [ migrations.RemoveField( - model_name='offenserecord', - name='disposition', + model_name="offenserecord", + name="disposition", ), migrations.RemoveField( - model_name='offenserecord', - name='is_visible', + model_name="offenserecord", + name="is_visible", ), ] diff --git a/dear_petition/petition/migrations/0054_merge_0052_auto_20230305_1344_0053_auto_20230407_1702.py b/dear_petition/petition/migrations/0054_merge_0052_auto_20230305_1344_0053_auto_20230407_1702.py index 2be530c3..2e531ffc 100644 --- a/dear_petition/petition/migrations/0054_merge_0052_auto_20230305_1344_0053_auto_20230407_1702.py +++ b/dear_petition/petition/migrations/0054_merge_0052_auto_20230305_1344_0053_auto_20230407_1702.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("petition", "0052_auto_20230305_1344"), ("petition", "0053_auto_20230407_1702"), diff --git a/dear_petition/petition/migrations/0055_merge_20230424_2121.py b/dear_petition/petition/migrations/0055_merge_20230424_2121.py index 366e3223..147879a2 100644 --- a/dear_petition/petition/migrations/0055_merge_20230424_2121.py +++ b/dear_petition/petition/migrations/0055_merge_20230424_2121.py @@ -4,11 +4,9 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0053_alter_batch_client'), - ('petition', '0054_merge_0052_auto_20230305_1344_0053_auto_20230407_1702'), + ("petition", "0053_alter_batch_client"), + ("petition", "0054_merge_0052_auto_20230305_1344_0053_auto_20230407_1702"), ] - operations = [ - ] + operations = [] diff --git a/dear_petition/petition/migrations/0056_offenserecord_count.py b/dear_petition/petition/migrations/0056_offenserecord_count.py index cc216660..be3b6afa 100644 --- a/dear_petition/petition/migrations/0056_offenserecord_count.py +++ b/dear_petition/petition/migrations/0056_offenserecord_count.py @@ -4,15 +4,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0055_merge_20230424_2121'), + ("petition", "0055_merge_20230424_2121"), ] operations = [ migrations.AddField( - model_name='offenserecord', - name='count', + model_name="offenserecord", + name="count", field=models.IntegerField(blank=True, null=True), ), ] diff --git a/dear_petition/petition/migrations/0057_ciprsrecord_has_additional_offenses.py b/dear_petition/petition/migrations/0057_ciprsrecord_has_additional_offenses.py index 8fe69296..88a765dc 100644 --- a/dear_petition/petition/migrations/0057_ciprsrecord_has_additional_offenses.py +++ b/dear_petition/petition/migrations/0057_ciprsrecord_has_additional_offenses.py @@ -4,15 +4,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0056_offenserecord_count'), + ("petition", "0056_offenserecord_count"), ] operations = [ migrations.AddField( - model_name='ciprsrecord', - name='has_additional_offenses', + model_name="ciprsrecord", + name="has_additional_offenses", field=models.BooleanField(default=False), ), ] diff --git a/dear_petition/petition/migrations/0058_contact_county.py b/dear_petition/petition/migrations/0058_contact_county.py index 58ea8018..9141507d 100644 --- a/dear_petition/petition/migrations/0058_contact_county.py +++ b/dear_petition/petition/migrations/0058_contact_county.py @@ -4,15 +4,14 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0057_ciprsrecord_has_additional_offenses'), + ("petition", "0057_ciprsrecord_has_additional_offenses"), ] operations = [ migrations.AddField( - model_name='contact', - name='county', + model_name="contact", + name="county", field=models.CharField(blank=True, max_length=100, null=True), ), ] diff --git a/dear_petition/petition/migrations/0059_alter_contact_address2.py b/dear_petition/petition/migrations/0059_alter_contact_address2.py index 4967698b..a62069cd 100644 --- a/dear_petition/petition/migrations/0059_alter_contact_address2.py +++ b/dear_petition/petition/migrations/0059_alter_contact_address2.py @@ -4,15 +4,16 @@ class Migration(migrations.Migration): - dependencies = [ - ('petition', '0058_contact_county'), + ("petition", "0058_contact_county"), ] operations = [ migrations.AlterField( - model_name='contact', - name='address2', - field=models.CharField(blank=True, default='', max_length=512, verbose_name='Address (Line 2)'), + model_name="contact", + name="address2", + field=models.CharField( + blank=True, default="", max_length=512, verbose_name="Address (Line 2)" + ), ), ] diff --git a/dear_petition/petition/migrations/0060_alter_contact_user.py b/dear_petition/petition/migrations/0060_alter_contact_user.py index 9b4d25af..33ae1cfc 100644 --- a/dear_petition/petition/migrations/0060_alter_contact_user.py +++ b/dear_petition/petition/migrations/0060_alter_contact_user.py @@ -6,16 +6,23 @@ class Migration(migrations.Migration): - dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('petition', '0059_alter_contact_address2'), + ("petition", "0059_alter_contact_address2"), ] operations = [ migrations.AlterField( - model_name='contact', - name='user', - field=models.ForeignKey(blank=True, default=None, help_text='The user associated with this contact (only applicable for Clients)', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='clients', to=settings.AUTH_USER_MODEL), + model_name="contact", + name="user", + field=models.ForeignKey( + blank=True, + default=None, + help_text="The user associated with this contact (only applicable for Clients)", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="clients", + to=settings.AUTH_USER_MODEL, + ), ), ] diff --git a/dear_petition/petition/migrations/0064_remove_contact_county_remove_contact_user_and_more.py b/dear_petition/petition/migrations/0064_remove_contact_county_remove_contact_user_and_more.py index 8e43aaff..d1155720 100644 --- a/dear_petition/petition/migrations/0064_remove_contact_county_remove_contact_user_and_more.py +++ b/dear_petition/petition/migrations/0064_remove_contact_county_remove_contact_user_and_more.py @@ -5,14 +5,17 @@ import django.db.models.deletion import django.db.models.manager -from dear_petition.petition.management.commands.convert_agency_table import convert_contacts_to_agency_objects +from dear_petition.petition.management.commands.convert_agency_table import ( + convert_contacts_to_agency_objects, +) + def forwards(apps, schema_editor): if schema_editor.connection.alias != "default": return - ContactModel = apps.get_model('petition', 'Contact') - AgencyModel = apps.get_model('petition', 'Agency') + ContactModel = apps.get_model("petition", "Contact") + AgencyModel = apps.get_model("petition", "Agency") convert_contacts_to_agency_objects(ContactModel, AgencyModel) diff --git a/dear_petition/petition/migrations/0065_alter_ciprsrecord_arrest_date_and_more.py b/dear_petition/petition/migrations/0065_alter_ciprsrecord_arrest_date_and_more.py index e54a02c4..07602ef0 100644 --- a/dear_petition/petition/migrations/0065_alter_ciprsrecord_arrest_date_and_more.py +++ b/dear_petition/petition/migrations/0065_alter_ciprsrecord_arrest_date_and_more.py @@ -18,9 +18,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="ciprsrecord", name="case_status", - field=models.CharField( - blank=True, max_length=256, verbose_name="Case Status" - ), + field=models.CharField(blank=True, max_length=256, verbose_name="Case Status"), ), migrations.AlterField( model_name="ciprsrecord", @@ -45,16 +43,12 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="ciprsrecord", name="file_no", - field=models.CharField( - blank=True, max_length=256, verbose_name="File Number" - ), + field=models.CharField(blank=True, max_length=256, verbose_name="File Number"), ), migrations.AlterField( model_name="ciprsrecord", name="has_additional_offenses", - field=models.BooleanField( - default=False, verbose_name="Has Additional Offenses" - ), + field=models.BooleanField(default=False, verbose_name="Has Additional Offenses"), ), migrations.AlterField( model_name="ciprsrecord", @@ -78,9 +72,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="ciprsrecord", name="offense_date", - field=models.DateTimeField( - blank=True, null=True, verbose_name="Offense Date" - ), + field=models.DateTimeField(blank=True, null=True, verbose_name="Offense Date"), ), migrations.AlterField( model_name="ciprsrecord", @@ -115,9 +107,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="contact", name="county", - field=models.CharField( - blank=True, max_length=100, null=True, verbose_name="County" - ), + field=models.CharField(blank=True, max_length=100, null=True, verbose_name="County"), ), migrations.AlterField( model_name="contact", @@ -207,9 +197,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="offense", name="disposed_on", - field=models.DateField( - blank=True, null=True, verbose_name="Disposed On Date" - ), + field=models.DateField(blank=True, null=True, verbose_name="Disposed On Date"), ), migrations.AlterField( model_name="offense", diff --git a/dear_petition/petition/migrations/0066_alter_offense_plea_alter_offense_verdict.py b/dear_petition/petition/migrations/0066_alter_offense_plea_alter_offense_verdict.py index e1bfc42d..dbe3137d 100644 --- a/dear_petition/petition/migrations/0066_alter_offense_plea_alter_offense_verdict.py +++ b/dear_petition/petition/migrations/0066_alter_offense_plea_alter_offense_verdict.py @@ -12,15 +12,11 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="offense", name="plea", - field=models.CharField( - blank=True, max_length=256, null=True, verbose_name="Plea" - ), + field=models.CharField(blank=True, max_length=256, null=True, verbose_name="Plea"), ), migrations.AlterField( model_name="offense", name="verdict", - field=models.CharField( - blank=True, max_length=256, null=True, verbose_name="Verdict" - ), + field=models.CharField(blank=True, max_length=256, null=True, verbose_name="Verdict"), ), ] diff --git a/dear_petition/petition/models.py b/dear_petition/petition/models.py index 5ebffcb9..22ec4b81 100644 --- a/dear_petition/petition/models.py +++ b/dear_petition/petition/models.py @@ -43,7 +43,6 @@ class CIPRSRecord(PrintableModelMixin, models.Model): - batch = models.ForeignKey("Batch", related_name="records", on_delete=models.CASCADE) batch_file = models.ForeignKey( "BatchFile", @@ -58,15 +57,22 @@ class CIPRSRecord(PrintableModelMixin, models.Model): file_no = models.CharField(max_length=256, blank=True, verbose_name="File Number") county = models.CharField(max_length=256, blank=True, verbose_name="County") dob = models.DateField(null=True, blank=True, verbose_name="Date of Birth") - sex = models.CharField(max_length=6, choices=SEX_CHOICES, default=NOT_AVAILABLE, verbose_name="Sex") + sex = models.CharField( + max_length=6, choices=SEX_CHOICES, default=NOT_AVAILABLE, verbose_name="Sex" + ) race = models.CharField(max_length=256, blank=True, verbose_name="Race") case_status = models.CharField(max_length=256, blank=True, verbose_name="Case Status") offense_date = models.DateTimeField(null=True, blank=True, verbose_name="Offense Date") arrest_date = models.DateField(null=True, blank=True, verbose_name="Arrest Date") jurisdiction = models.CharField( - max_length=16, choices=JURISDICTION_CHOICES, default=NOT_AVAILABLE, verbose_name="Jurisdiction" + max_length=16, + choices=JURISDICTION_CHOICES, + default=NOT_AVAILABLE, + verbose_name="Jurisdiction", + ) + has_additional_offenses = models.BooleanField( + default=False, verbose_name="Has Additional Offenses" ) - has_additional_offenses = models.BooleanField(default=False, verbose_name="Has Additional Offenses") def __str__(self): return f"{self.label} {self.file_no} ({self.pk})" @@ -107,7 +113,10 @@ class Offense(PrintableModelMixin, models.Model): "CIPRSRecord", related_name="offenses", on_delete=models.CASCADE ) jurisdiction = models.CharField( - choices=JURISDICTION_CHOICES, max_length=255, default=pc.DISTRICT_COURT, verbose_name="Jurisdiction" + choices=JURISDICTION_CHOICES, + max_length=255, + default=pc.DISTRICT_COURT, + verbose_name="Jurisdiction", ) disposed_on = models.DateField(blank=True, null=True, verbose_name="Disposed On Date") disposition_method = models.CharField(max_length=256, verbose_name="Disposition Method") @@ -126,9 +135,7 @@ def is_convicted_of_charged(self): pc.VERDICT_PRAYER_FOR_JUDGMENT, pc.VERDICT_RESPONSIBLE, ] - return ( - self.verdict in convicted_verdicts and self.has_equivalent_offense_records() - ) + return self.verdict in convicted_verdicts and self.has_equivalent_offense_records() def is_guilty_to_lesser(self): """ @@ -158,25 +165,23 @@ def has_equivalent_offense_records(self): if len(offense_records) != 2: return False - same_description = ( - offense_records[0].description == offense_records[1].description - ) + same_description = offense_records[0].description == offense_records[1].description same_severity = offense_records[0].severity == offense_records[1].severity return same_description and same_severity class OffenseRecord(PrintableModelMixin, models.Model): - offense = models.ForeignKey( - "Offense", related_name="offense_records", on_delete=models.CASCADE - ) + offense = models.ForeignKey("Offense", related_name="offense_records", on_delete=models.CASCADE) count = models.IntegerField(blank=True, null=True, verbose_name="Count") law = models.CharField(max_length=256, blank=True, verbose_name="Law") code = models.IntegerField(blank=True, null=True, verbose_name="Code") action = models.CharField(max_length=256, null=True, verbose_name="Action") severity = models.CharField(max_length=256, verbose_name="Severity") description = models.CharField(max_length=256, verbose_name="Description") - agency = models.ForeignKey("Contact", related_name="+", null=True, blank=True, on_delete=models.SET_NULL) + agency = models.ForeignKey( + "Contact", related_name="+", null=True, blank=True, on_delete=models.SET_NULL + ) def __str__(self): ciprs_record = self.offense.ciprs_record @@ -211,10 +216,14 @@ def is_visible(self): """ # check if any conditions are met that would cause offense record to be hidden - has_excluded_disp_method = self.offense.disposition_method in \ - [pc.DISP_METHOD_SUPERSEDING_INDICTMENT, pc.DISP_METHOD_WAIVER_OF_PROBABLE_CAUSE] + has_excluded_disp_method = self.offense.disposition_method in [ + pc.DISP_METHOD_SUPERSEDING_INDICTMENT, + pc.DISP_METHOD_WAIVER_OF_PROBABLE_CAUSE, + ] has_de_novo_review = self.has_de_novo_review - is_convicted_of_charged = self.action == pc.CHARGED and self.offense.is_convicted_of_charged() + is_convicted_of_charged = ( + self.action == pc.CHARGED and self.offense.is_convicted_of_charged() + ) # determine if the offense record should be visible return not (has_excluded_disp_method or has_de_novo_review or is_convicted_of_charged) @@ -227,14 +236,17 @@ def has_de_novo_review(self): """ # return false if this is not a district court, guilty offense - if self.offense.verdict != pc.VERDICT_GUILTY or self.offense.jurisdiction != pc.DISTRICT_COURT: + if ( + self.offense.verdict != pc.VERDICT_GUILTY + or self.offense.jurisdiction != pc.DISTRICT_COURT + ): return False # determine if there are matching (same description and severity) superior court offenses on this ciprs record return self.offense.ciprs_record.offenses.filter( jurisdiction=pc.SUPERIOR_COURT, offense_records__description=self.description, - offense_records__severity=self.severity + offense_records__severity=self.severity, ).exists() @property @@ -254,34 +266,41 @@ def disposition(self): AGENCY_SHERRIFF_OFFICE_PATTERN = r"Sheriff'?s? Office\s*$" AGENCY_SHERRIFF_DEPARTMENT_PATTERN = r"Sheriff'?s? Department\s*$" + + class AgencyWithSherriffOfficeManager(models.Manager): def get_queryset(self): """Annotation version of is_sheriff_office to be used from database""" return ( super(AgencyWithSherriffOfficeManager, self) .get_queryset() - .annotate(is_sheriff_office=Case( - When(name__iregex=AGENCY_SHERRIFF_OFFICE_PATTERN, then=Value(True)), - When(name__iregex=AGENCY_SHERRIFF_DEPARTMENT_PATTERN, then=Value(True)), - default=Value(False), - output_field=models.BooleanField(), - )) + .annotate( + is_sheriff_office=Case( + When(name__iregex=AGENCY_SHERRIFF_OFFICE_PATTERN, then=Value(True)), + When(name__iregex=AGENCY_SHERRIFF_DEPARTMENT_PATTERN, then=Value(True)), + default=Value(False), + output_field=models.BooleanField(), + ) + ) ) - + + class AgencyWithCleanNameManager(models.Manager): def get_queryset(self): """Annotation version of is_sheriff_office to be used from database""" return ( super(AgencyWithCleanNameManager, self) .get_queryset() - .annotate(clean_name=models.Func( - models.F('name'), - Value(r'[\'\-\"\(\)&:\/\.]'), # special characters to remove - Value(r''), - Value('g'), # regex flag - function='REGEXP_REPLACE', - output_field=models.TextField(), - )) + .annotate( + clean_name=models.Func( + models.F("name"), + Value(r"[\'\-\"\(\)&:\/\.]"), # special characters to remove + Value(r""), + Value("g"), # regex flag + function="REGEXP_REPLACE", + output_field=models.TextField(), + ) + ) ) @@ -289,9 +308,11 @@ class Contact(PrintableModelMixin, models.Model): name = models.CharField(max_length=512, verbose_name="Name") category = models.CharField(max_length=16, choices=CONTACT_CATEGORIES) address1 = models.CharField("Address (Line 1)", max_length=512, blank=True) - address2 = models.CharField("Address (Line 2)", max_length=512, default='', blank=True) + address2 = models.CharField("Address (Line 2)", max_length=512, default="", blank=True) city = models.CharField(max_length=64, blank=True, verbose_name="City") - state = models.CharField(choices=us_states.US_STATES, max_length=64, blank=True, verbose_name="State") + state = models.CharField( + choices=us_states.US_STATES, max_length=64, blank=True, verbose_name="State" + ) zipcode = models.CharField("ZIP Code", max_length=16, blank=True) phone_number = PhoneNumberField(null=True, blank=True, verbose_name="Phone Number") email = models.EmailField(max_length=254, null=True, blank=True, verbose_name="Email Address") @@ -300,8 +321,8 @@ class Contact(PrintableModelMixin, models.Model): objects = models.Manager() def __str__(self): - return self.name if self.name else '' - + return self.name if self.name else "" + class Client(Contact): dob = models.DateField(null=True, blank=True, verbose_name="Date of Birth") @@ -312,7 +333,7 @@ class Client(Contact): blank=True, default=None, on_delete=models.CASCADE, - help_text="The user associated with this contact (only applicable for Clients)" + help_text="The user associated with this contact (only applicable for Clients)", ) def __init__(self, *args, **kwargs): @@ -350,23 +371,21 @@ def save(self, *args, **kwargs): super().save(*args, **kwargs) - @classmethod def get_sherriff_office_by_county(cls, county: str): qs = cls.agencies_with_sherriff_office.filter(county__iexact=county, is_sheriff_office=True) if qs.count() > 1: - logger.error('Multiple agencies with sherriff department name detected. Picking first one...') + logger.error( + "Multiple agencies with sherriff department name detected. Picking first one..." + ) return qs.first() if qs.exists() else None class Batch(PrintableModelMixin, models.Model): - label = models.CharField(max_length=2048, blank=True) date_uploaded = models.DateTimeField(auto_now_add=True) user = models.ForeignKey(User, related_name="batches", on_delete=models.CASCADE) - emails = models.ManyToManyField( - "sendgrid.Email", related_name="batches", blank=True - ) + emails = models.ManyToManyField("sendgrid.Email", related_name="batches", blank=True) attorney = models.ForeignKey( Contact, related_name="+", @@ -401,9 +420,7 @@ def offenses(self): @property def most_recent_record(self): most_recent_record = None - most_recent_offense_date = make_datetime_aware( - datetime.min.strftime(DATETIME_FORMAT) - ) + most_recent_offense_date = make_datetime_aware(datetime.min.strftime(DATETIME_FORMAT)) for record in self.records.order_by("pk"): if not record.offense_date: continue @@ -432,12 +449,13 @@ def adult_felony_records(self, jurisdiction=""): def adult_misdemeanor_records(self, jurisdiction=""): return self.petition_offense_records(pc.ADULT_MISDEMEANORS, jurisdiction) - + def adjust_for_new_client_dob(self): """ Called when a new date of birth is added to a batch's client to adjust the petitions accordingly. """ from dear_petition.petition.etl.load import create_petitions_from_records + Petition.objects.filter(batch=self, form_type=pc.UNDERAGED_CONVICTIONS).delete() create_petitions_from_records(self, pc.UNDERAGED_CONVICTIONS) @@ -466,9 +484,7 @@ def age(self): @property def automatic_delete_date(self): """Date when this batch will be automatically deleted by the cleanup task""" - return self.date_uploaded + timedelta( - hours=settings.CIPRS_RECORD_LIFETIME_HOURS - ) + return self.date_uploaded + timedelta(hours=settings.CIPRS_RECORD_LIFETIME_HOURS) @receiver(signals.post_delete, sender=Batch) @@ -513,16 +529,13 @@ def __str__(self): class Comment(PrintableModelMixin, models.Model): - user = models.ForeignKey(User, related_name="comments", on_delete=models.DO_NOTHING) text = models.TextField() batch = models.ForeignKey(Batch, related_name="comments", on_delete=models.CASCADE) time = models.DateTimeField(auto_now_add=True) def save(self, *args, **kwargs): - link = reverse( - "create-petition", kwargs={"pk": self.batch.id, "tab": "comments"} - ) + link = reverse("create-petition", kwargs={"pk": self.batch.id, "tab": "comments"}) if self.user.is_staff: for staff_member in User.objects.filter(is_staff=True): staff_member.send_email( @@ -538,7 +551,6 @@ def save(self, *args, **kwargs): class Petition(PrintableModelMixin, TimeStampedModel): - form_type = models.CharField(choices=FORM_TYPES, max_length=255) batch = models.ForeignKey(Batch, on_delete=models.CASCADE, related_name="petitions") county = models.CharField(max_length=256, blank=True) @@ -593,15 +605,11 @@ def get_all_offense_records(self, include_annotations=True, filter_active=False) file_number_year=Case( When( first_two_digits_file_number__gt=two_digit_current_year, - then=Concat( - Value("19"), "first_two_digits_file_number_chars" - ), + then=Concat(Value("19"), "first_two_digits_file_number_chars"), ), When( first_two_digits_file_number__lte=two_digit_current_year, - then=Concat( - Value("20"), "first_two_digits_file_number_chars" - ), + then=Concat(Value("20"), "first_two_digits_file_number_chars"), ), ) ) @@ -628,9 +636,7 @@ def has_attachments(self): class PetitionDocument(PrintableModelMixin, models.Model): - petition = models.ForeignKey( - Petition, on_delete=models.CASCADE, related_name="documents" - ) + petition = models.ForeignKey(Petition, on_delete=models.CASCADE, related_name="documents") offense_records = models.ManyToManyField(OffenseRecord, related_name="documents") previous_document = models.OneToOneField( "self", on_delete=models.CASCADE, null=True, related_name="following_document" @@ -669,13 +675,9 @@ class GeneratedPetition(PrintableModelMixin, TimeStampedModel): number_of_charges = models.IntegerField() batch_id = models.PositiveIntegerField() county = models.CharField(max_length=256, blank=True, null=True) - jurisdiction = models.CharField( - choices=JURISDICTION_CHOICES, max_length=255, null=True - ) + jurisdiction = models.CharField(choices=JURISDICTION_CHOICES, max_length=255, null=True) race = models.CharField(max_length=256, null=True) - sex = models.CharField( - max_length=6, choices=SEX_CHOICES, default=NOT_AVAILABLE, null=True - ) + sex = models.CharField(max_length=6, choices=SEX_CHOICES, default=NOT_AVAILABLE, null=True) age = models.PositiveIntegerField(null=True) @classmethod diff --git a/dear_petition/petition/resources.py b/dear_petition/petition/resources.py index 29cb629f..30fc4ddb 100644 --- a/dear_petition/petition/resources.py +++ b/dear_petition/petition/resources.py @@ -21,22 +21,23 @@ def titlecase(string): - string = string.replace('_',' ') + string = string.replace("_", " ") return string.title() def int_to_char(i: int) -> str: return chr(i + 65) + def parse_agency_full_address(full_address: str) -> typing.Tuple[str, str, str, str, str]: """Parse fields needed for agency lookup""" - [*address_lines, city_state_zip_line] = full_address.split('\n') + [*address_lines, city_state_zip_line] = full_address.split("\n") if len(address_lines) == 0: raise ValueError("Address must be split into multiple lines") adress1 = address_lines[0] address2 = address_lines[1] if len(address_lines) == 2 else None - match = re.match(r'\s*([^,]+?)[,\s]\s*(\w{2})\s*([\w-]+)\s*$', city_state_zip_line) + match = re.match(r"\s*([^,]+?)[,\s]\s*(\w{2})\s*([\w-]+)\s*$", city_state_zip_line) if not match: raise ValueError("City, State Zipcode format is incorrect") (city, state, zipcode) = match.groups() @@ -48,11 +49,11 @@ def is_empty_row(row) -> bool: class ExcelField(fields.Field): - def __init__(self, **kwargs): - self.dropdown = kwargs.pop('dropdown', None) + self.dropdown = kwargs.pop("dropdown", None) super().__init__(**kwargs) + class ExcelDataset: def __init__(self): self.wb = Workbook() @@ -71,8 +72,15 @@ def create_new_worksheet(self, title=None): self.wb.create_sheet(title=title) self.change_worksheet(sheet_name=title) - def append(self, values, fields, is_header=False, num_indent=0, bold=False, color=None,): - + def append( + self, + values, + fields, + is_header=False, + num_indent=0, + bold=False, + color=None, + ): if len(values) != len(fields): raise ValueError("The values and fields passed to append should match.") @@ -80,23 +88,22 @@ def append(self, values, fields, is_header=False, num_indent=0, bold=False, colo self.ws.append(row) row_number = self.ws.max_row - fill=None + fill = None if color: fill = PatternFill(start_color=color, end_color=color, fill_type="solid") - + # Apply font and alignment to each cell in the row if specified - for col_number, field in enumerate(fields, num_indent+1): + for col_number, field in enumerate(fields, num_indent + 1): cell = self.ws.cell(row=row_number, column=col_number) if bold: cell.font = bold_font if fill: - cell.fill = fill - if not is_header and getattr(field, 'dropdown', None): + cell.fill = fill + if not is_header and getattr(field, "dropdown", None): self.ws.add_data_validation(field.dropdown) dropdown = field.dropdown dropdown.add(cell) - def append_separator(self): """ Appends a blank row @@ -108,13 +115,13 @@ def resize_columns(self): for column_cells in sheet.columns: max_length = 0 column = column_cells[0].column_letter - + for cell in column_cells: if cell.value: max_length = max(max_length, len(str(cell.value))) if max_length > 0: - adjusted_width = max_length + 2 + adjusted_width = max_length + 2 sheet.column_dimensions[column].width = adjusted_width def save(self, filename): @@ -125,184 +132,258 @@ def save(self, filename): class AgencyResource(resources.ModelResource): - county = ExcelField(attribute='county', column_name='County') - name = ExcelField(attribute='name', column_name='Arresting Agency') - address = ExcelField(column_name='Address') + county = ExcelField(attribute="county", column_name="County") + name = ExcelField(attribute="name", column_name="Arresting Agency") + address = ExcelField(column_name="Address") def init_instance(self, row=None): instance = super().init_instance(row) if is_empty_row(row): return instance - instance.address1 = row['address1'] - instance.address2 = row['address2'] + instance.address1 = row["address1"] + instance.address2 = row["address2"] return instance def get_instance(self, instance_loader, row): try: return super().get_instance(instance_loader, row) except models.Agency.MultipleObjectsReturned as e: - raise models.Agency.MultipleObjectsReturned(f"There are multiple agencies named '{row['Arresting Agency']}' in county '{row['County']}. Ensure there is only 1.") + raise models.Agency.MultipleObjectsReturned( + f"There are multiple agencies named '{row['Arresting Agency']}' in county '{row['County']}. Ensure there is only 1." + ) def before_import_row(self, row, **kwargs): if is_empty_row(row): return # found a bug where leading newlines were causing false negative matches for existing agencies - row['Arresting Agency'] = row['Arresting Agency'].strip() - row['name'] = row['Arresting Agency'] - row['County'] = row['County'].strip() - row['county'] = row['County'].strip() - - (address1, address2, city, state, zipcode) = parse_agency_full_address(row['Address']) - row['city'] = city.strip() - row['state'] = state.strip() - row['zipcode'] = zipcode.strip() - row['address1'] = address1.strip() - row['address2'] = address2.strip() if address2 else None - - name = row['name'] - if re.search(models.AGENCY_SHERRIFF_OFFICE_PATTERN, name, re.IGNORECASE) or re.search(models.AGENCY_SHERRIFF_DEPARTMENT_PATTERN, name, re.IGNORECASE): - row['is_sheriff'] = True + row["Arresting Agency"] = row["Arresting Agency"].strip() + row["name"] = row["Arresting Agency"] + row["County"] = row["County"].strip() + row["county"] = row["County"].strip() + + (address1, address2, city, state, zipcode) = parse_agency_full_address(row["Address"]) + row["city"] = city.strip() + row["state"] = state.strip() + row["zipcode"] = zipcode.strip() + row["address1"] = address1.strip() + row["address2"] = address2.strip() if address2 else None + + name = row["name"] + if re.search(models.AGENCY_SHERRIFF_OFFICE_PATTERN, name, re.IGNORECASE) or re.search( + models.AGENCY_SHERRIFF_DEPARTMENT_PATTERN, name, re.IGNORECASE + ): + row["is_sheriff"] = True else: - row['is_sheriff'] = False + row["is_sheriff"] = False def skip_row(self, instance, original, row, import_validation_errors=None): - if (is_empty_row(row)): + if is_empty_row(row): return True - return super().skip_row(instance, original, row, import_validation_errors=import_validation_errors) - + return super().skip_row( + instance, original, row, import_validation_errors=import_validation_errors + ) class Meta: model = models.Agency - import_id_fields = ('name', 'county') + import_id_fields = ("name", "county") store_instance = True + class MultiModelResource(resources.ModelResource): - - PARENT_OBJECT_FIELD = None - NUM_INDENT=0 - - def __init__(self): - super().__init__() - self.saved_instance_ids=[] - - def after_save_instance(self, instance, using_transactions, dry_run): - if not dry_run: - self.saved_instance_ids.append(instance.id) - - def export_resource(self, obj): - return [self.export_field(field, obj) for field in self.get_export_fields()] - - def get_export_headers(self): - headers = [titlecase(field.column_name) for field in self.get_fields()] - return headers - - def export_field(self, field, obj): - field_name = self.get_field_name(field) - dehydrate_method = field.get_dehydrate_method(field_name) - - if isinstance(self._meta.model._meta.get_field(field.attribute), BooleanField): - field.dropdown = DataValidation(type="list", formula1=f'"True,False"', showDropDown=True) - - method = getattr(self, dehydrate_method, None) - if method is not None: - return method(obj) - - return field.export(obj) - - def import_field(self, field, obj, data, is_m2m=False, **kwargs): - hydrate_method = getattr(self, f"hydrate_{field.attribute}", None) - if hydrate_method is not None: - hydrate_method(field, data) - - if field.attribute and field.column_name in data: - field.save(obj, data, is_m2m, **kwargs) - - def export_excel(self, data, dataset: ExcelDataset, color=None, **kwargs): - headers = self.get_export_headers() - fields = self.get_export_fields() - - dataset.append(headers, fields, num_indent=self.NUM_INDENT, is_header=True, bold=True, color=color) - - if isinstance(data, QuerySet): - for obj in data: - dataset.append(self.export_resource(obj), fields, num_indent=self.NUM_INDENT, color=color) - else: - dataset.append(self.export_resource(data), fields, num_indent=self.NUM_INDENT, color=color) - - return dataset - - - + PARENT_OBJECT_FIELD = None + NUM_INDENT = 0 + + def __init__(self): + super().__init__() + self.saved_instance_ids = [] + + def after_save_instance(self, instance, using_transactions, dry_run): + if not dry_run: + self.saved_instance_ids.append(instance.id) + + def export_resource(self, obj): + return [self.export_field(field, obj) for field in self.get_export_fields()] + + def get_export_headers(self): + headers = [titlecase(field.column_name) for field in self.get_fields()] + return headers + + def export_field(self, field, obj): + field_name = self.get_field_name(field) + dehydrate_method = field.get_dehydrate_method(field_name) + + if isinstance(self._meta.model._meta.get_field(field.attribute), BooleanField): + field.dropdown = DataValidation( + type="list", formula1=f'"True,False"', showDropDown=True + ) + + method = getattr(self, dehydrate_method, None) + if method is not None: + return method(obj) + + return field.export(obj) + + def import_field(self, field, obj, data, is_m2m=False, **kwargs): + hydrate_method = getattr(self, f"hydrate_{field.attribute}", None) + if hydrate_method is not None: + hydrate_method(field, data) + + if field.attribute and field.column_name in data: + field.save(obj, data, is_m2m, **kwargs) + + def export_excel(self, data, dataset: ExcelDataset, color=None, **kwargs): + headers = self.get_export_headers() + fields = self.get_export_fields() + + dataset.append( + headers, fields, num_indent=self.NUM_INDENT, is_header=True, bold=True, color=color + ) + + if isinstance(data, QuerySet): + for obj in data: + dataset.append( + self.export_resource(obj), fields, num_indent=self.NUM_INDENT, color=color + ) + else: + dataset.append( + self.export_resource(data), fields, num_indent=self.NUM_INDENT, color=color + ) + + return dataset + + class BatchResource(MultiModelResource): class Meta: model = models.Batch - include = ('label',) + include = ("label",) + class RecordResource(MultiModelResource): batch_id = fields.Field(attribute="batch_id") - label = ExcelField(attribute='label', column_name='Defendent Name') - dob = ExcelField(attribute='dob', column_name='Date of Birth') - has_additional_offenses = ExcelField(attribute='has_additional_offenses', column_name='Additional Offenses Exist') - jurisdiction = ExcelField(attribute='jurisdiction', dropdown=DataValidation(type="list", formula1=f'"{",".join(constants.JURISDICTION_MAP.values())}"', showDropDown=True)) - sex = ExcelField(attribute='sex', dropdown=DataValidation(type="list", formula1=f'"{",".join(constants.SEX_MAP.keys())}"', showDropDown=True)) - + label = ExcelField(attribute="label", column_name="Defendent Name") + dob = ExcelField(attribute="dob", column_name="Date of Birth") + has_additional_offenses = ExcelField( + attribute="has_additional_offenses", column_name="Additional Offenses Exist" + ) + jurisdiction = ExcelField( + attribute="jurisdiction", + dropdown=DataValidation( + type="list", + formula1=f'"{",".join(constants.JURISDICTION_MAP.values())}"', + showDropDown=True, + ), + ) + sex = ExcelField( + attribute="sex", + dropdown=DataValidation( + type="list", formula1=f'"{",".join(constants.SEX_MAP.keys())}"', showDropDown=True + ), + ) + def dehydrate_jurisdiction(self, record): - jurisdiction = getattr(record, 'jurisdiction') + jurisdiction = getattr(record, "jurisdiction") return constants.JURISDICTION_MAP[jurisdiction] - + def hydrate_jurisdiction(self, field, data): attribute = field.attribute - for k,v in constants.JURISDICTION_MAP.items(): + for k, v in constants.JURISDICTION_MAP.items(): if v == data[attribute]: data[attribute] = k break return data - + def dehydrate_sex(self, record): - sex = getattr(record, 'sex') + sex = getattr(record, "sex") return constants.SEX_CHOICES[sex] - + def hydrate_sex(self, field, data): attribute = field.attribute data[attribute] = constants.SEX_MAP[data[attribute]] return data - + def get_export_fields(self): - return [field for field in super().get_export_fields() if field.column_name not in ('batch_id',)] - + return [ + field for field in super().get_export_fields() if field.column_name not in ("batch_id",) + ] + def get_export_headers(self): - return [header for header in super().get_export_headers() if header not in ('Batch Id',)] + return [header for header in super().get_export_headers() if header not in ("Batch Id",)] class Meta: model = models.CIPRSRecord - exclude = ('id', 'batch', 'batch_file', 'date_uploaded', 'data',) - export_order = ('batch_id','label','file_no','dob', 'jurisdiction', 'county', 'has_additional_offenses') + exclude = ( + "id", + "batch", + "batch_file", + "date_uploaded", + "data", + ) + export_order = ( + "batch_id", + "label", + "file_no", + "dob", + "jurisdiction", + "county", + "has_additional_offenses", + ) force_init_instance = True + class OffenseResource(MultiModelResource): ciprs_record_id = fields.Field(attribute="ciprs_record_id") - disposed_on = ExcelField(attribute='disposed_on', column_name='Disposition Date') - jurisdiction = ExcelField(attribute='jurisdiction', dropdown=DataValidation(type="list", formula1=f'"{",".join(constants.JURISDICTION_MAP.values())}"', showDropDown=True)) - plea = ExcelField(attribute='plea', dropdown=DataValidation(type="list", formula1=f'"{",".join(constants.VERDICT_CODE_MAP.keys())}"', showDropDown=True)) - verdict = ExcelField(attribute='verdict', dropdown=DataValidation(type="list", formula1=f'"{",".join(constants.VERDICT_CODE_MAP.keys())}"', showDropDown=True)) - disposition_method = ExcelField(attribute='disposition_method', dropdown=DataValidation(type="list", formula1=f'"{",".join(constants.DISPOSITION_METHOD_CODE_MAP.keys())}"', showDropDown=True)) + disposed_on = ExcelField(attribute="disposed_on", column_name="Disposition Date") + jurisdiction = ExcelField( + attribute="jurisdiction", + dropdown=DataValidation( + type="list", + formula1=f'"{",".join(constants.JURISDICTION_MAP.values())}"', + showDropDown=True, + ), + ) + plea = ExcelField( + attribute="plea", + dropdown=DataValidation( + type="list", + formula1=f'"{",".join(constants.VERDICT_CODE_MAP.keys())}"', + showDropDown=True, + ), + ) + verdict = ExcelField( + attribute="verdict", + dropdown=DataValidation( + type="list", + formula1=f'"{",".join(constants.VERDICT_CODE_MAP.keys())}"', + showDropDown=True, + ), + ) + disposition_method = ExcelField( + attribute="disposition_method", + dropdown=DataValidation( + type="list", + formula1=f'"{",".join(constants.DISPOSITION_METHOD_CODE_MAP.keys())}"', + showDropDown=True, + ), + ) def get_export_fields(self): - return [field for field in super().get_export_fields() if field.column_name != 'ciprs_record_id'] - + return [ + field for field in super().get_export_fields() if field.column_name != "ciprs_record_id" + ] + def get_export_headers(self): - return [header for header in super().get_export_headers() if header != 'Ciprs Record Id'] + return [header for header in super().get_export_headers() if header != "Ciprs Record Id"] def dehydrate_jurisdiction(self, record): - jurisdiction = getattr(record, 'jurisdiction') + jurisdiction = getattr(record, "jurisdiction") return constants.JURISDICTION_MAP[jurisdiction] - + def hydrate_jurisdiction(self, field, data): attribute = field.attribute - for k,v in constants.JURISDICTION_MAP.items(): + for k, v in constants.JURISDICTION_MAP.items(): if v == data[attribute]: data[attribute] = k break @@ -311,45 +392,57 @@ def hydrate_jurisdiction(self, field, data): class Meta: model = models.Offense - exclude = ('id', 'ciprs_record') - export_order = ('ciprs_record_id',) + exclude = ("id", "ciprs_record") + export_order = ("ciprs_record_id",) force_init_instance = True class OffenseRecordResource(MultiModelResource): - - NUM_INDENT=1 + NUM_INDENT = 1 offense_id = fields.Field(attribute="offense_id") - count = ExcelField(attribute='count', column_name='#') - severity = ExcelField(attribute='severity', dropdown=DataValidation(type="list", formula1=f'"{",".join(constants.SEVERITIES._db_values)}"', showDropDown=True)) - action = ExcelField(attribute='action', dropdown=DataValidation(type="list", formula1=f'"{",".join(constants.ACTIONS._db_values)}"', showDropDown=True)) + count = ExcelField(attribute="count", column_name="#") + severity = ExcelField( + attribute="severity", + dropdown=DataValidation( + type="list", + formula1=f'"{",".join(constants.SEVERITIES._db_values)}"', + showDropDown=True, + ), + ) + action = ExcelField( + attribute="action", + dropdown=DataValidation( + type="list", formula1=f'"{",".join(constants.ACTIONS._db_values)}"', showDropDown=True + ), + ) def get_export_fields(self): - return [field for field in super().get_export_fields() if field.column_name != 'offense_id'] - + return [field for field in super().get_export_fields() if field.column_name != "offense_id"] + def get_export_headers(self): - return [header for header in super().get_export_headers() if header not in ('Offense Id')] + return [header for header in super().get_export_headers() if header not in ("Offense Id")] class Meta: model = models.OffenseRecord - exclude = ('id', 'agency', 'offense') - export_order = ('offense_id',) + exclude = ("id", "agency", "offense") + export_order = ("offense_id",) force_init_instance = True + class ClientResource(MultiModelResource): - dob = ExcelField(attribute='dob', column_name='Date of Birth') + dob = ExcelField(attribute="dob", column_name="Date of Birth") class Meta: model = models.Client - exclude = ('id', 'contact_ptr', 'category','user') + exclude = ("id", "contact_ptr", "category", "user") force_init_instance = True def get_import_fields(self): return ["batch_id"] + super().get_import_fields() -class RecordSummaryResource(resources.ModelResource): +class RecordSummaryResource(resources.ModelResource): class Meta: model = models.Batch @@ -368,8 +461,7 @@ def __init__(self): self.first_offense_record_header = self.offense_record_headers[0] def export(self, batch_object=None, *args, **kwargs): - - if not isinstance(batch_object,models.Batch): + if not isinstance(batch_object, models.Batch): raise ValueError("Queryset must be a Batch object") dataset = ExcelDataset() @@ -380,27 +472,32 @@ def export(self, batch_object=None, *args, **kwargs): self.client_resource.export_excel(batch_object.client, dataset) # Record - for record_object in batch_object.records.order_by('file_no').prefetch_related('offenses','offenses__offense_records').all(): + for record_object in ( + batch_object.records.order_by("file_no") + .prefetch_related("offenses", "offenses__offense_records") + .all() + ): dataset.create_new_worksheet(title=record_object.file_no) - self.record_resource.export_excel(record_object, dataset, color='E0FFFF') + self.record_resource.export_excel(record_object, dataset, color="E0FFFF") dataset.append_separator() # Offense - i=0 + i = 0 for offense_object in record_object.offenses.all(): - color = '90EE90' if i % 2 == 1 else 'FFFFE0' + color = "90EE90" if i % 2 == 1 else "FFFFE0" self.offense_resource.export_excel(offense_object, dataset, color=color) # Offense Record - self.offense_record_resource.export_excel(offense_object.offense_records.all(), dataset, color=color) + self.offense_record_resource.export_excel( + offense_object.offense_records.all(), dataset, color=color + ) dataset.append_separator() - i+=1 + i += 1 dataset.resize_columns() return dataset - - + def import_data(self, workbook: Workbook, batch: models.Batch, *args, **kwargs): with transaction.atomic(): if CLIENT_SHEET_TITLE in workbook: @@ -421,39 +518,56 @@ def import_data(self, workbook: Workbook, batch: models.Batch, *args, **kwargs): current_resource = None current_dataset = tablib.Dataset() for row_number, row in enumerate(worksheet.iter_rows(), 1): - - if all(cell.value in (None, '') for cell in row): - continue # This is an empty row. + if all(cell.value in (None, "") for cell in row): + continue # This is an empty row. for cell_number, cell in enumerate(worksheet[row_number]): if cell.value is not None: - break # Get first non-null value - - if cell.value in (self.first_record_header, self.first_offense_header, self.first_offense_record_header): + break # Get first non-null value + if cell.value in ( + self.first_record_header, + self.first_offense_header, + self.first_offense_record_header, + ): if current_resource and current_dataset: result = current_resource.import_data(current_dataset) current_dataset = tablib.Dataset() if cell.value == self.first_record_header: current_resource = self.record_resource - current_dataset.headers = [col.column_name for col in current_resource.get_import_fields()] + current_dataset.headers = [ + col.column_name for col in current_resource.get_import_fields() + ] elif cell.value == self.first_offense_header: current_resource = self.offense_resource - current_dataset.headers = [col.column_name for col in current_resource.get_import_fields()] + current_dataset.headers = [ + col.column_name for col in current_resource.get_import_fields() + ] elif cell.value == self.first_offense_record_header: current_resource = self.offense_record_resource - current_dataset.headers = [col.column_name for col in current_resource.get_import_fields()] - else: + current_dataset.headers = [ + col.column_name for col in current_resource.get_import_fields() + ] + else: if current_resource == self.record_resource: - row = list(row)[current_resource.NUM_INDENT:len(self.record_headers) + current_resource.NUM_INDENT] + row = list(row)[ + current_resource.NUM_INDENT : len(self.record_headers) + + current_resource.NUM_INDENT + ] current_dataset.append([batch.id] + [cell.value for cell in row]) elif current_resource == self.offense_resource: - row = list(row)[current_resource.NUM_INDENT:len(self.offense_headers) + current_resource.NUM_INDENT] + row = list(row)[ + current_resource.NUM_INDENT : len(self.offense_headers) + + current_resource.NUM_INDENT + ] record_id = self.record_resource.saved_instance_ids[-1] current_dataset.append([record_id] + [cell.value for cell in row]) elif current_resource == self.offense_record_resource: - row = list(row)[current_resource.NUM_INDENT:len(self.offense_record_headers) + current_resource.NUM_INDENT] + row = list(row)[ + current_resource.NUM_INDENT : len(self.offense_record_headers) + + current_resource.NUM_INDENT + ] offense_id = self.offense_resource.saved_instance_ids[-1] current_dataset.append([offense_id] + [cell.value for cell in row]) else: @@ -463,4 +577,4 @@ def import_data(self, workbook: Workbook, batch: models.Batch, *args, **kwargs): result = current_resource.import_data(current_dataset) batch.refresh_from_db() - create_batch_petitions(batch) \ No newline at end of file + create_batch_petitions(batch) diff --git a/dear_petition/petition/tests/factories.py b/dear_petition/petition/tests/factories.py index 0be9e99c..3634971c 100644 --- a/dear_petition/petition/tests/factories.py +++ b/dear_petition/petition/tests/factories.py @@ -2,18 +2,37 @@ import random import factory -from dear_petition.petition.models import (Batch, BatchFile, CIPRSRecord, - Contact, Agency, Client, GeneratedPetition, Offense, - OffenseRecord, Petition, - PetitionDocument, - PetitionOffenseRecord) +from dear_petition.petition.models import ( + Batch, + BatchFile, + CIPRSRecord, + Contact, + Agency, + Client, + GeneratedPetition, + Offense, + OffenseRecord, + Petition, + PetitionDocument, + PetitionOffenseRecord, +) from dear_petition.users.tests.factories import UserFactory from django.core.files.uploadedfile import InMemoryUploadedFile from pytz import timezone -from ..constants import (CHARGED, CONVICTED, DISMISSED, DISTRICT_COURT, - DISTRICT_COURT_WITHOUT_DA_LEAVE, DURHAM_COUNTY, - FEMALE, MALE, NOT_AVAILABLE, SUPERIOR_COURT, UNKNOWN) +from ..constants import ( + CHARGED, + CONVICTED, + DISMISSED, + DISTRICT_COURT, + DISTRICT_COURT_WITHOUT_DA_LEAVE, + DURHAM_COUNTY, + FEMALE, + MALE, + NOT_AVAILABLE, + SUPERIOR_COURT, + UNKNOWN, +) class ContactFactory(factory.django.DjangoModelFactory): @@ -120,15 +139,11 @@ class CIPRSRecordFactory(factory.django.DjangoModelFactory): data = factory.Sequence(record_data) offense_date = factory.Faker("date_time", tzinfo=timezone("US/Eastern")) arrest_date = factory.Faker("date_object") - jurisdiction = factory.LazyFunction( - lambda: random.choice([DISTRICT_COURT, SUPERIOR_COURT]) - ) + jurisdiction = factory.LazyFunction(lambda: random.choice([DISTRICT_COURT, SUPERIOR_COURT])) county = factory.LazyFunction(lambda: random.choice(["DURHAM", "WAKE", "ORANGE"])) file_no = "99CRAAAAAAAAAAAA" race = factory.LazyFunction(lambda: random.choice(["ASIAN", "BLACK", "WHITE"])) - sex = factory.LazyFunction( - lambda: random.choice([FEMALE, MALE, NOT_AVAILABLE, UNKNOWN]) - ) + sex = factory.LazyFunction(lambda: random.choice([FEMALE, MALE, NOT_AVAILABLE, UNKNOWN])) class Meta: model = CIPRSRecord @@ -175,9 +190,7 @@ class Meta: class DismissedOffenseRecordFactory(factory.django.DjangoModelFactory): - offense = factory.SubFactory( - OffenseFactory, disposition_method=DISTRICT_COURT_WITHOUT_DA_LEAVE - ) + offense = factory.SubFactory(OffenseFactory, disposition_method=DISTRICT_COURT_WITHOUT_DA_LEAVE) law = "20-141(J1)" code = "4450" action = CHARGED @@ -189,9 +202,7 @@ class Meta: class GuiltyOffenseRecordFactory(factory.django.DjangoModelFactory): - offense = factory.SubFactory( - OffenseFactory, disposition_method=DISTRICT_COURT_WITHOUT_DA_LEAVE - ) + offense = factory.SubFactory(OffenseFactory, disposition_method=DISTRICT_COURT_WITHOUT_DA_LEAVE) law = "20-141(J1)" code = "4450" action = "Guilty" diff --git a/dear_petition/petition/tests/test_admin.py b/dear_petition/petition/tests/test_admin.py index 1c94bf77..73ffc985 100644 --- a/dear_petition/petition/tests/test_admin.py +++ b/dear_petition/petition/tests/test_admin.py @@ -3,22 +3,35 @@ from dear_petition.petition.admin import GeneratedPetitionAdmin from dear_petition.petition.models import GeneratedPetition + class MockRequest: pass + request = MockRequest() def test_generated_petition_admin(): # test constants - READ_ONLY_FIELDS = ["username", "batch_id", "form_type", "number_of_charges", "county", "jurisdiction", "race", - "sex", "age"] + READ_ONLY_FIELDS = [ + "username", + "batch_id", + "form_type", + "number_of_charges", + "county", + "jurisdiction", + "race", + "sex", + "age", + ] READ_WRITE_FIELDS = [] # there are currently no writable fields in GeneratedPetitionAdmin # create GeneratedPetitionAdmin gp_admin = GeneratedPetitionAdmin(GeneratedPetition, AdminSite()) # assertions - assert(list(gp_admin.get_form(request).base_fields) == READ_WRITE_FIELDS) - assert(list(gp_admin.get_fields(request)) == READ_WRITE_FIELDS + READ_ONLY_FIELDS) - assert(list(gp_admin.get_fieldsets(request)) == [(None, {"fields": READ_WRITE_FIELDS + READ_ONLY_FIELDS})]) + assert list(gp_admin.get_form(request).base_fields) == READ_WRITE_FIELDS + assert list(gp_admin.get_fields(request)) == READ_WRITE_FIELDS + READ_ONLY_FIELDS + assert list(gp_admin.get_fieldsets(request)) == [ + (None, {"fields": READ_WRITE_FIELDS + READ_ONLY_FIELDS}) + ] diff --git a/dear_petition/petition/tests/test_models.py b/dear_petition/petition/tests/test_models.py index 51200b20..e4e89c5b 100644 --- a/dear_petition/petition/tests/test_models.py +++ b/dear_petition/petition/tests/test_models.py @@ -20,10 +20,14 @@ CHARGED, CONVICTED, FEMALE, - MALE + MALE, ) from dear_petition.petition.models import GeneratedPetition -from dear_petition.petition.tests.factories import AgencyFactory, OffenseFactory, OffenseRecordFactory +from dear_petition.petition.tests.factories import ( + AgencyFactory, + OffenseFactory, + OffenseRecordFactory, +) from dear_petition.users.tests.factories import UserFactory pytestmark = pytest.mark.django_db @@ -43,18 +47,20 @@ def test_printable_model_mixin__petition(batch, petition, offense_record1): petition.offense_records.add(offense_record1) # assertions - expected_repr = ", ".join([ - "{'id': " + repr(petition.id), - "'created': " + repr(petition.created), - "'modified': " + repr(petition.modified), - "'form_type': 'AOC-CR-287'", - "'batch': " + repr(batch.id), - "'county': 'DURHAM'", - "'jurisdiction': 'D'", - "'offense_records': [" + repr(offense_record1.id) + "]", - "'agencies': [" + repr(contact1.id) + ", " + repr(contact2.id) + "]}" - ]) - assert(repr(petition) == expected_repr) + expected_repr = ", ".join( + [ + "{'id': " + repr(petition.id), + "'created': " + repr(petition.created), + "'modified': " + repr(petition.modified), + "'form_type': 'AOC-CR-287'", + "'batch': " + repr(batch.id), + "'county': 'DURHAM'", + "'jurisdiction': 'D'", + "'offense_records': [" + repr(offense_record1.id) + "]", + "'agencies': [" + repr(contact1.id) + ", " + repr(contact2.id) + "]}", + ] + ) + assert repr(petition) == expected_repr def test_printable_model_mixin__user(): @@ -63,44 +69,51 @@ def test_printable_model_mixin__user(): """ # create model object - user = UserFactory(username="tmarshall", email="tmarshall@supremecourt.gov", name="Thurgood Marshall") + user = UserFactory( + username="tmarshall", email="tmarshall@supremecourt.gov", name="Thurgood Marshall" + ) # assertions - expected_repr = ", ".join([ - "{'id': " + repr(user.id), - "'last_login': None", - "'is_superuser': False", - "'username': 'tmarshall'", - "'first_name': ''", - "'last_name': ''", - "'email': 'tmarshall@supremecourt.gov'", - "'is_staff': False", - "'is_active': True", - "'date_joined': " + repr(user.date_joined), - "'name': 'Thurgood Marshall'", - "'last_generated_petition_time': None", - "'groups': []", - "'user_permissions': []}" - ]) - assert(repr(user) == expected_repr) - - -@pytest.mark.parametrize("input_dob, input_today, expected_age", [ - # has had birthday already this year - (datetime(2000, 1, 1), datetime(2030, 7, 15, 0, 0, 0, 0, pytz.UTC), 30), - # has not had birthday yet this year - (datetime(2000, 12, 31), datetime(2030, 7, 15, 0, 0, 0, 0, pytz.UTC), 29), - # tomorrow is birthday - (datetime(2000, 7, 15), datetime(2020, 7, 14, 23, 59, 59, 999999, pytz.UTC), 19), - # today is birthday - (datetime(2000, 7, 15), datetime(2020, 7, 15, 0, 0, 0, 0, pytz.UTC), 20), - # born today - (datetime(2020, 7, 15), datetime(2020, 7, 15, 0, 0, 0, 0, pytz.UTC), 0), - # born 100+ years ago - (datetime(1920, 7, 15), datetime(2020, 7, 15, 0, 0, 0, 0, pytz.UTC), 100), - # age < 0 (dob mistake) - (datetime(2070, 1, 1), datetime(2020, 7, 15, 0, 0, 0, 0, pytz.UTC), -50), -]) + expected_repr = ", ".join( + [ + "{'id': " + repr(user.id), + "'last_login': None", + "'is_superuser': False", + "'username': 'tmarshall'", + "'first_name': ''", + "'last_name': ''", + "'email': 'tmarshall@supremecourt.gov'", + "'is_staff': False", + "'is_active': True", + "'date_joined': " + repr(user.date_joined), + "'name': 'Thurgood Marshall'", + "'last_generated_petition_time': None", + "'groups': []", + "'user_permissions': []}", + ] + ) + assert repr(user) == expected_repr + + +@pytest.mark.parametrize( + "input_dob, input_today, expected_age", + [ + # has had birthday already this year + (datetime(2000, 1, 1), datetime(2030, 7, 15, 0, 0, 0, 0, pytz.UTC), 30), + # has not had birthday yet this year + (datetime(2000, 12, 31), datetime(2030, 7, 15, 0, 0, 0, 0, pytz.UTC), 29), + # tomorrow is birthday + (datetime(2000, 7, 15), datetime(2020, 7, 14, 23, 59, 59, 999999, pytz.UTC), 19), + # today is birthday + (datetime(2000, 7, 15), datetime(2020, 7, 15, 0, 0, 0, 0, pytz.UTC), 20), + # born today + (datetime(2020, 7, 15), datetime(2020, 7, 15, 0, 0, 0, 0, pytz.UTC), 0), + # born 100+ years ago + (datetime(1920, 7, 15), datetime(2020, 7, 15, 0, 0, 0, 0, pytz.UTC), 100), + # age < 0 (dob mistake) + (datetime(2070, 1, 1), datetime(2020, 7, 15, 0, 0, 0, 0, pytz.UTC), -50), + ], +) def test_batch__age(mocker, batch, record0, input_dob, input_today, expected_age): """ Test age in Batch @@ -116,7 +129,7 @@ def test_batch__age(mocker, batch, record0, input_dob, input_today, expected_age record0(None, "ASIAN", FEMALE) # assertions - assert(batch.age == expected_age) + assert batch.age == expected_age def test_batch__age_no_dob(batch, record0): @@ -128,7 +141,7 @@ def test_batch__age_no_dob(batch, record0): record0(None, "ASIAN", FEMALE) # assertions - assert(batch.age is None) + assert batch.age is None def test_batch__race(batch, record0): @@ -143,7 +156,7 @@ def test_batch__race(batch, record0): record0(None, RACE, FEMALE) # assertions - assert(batch.race == RACE) + assert batch.race == RACE def test_batch__sex(batch, record0): @@ -158,11 +171,12 @@ def test_batch__sex(batch, record0): record0(None, "BLACK", SEX) # assertions - assert(batch.sex == SEX) + assert batch.sex == SEX -def test_generated_petition__get_stats_generated_petition(mocker, charged_dismissed_record, charged_not_guilty_record, - petition_document, user): +def test_generated_petition__get_stats_generated_petition( + mocker, charged_dismissed_record, charged_not_guilty_record, petition_document, user +): """ Test get_stats_generated_petition in GeneratedPetition """ @@ -187,19 +201,21 @@ def test_generated_petition__get_stats_generated_petition(mocker, charged_dismis generated_petition = GeneratedPetition.get_stats_generated_petition(petition_document.id, user) # assertions - assert(generated_petition.username == USERNAME) - assert(generated_petition.form_type == DISMISSED) - assert(generated_petition.number_of_charges == len(OFFENSE_RECORDS)) - assert(generated_petition.batch_id == petition_document.petition.batch.id) - assert(generated_petition.age == AGE) - assert(generated_petition.race == RACE) - assert(generated_petition.sex == SEX) - assert(generated_petition.jurisdiction == DISTRICT_COURT) - assert(generated_petition.county == DURHAM_COUNTY) - assert(user.last_generated_petition_time == TODAY) - - -def test_generated_petition__get_stats_generated_petition__dob_after_today(mocker, petition_document, record0, user): + assert generated_petition.username == USERNAME + assert generated_petition.form_type == DISMISSED + assert generated_petition.number_of_charges == len(OFFENSE_RECORDS) + assert generated_petition.batch_id == petition_document.petition.batch.id + assert generated_petition.age == AGE + assert generated_petition.race == RACE + assert generated_petition.sex == SEX + assert generated_petition.jurisdiction == DISTRICT_COURT + assert generated_petition.county == DURHAM_COUNTY + assert user.last_generated_petition_time == TODAY + + +def test_generated_petition__get_stats_generated_petition__dob_after_today( + mocker, petition_document, record0, user +): """ Test get_stats_generated_petition in GeneratedPetition when date of birth on CIPRS record (mistakenly) is after today @@ -218,52 +234,70 @@ def test_generated_petition__get_stats_generated_petition__dob_after_today(mocke # test should pass if error raised with pytest.raises(IntegrityError): - # get stats for generated petition - generated_petition = GeneratedPetition.get_stats_generated_petition(petition_document.id, user) + generated_petition = GeneratedPetition.get_stats_generated_petition( + petition_document.id, user + ) def test_offense__is_convicted_of_charged(): """ Test is_convicted_of_charged in Offense. Should return true. """ - offense = OffenseFactory(verdict = VERDICT_GUILTY) - OffenseRecordFactory(offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") - OffenseRecordFactory(offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") + offense = OffenseFactory(verdict=VERDICT_GUILTY) + OffenseRecordFactory( + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) + OffenseRecordFactory( + offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) - assert(offense.is_convicted_of_charged()) + assert offense.is_convicted_of_charged() def test_offense__is_convicted_of_charged__different_descriptions(): """ Test is_convicted_of_charged in Offense. Should return false because descriptions are different. """ - offense = OffenseFactory(verdict = VERDICT_GUILTY) - OffenseRecordFactory(offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") - OffenseRecordFactory(offense=offense, action=CONVICTED, description="COMMUNICATING THREATS", severity="MISDEMEANOR") + offense = OffenseFactory(verdict=VERDICT_GUILTY) + OffenseRecordFactory( + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) + OffenseRecordFactory( + offense=offense, + action=CONVICTED, + description="COMMUNICATING THREATS", + severity="MISDEMEANOR", + ) - assert(not offense.is_convicted_of_charged()) + assert not offense.is_convicted_of_charged() def test_offense__is_convicted_of_charged__different_severities(): """ Test is_convicted_of_charged in Offense. Should return false because severities are different. """ - offense = OffenseFactory(verdict = VERDICT_GUILTY) - OffenseRecordFactory(offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY") - OffenseRecordFactory(offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") + offense = OffenseFactory(verdict=VERDICT_GUILTY) + OffenseRecordFactory( + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY" + ) + OffenseRecordFactory( + offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) - assert(not offense.is_convicted_of_charged()) + assert not offense.is_convicted_of_charged() def test_offense__is_convicted_of_charged__not_guilty(): """ Test is_convicted_of_charged in Offense. Should return false because verdict is not GUILTY. """ - offense = OffenseFactory(verdict = "NOT GUILTY") - OffenseRecordFactory(offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") + offense = OffenseFactory(verdict="NOT GUILTY") + OffenseRecordFactory( + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) - assert(not offense.is_convicted_of_charged()) + assert not offense.is_convicted_of_charged() def test_offense__is_guilty_to_lesser__different_descriptions(): @@ -271,10 +305,17 @@ def test_offense__is_guilty_to_lesser__different_descriptions(): Test is_guilty_to_lesser in Offense. Should return true because descriptions are different. """ offense = OffenseFactory(verdict=VERDICT_GUILTY) - OffenseRecordFactory(offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") - OffenseRecordFactory(offense=offense, action=CONVICTED, description="COMMUNICATING THREATS", severity="MISDEMEANOR") + OffenseRecordFactory( + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) + OffenseRecordFactory( + offense=offense, + action=CONVICTED, + description="COMMUNICATING THREATS", + severity="MISDEMEANOR", + ) - assert(offense.is_guilty_to_lesser()) + assert offense.is_guilty_to_lesser() def test_offense__is_guilty_to_lesser__different_severities(): @@ -282,10 +323,14 @@ def test_offense__is_guilty_to_lesser__different_severities(): Test is_guilty_to_lesser in Offense. Should return true because severities are different. """ offense = OffenseFactory(verdict=VERDICT_GUILTY) - OffenseRecordFactory(offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY") - OffenseRecordFactory(offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") + OffenseRecordFactory( + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY" + ) + OffenseRecordFactory( + offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) - assert(offense.is_guilty_to_lesser()) + assert offense.is_guilty_to_lesser() def test_offense__is_guilty_to_lesser__equivalent_offenses(): @@ -293,10 +338,14 @@ def test_offense__is_guilty_to_lesser__equivalent_offenses(): Test is_guilty_to_lesser in Offense. Should return false because offenses are equivalent. """ offense = OffenseFactory(verdict=VERDICT_GUILTY) - OffenseRecordFactory(offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") - OffenseRecordFactory(offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") + OffenseRecordFactory( + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) + OffenseRecordFactory( + offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) - assert(not offense.is_guilty_to_lesser()) + assert not offense.is_guilty_to_lesser() def test_offense__is_guilty_to_lesser__not_guilty(): @@ -304,51 +353,72 @@ def test_offense__is_guilty_to_lesser__not_guilty(): Test is_guilty_to_lesser in Offense. Should return false because verdict is not GUILTY. """ offense = OffenseFactory(verdict="NOT GUILTY") - OffenseRecordFactory(offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") + OffenseRecordFactory( + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) - assert(not offense.is_guilty_to_lesser()) + assert not offense.is_guilty_to_lesser() def test_offense__has_equivalent_offense_records__equivalent(offense1): """ Test has_equivalent_offense_records in Offense. Should return true. """ - OffenseRecordFactory(offense=offense1, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") - OffenseRecordFactory(offense=offense1, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") + OffenseRecordFactory( + offense=offense1, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) + OffenseRecordFactory( + offense=offense1, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) - assert(offense1.has_equivalent_offense_records()) + assert offense1.has_equivalent_offense_records() def test_offense__has_equivalent_offense_records__different_descriptions(offense1): """ Test has_equivalent_offense_records in Offense. Should return false because descriptions are different. """ - OffenseRecordFactory(offense=offense1, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") - OffenseRecordFactory(offense=offense1, action=CONVICTED, description="COMMUNICATING THREATS", severity="MISDEMEANOR") + OffenseRecordFactory( + offense=offense1, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) + OffenseRecordFactory( + offense=offense1, + action=CONVICTED, + description="COMMUNICATING THREATS", + severity="MISDEMEANOR", + ) - assert(not offense1.has_equivalent_offense_records()) + assert not offense1.has_equivalent_offense_records() def test_offense__has_equivalent_offense_records__different_severities(offense1): """ Test has_equivalent_offense_records in Offense. Should return false because severities are different. """ - OffenseRecordFactory(offense=offense1, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY") - OffenseRecordFactory(offense=offense1, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR") + OffenseRecordFactory( + offense=offense1, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY" + ) + OffenseRecordFactory( + offense=offense1, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" + ) - assert(not offense1.has_equivalent_offense_records()) + assert not offense1.has_equivalent_offense_records() def test_offense__has_equivalent_offense_records__one_offense_record(offense1): """ Test has_equivalent_offense_records in Offense. Should return false because there is only one offense record. """ - OffenseRecordFactory(offense=offense1, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY") + OffenseRecordFactory( + offense=offense1, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY" + ) - assert(not offense1.has_equivalent_offense_records()) + assert not offense1.has_equivalent_offense_records() -@pytest.mark.parametrize("verdict", [VERDICT_GUILTY, VERDICT_PRAYER_FOR_JUDGMENT, VERDICT_RESPONSIBLE]) +@pytest.mark.parametrize( + "verdict", [VERDICT_GUILTY, VERDICT_PRAYER_FOR_JUDGMENT, VERDICT_RESPONSIBLE] +) def test_offense__is_visible__equivalent(verdict): """ Test is_visible in Offense when the verdict is GUILTY, RESPONSIBLE, or PRAYER FOR JUDGMENT and the offense records @@ -356,23 +426,19 @@ def test_offense__is_visible__equivalent(verdict): """ offense = OffenseFactory(verdict=verdict) offense_record_charged = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) offense_record_convicted = OffenseRecordFactory( - offense=offense, - action=CONVICTED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) assert not offense_record_charged.is_visible assert offense_record_convicted.is_visible -@pytest.mark.parametrize("verdict", [VERDICT_GUILTY, VERDICT_PRAYER_FOR_JUDGMENT, VERDICT_RESPONSIBLE]) +@pytest.mark.parametrize( + "verdict", [VERDICT_GUILTY, VERDICT_PRAYER_FOR_JUDGMENT, VERDICT_RESPONSIBLE] +) def test_offense__is_visible__not_equivalent_description(verdict): """ Test is_visible in Offense when the verdict is GUILTY, RESPONSIBLE, or PRAYER FOR JUDGMENT and the offense records @@ -380,23 +446,22 @@ def test_offense__is_visible__not_equivalent_description(verdict): """ offense = OffenseFactory(verdict=verdict) offense_record_charged = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) offense_record_convicted = OffenseRecordFactory( offense=offense, action=CONVICTED, description="COMMUNICATING THREATS", - severity="MISDEMEANOR" + severity="MISDEMEANOR", ) assert offense_record_charged.is_visible assert offense_record_convicted.is_visible -@pytest.mark.parametrize("verdict", [VERDICT_GUILTY, VERDICT_PRAYER_FOR_JUDGMENT, VERDICT_RESPONSIBLE]) +@pytest.mark.parametrize( + "verdict", [VERDICT_GUILTY, VERDICT_PRAYER_FOR_JUDGMENT, VERDICT_RESPONSIBLE] +) def test_offense__is_visible__not_equivalent_severity(verdict): """ Test is_visible in Offense when the verdict is GUILTY, RESPONSIBLE, or PRAYER FOR JUDGMENT and the offense records @@ -404,23 +469,19 @@ def test_offense__is_visible__not_equivalent_severity(verdict): """ offense = OffenseFactory(verdict=verdict) offense_record_charged = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="FELONY" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="FELONY" ) offense_record_convicted = OffenseRecordFactory( - offense=offense, - action=CONVICTED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) assert offense_record_charged.is_visible assert offense_record_convicted.is_visible -@pytest.mark.parametrize("verdict", [VERDICT_GUILTY, VERDICT_PRAYER_FOR_JUDGMENT, VERDICT_RESPONSIBLE]) +@pytest.mark.parametrize( + "verdict", [VERDICT_GUILTY, VERDICT_PRAYER_FOR_JUDGMENT, VERDICT_RESPONSIBLE] +) def test_offense__is_visible__one_offense_record(verdict): """ Test is_visible in Offense when the verdict is GUILTY, RESPONSIBLE, or PRAYER FOR JUDGMENT and there is only one @@ -428,10 +489,7 @@ def test_offense__is_visible__one_offense_record(verdict): """ offense = OffenseFactory(verdict=verdict) offense_record = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) assert offense_record.is_visible @@ -444,39 +502,29 @@ def test_offense__is_visible__not_convicted(): """ offense = OffenseFactory(verdict="JUDGMENT ARRESTED") offense_record_charged = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) offense_record_convicted = OffenseRecordFactory( - offense=offense, - action=CONVICTED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) assert offense_record_charged.is_visible assert offense_record_convicted.is_visible -@pytest.mark.parametrize("disp_method", [DISP_METHOD_SUPERSEDING_INDICTMENT, DISP_METHOD_WAIVER_OF_PROBABLE_CAUSE]) +@pytest.mark.parametrize( + "disp_method", [DISP_METHOD_SUPERSEDING_INDICTMENT, DISP_METHOD_WAIVER_OF_PROBABLE_CAUSE] +) def test_offense__is_visible__excluded_disp_method(disp_method): """ Test is_visible in Offense when the disposition method is excluded. No offense records should be visible. """ offense = OffenseFactory(verdict=VERDICT_GUILTY, disposition_method=disp_method) offense_record_charged = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) offense_record_convicted = OffenseRecordFactory( - offense=offense, - action=CONVICTED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CONVICTED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) assert not offense_record_charged.is_visible @@ -492,24 +540,20 @@ def test_offense_record__is_visible__yes_has_de_novo(batch, record1): ciprs_record=record1, jurisdiction=DISTRICT_COURT, verdict=VERDICT_GUILTY, - disposition_method="JURY TRIAL" + disposition_method="JURY TRIAL", ) offense_record_district = OffenseRecordFactory( - offense=offense_district, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense_district, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) offense_superior = OffenseFactory( ciprs_record=record1, jurisdiction=SUPERIOR_COURT, verdict=VERDICT_PRAYER_FOR_JUDGMENT, - disposition_method="JURY TRIAL" + disposition_method="JURY TRIAL", ) offense_record_superior = OffenseRecordFactory( - offense=offense_superior, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense_superior, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) assert not offense_record_district.is_visible @@ -520,21 +564,34 @@ def test_offense_record__is_visible__yes_has_de_novo(batch, record1): "verdict_d, description_d, severity_d, verdict_s, description_s, severity_s ", [ ( - VERDICT_PRAYER_FOR_JUDGMENT, "SIMPLE ASSAULT", "MISDEMEANOR", - VERDICT_GUILTY, "SIMPLE ASSAULT", "MISDEMEANOR" + VERDICT_PRAYER_FOR_JUDGMENT, + "SIMPLE ASSAULT", + "MISDEMEANOR", + VERDICT_GUILTY, + "SIMPLE ASSAULT", + "MISDEMEANOR", ), ( - VERDICT_GUILTY, "SIMPLE ASSAULT", "MISDEMEANOR", - VERDICT_PRAYER_FOR_JUDGMENT, "NOT SIMPLE ASSAULT", "MISDEMEANOR" + VERDICT_GUILTY, + "SIMPLE ASSAULT", + "MISDEMEANOR", + VERDICT_PRAYER_FOR_JUDGMENT, + "NOT SIMPLE ASSAULT", + "MISDEMEANOR", ), ( - VERDICT_GUILTY, "SIMPLE ASSAULT", "MISDEMEANOR", - VERDICT_PRAYER_FOR_JUDGMENT, "SIMPLE ASSAULT", "NOT MISDEMEANOR" + VERDICT_GUILTY, + "SIMPLE ASSAULT", + "MISDEMEANOR", + VERDICT_PRAYER_FOR_JUDGMENT, + "SIMPLE ASSAULT", + "NOT MISDEMEANOR", ), - ] + ], ) def test_offense_record__is_visible__no_has_de_novo( - batch, record1, verdict_d, description_d, severity_d, verdict_s, description_s, severity_s): + batch, record1, verdict_d, description_d, severity_d, verdict_s, description_s, severity_s +): """ Test is_visible in OffenseRecord when there is no de novo review. There is no de novo review when 1) it is not a guilty district court offense or 2) when there is no matching (description and severity) offense record in superior @@ -547,9 +604,7 @@ def test_offense_record__is_visible__no_has_de_novo( disposition_method="JURY TRIAL", ) offense_record_district = OffenseRecordFactory( - offense=offense_district, - description=description_d, - severity=severity_d + offense=offense_district, description=description_d, severity=severity_d ) offense_superior = OffenseFactory( @@ -559,9 +614,7 @@ def test_offense_record__is_visible__no_has_de_novo( disposition_method="JURY TRIAL", ) offense_record_superior = OffenseRecordFactory( - offense=offense_superior, - description=description_s, - severity=severity_s + offense=offense_superior, description=description_s, severity=severity_s ) assert offense_record_district.is_visible @@ -575,10 +628,7 @@ def test_offense__disposition__no_verdict(): """ offense = OffenseFactory(disposition_method="NO PROBABLE CAUSE", verdict="") offense_record = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) assert offense_record.disposition == "NO PROBABLE CAUSE" @@ -591,10 +641,7 @@ def test_offense__disposition__verdict(): """ offense = OffenseFactory(disposition_method="NO PROBABLE CAUSE", verdict="JUDGMENT ARRESTED") offense_record = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) assert offense_record.disposition == "JUDGMENT ARRESTED" @@ -607,16 +654,13 @@ def test_offense__disposition__guilty_to_lesser(): """ offense = OffenseFactory(disposition_method="DISPOSED BY JUDGE", verdict=VERDICT_GUILTY) offense_record_charged = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) offense_record_convicted = OffenseRecordFactory( offense=offense, action=CONVICTED, description="COMMUNICATING THREATS", - severity="MISDEMEANOR" + severity="MISDEMEANOR", ) assert offense_record_charged.disposition == VERDICT_GUILTY_TO_LESSER @@ -630,16 +674,13 @@ def test_offense__disposition__responsible_to_lesser(): """ offense = OffenseFactory(disposition_method="DISPOSED BY JUDGE", verdict=VERDICT_RESPONSIBLE) offense_record_charged = OffenseRecordFactory( - offense=offense, - action=CHARGED, - description="SIMPLE ASSAULT", - severity="MISDEMEANOR" + offense=offense, action=CHARGED, description="SIMPLE ASSAULT", severity="MISDEMEANOR" ) offense_record_convicted = OffenseRecordFactory( offense=offense, action=CONVICTED, description="COMMUNICATING THREATS", - severity="MISDEMEANOR" + severity="MISDEMEANOR", ) assert offense_record_charged.disposition == VERDICT_RESPONSIBLE_TO_LESSER diff --git a/dear_petition/petition/tests/test_resources.py b/dear_petition/petition/tests/test_resources.py index e28b16bd..c5092061 100644 --- a/dear_petition/petition/tests/test_resources.py +++ b/dear_petition/petition/tests/test_resources.py @@ -5,13 +5,28 @@ pytestmark = pytest.mark.django_db -@pytest.mark.parametrize("full_address, expected_result", [ - ('123 Test St.\nWashington, NC 27889', ('123 Test St.', None, 'Washington', 'NC', '27889')), - ('90 Elk Mountain Road\nAsheville, NC 28804', ('90 Elk Mountain Road', None, 'Asheville', 'NC', '28804')), - ('16 Fernihurst Drive\nAsheville NC 28801', ('16 Fernihurst Drive', None, 'Asheville', 'NC', '28801')), - ('P.O. Box 31\n110 N. Church Street # 2\nHertford, NC 27944', ('P.O. Box 31', '110 N. Church Street # 2', 'Hertford', 'NC', '27944')), - ('450 W. Hanes Mill Road\nWinston-Salem, NC 27894-1666', ('450 W. Hanes Mill Road', None, 'Winston-Salem', 'NC', '27894-1666')), -]) +@pytest.mark.parametrize( + "full_address, expected_result", + [ + ("123 Test St.\nWashington, NC 27889", ("123 Test St.", None, "Washington", "NC", "27889")), + ( + "90 Elk Mountain Road\nAsheville, NC 28804", + ("90 Elk Mountain Road", None, "Asheville", "NC", "28804"), + ), + ( + "16 Fernihurst Drive\nAsheville NC 28801", + ("16 Fernihurst Drive", None, "Asheville", "NC", "28801"), + ), + ( + "P.O. Box 31\n110 N. Church Street # 2\nHertford, NC 27944", + ("P.O. Box 31", "110 N. Church Street # 2", "Hertford", "NC", "27944"), + ), + ( + "450 W. Hanes Mill Road\nWinston-Salem, NC 27894-1666", + ("450 W. Hanes Mill Road", None, "Winston-Salem", "NC", "27894-1666"), + ), + ], +) def test_parse_agency_full_address(full_address, expected_result): parsed_address = parse_agency_full_address(full_address) assert parsed_address == expected_result @@ -30,14 +45,13 @@ def test_record_summary_resource(batch, record1, client, dismissed_offense): client_worksheet = dataset.wb.worksheets[0] record_worksheet = dataset.wb.worksheets[1] - assert client_worksheet.title == 'Client Information' - assert client_worksheet['B1'].value == "Name" - assert client_worksheet['B2'].value == "Test Client" + assert client_worksheet.title == "Client Information" + assert client_worksheet["B1"].value == "Name" + assert client_worksheet["B2"].value == "Test Client" assert record_worksheet.title == "99CRAAAAAAAAAAAA" - assert record_worksheet['A1'].value == 'Defendent Name' - assert record_worksheet['A2'].value == 'Test Record' - assert record_worksheet['B1'].value == 'File No' - assert record_worksheet['B2'].value == '99CRAAAAAAAAAAAA' - assert record_worksheet['C1'].value == 'Date Of Birth' - assert record_worksheet['C2'].value == '1980-07-07' - + assert record_worksheet["A1"].value == "Defendent Name" + assert record_worksheet["A2"].value == "Test Record" + assert record_worksheet["B1"].value == "File No" + assert record_worksheet["B2"].value == "99CRAAAAAAAAAAAA" + assert record_worksheet["C1"].value == "Date Of Birth" + assert record_worksheet["C2"].value == "1980-07-07" diff --git a/dear_petition/petition/tests/test_utils.py b/dear_petition/petition/tests/test_utils.py index e86b88c7..75441bcd 100644 --- a/dear_petition/petition/tests/test_utils.py +++ b/dear_petition/petition/tests/test_utils.py @@ -11,8 +11,7 @@ def test_dt_obj_to_date(settings): - """Should receive only datetime objects to be converted into dates - """ + """Should receive only datetime objects to be converted into dates""" # Set the TIME_ZONE in the settings. settings.TIME_ZONE = "America/New_York" @@ -29,12 +28,8 @@ def test_dt_obj_to_date(settings): ) # Calling pu.dt_obj_to_date() returns the date at each of these moments in the # "America/New_York" timezone, which was "2018-01-01". - assert pu.dt_obj_to_date(datetime_2018_01_01_2000_ny) == date( - year=2018, month=1, day=1 - ) - assert pu.dt_obj_to_date(datetime_2018_01_02_0100_utc) == date( - year=2018, month=1, day=1 - ) + assert pu.dt_obj_to_date(datetime_2018_01_01_2000_ny) == date(year=2018, month=1, day=1) + assert pu.dt_obj_to_date(datetime_2018_01_02_0100_utc) == date(year=2018, month=1, day=1) # Calling pu.dt_obj_to_date() for non datetime objects returns None. dt_obj = "A random string." @@ -52,8 +47,7 @@ def test_dt_obj_to_date(settings): def test_make_datetime_aware(settings): - """Aware Datetime should be returned unless dt_str is empty ("" or None) - """ + """Aware Datetime should be returned unless dt_str is empty ("" or None)""" # Set the TIME_ZONE in the settings. settings.TIME_ZONE = "America/New_York" @@ -89,7 +83,7 @@ def test_make_datetime_aware_ambiguous(settings): expected_datetime_obj = make_aware( datetime(year=2011, month=11, day=6, hour=1, minute=46, second=0), timezone=pytz.timezone("America/New_York"), - is_dst=False + is_dst=False, ) assert pu.make_datetime_aware(naive_datetime_str) == expected_datetime_obj @@ -118,8 +112,12 @@ def test_get_truncation_point_of_short_text_by_pixel_size(): truncation_point = pu.get_truncation_point_of_text_by_pixel_size(text, 20000) assert truncation_point == len(text) + def test_get_petition_filename(petition): petition.created = datetime(2024, 7, 28, 0, 0) petition.save() petitioner_name = "Test" - assert pu.get_petition_filename(petitioner_name, petition, 'pdf') == '07-28-2024 DURHAM DC 146(a) Test.pdf' \ No newline at end of file + assert ( + pu.get_petition_filename(petitioner_name, petition, "pdf") + == "07-28-2024 DURHAM DC 146(a) Test.pdf" + ) diff --git a/dear_petition/petition/types/addendum.py b/dear_petition/petition/types/addendum.py index 9493ae23..45330110 100644 --- a/dear_petition/petition/types/addendum.py +++ b/dear_petition/petition/types/addendum.py @@ -9,6 +9,7 @@ def create_addendum_documents(petition, previous_document): addendum_document_creator = ADDENDUM_FORMS_TYPE_MAP[petition.form_type] addendum_document_creator(petition, previous_document) + def calculate_offense_record_string(offense_record): offense_record_string = f"{offense_record.file_no} {offense_record.description}" @@ -17,10 +18,10 @@ def calculate_offense_record_string(offense_record): return offense_record_string + def calculate_checkmark_3b_string(offense_records): offense_record_strings = [ - calculate_offense_record_string(offense_record) - for offense_record in offense_records + calculate_offense_record_string(offense_record) for offense_record in offense_records ] checkmark_3b_string = ", ".join(offense_record_strings) return checkmark_3b_string @@ -29,9 +30,7 @@ def calculate_checkmark_3b_string(offense_records): def create_checkmark_3b_addendum_form(petition, previous_document): ADDENDUM_3B_FIRST_LINE_LIMIT = 242 ADDENDUM_3B_SECOND_LINE_LIMIT = 410 - ADDENDUM_3B_PIXEL_LIMIT = ( - ADDENDUM_3B_FIRST_LINE_LIMIT + ADDENDUM_3B_SECOND_LINE_LIMIT - ) + ADDENDUM_3B_PIXEL_LIMIT = ADDENDUM_3B_FIRST_LINE_LIMIT + ADDENDUM_3B_SECOND_LINE_LIMIT qs = addendum_3b.get_offense_records(petition) if not qs.exists(): petition.base_document.form_specific_data["is_checkmark_3b_checked"] = False @@ -46,17 +45,15 @@ def create_checkmark_3b_addendum_form(petition, previous_document): ) addendum_3b_document.offense_records.add(*qs) petition.base_document.form_specific_data["is_checkmark_3b_checked"] = True - petition.base_document.form_specific_data[ - "charged_desc_string" - ] = "See addendum" + petition.base_document.form_specific_data["charged_desc_string"] = "See addendum" else: petition.base_document.form_specific_data["is_checkmark_3b_checked"] = True truncation_point = pu.get_truncation_point_of_text_by_pixel_size( checkmark_3b_string, ADDENDUM_3B_FIRST_LINE_LIMIT ) - petition.base_document.form_specific_data[ - "charged_desc_string" - ] = checkmark_3b_string[0:truncation_point] + petition.base_document.form_specific_data["charged_desc_string"] = checkmark_3b_string[ + 0:truncation_point + ] petition.base_document.form_specific_data[ "charged_desc_cont_string" ] = checkmark_3b_string[truncation_point:] diff --git a/dear_petition/petition/types/adult_felonies.py b/dear_petition/petition/types/adult_felonies.py index 59ad2741..928c633e 100644 --- a/dear_petition/petition/types/adult_felonies.py +++ b/dear_petition/petition/types/adult_felonies.py @@ -34,4 +34,3 @@ def build_query(): adult_felony_portal = methods & severity & waiting_period return adult_felony_ciprs | adult_felony_portal - diff --git a/dear_petition/petition/types/dismissed.py b/dear_petition/petition/types/dismissed.py index f3403c4d..738ecff2 100644 --- a/dear_petition/petition/types/dismissed.py +++ b/dear_petition/petition/types/dismissed.py @@ -1,7 +1,10 @@ from django.db.models import Q from dear_petition.petition.models import OffenseRecord -from dear_petition.petition.constants import CIPRS_DISPOSITION_METHODS_DISMISSED, PORTAL_DISPOSITION_METHODS_DISMISSED +from dear_petition.petition.constants import ( + CIPRS_DISPOSITION_METHODS_DISMISSED, + PORTAL_DISPOSITION_METHODS_DISMISSED, +) def get_offense_records(batch, jurisdiction=""): @@ -14,7 +17,7 @@ def get_offense_records(batch, jurisdiction=""): def build_query(): action = Q(action="CHARGED") - + methods_ciprs = Q() for method in CIPRS_DISPOSITION_METHODS_DISMISSED: methods_ciprs |= Q(offense__disposition_method__iexact=method) diff --git a/dear_petition/petition/types/tests/test_addendum.py b/dear_petition/petition/types/tests/test_addendum.py index 45047e64..5eb2db5d 100644 --- a/dear_petition/petition/types/tests/test_addendum.py +++ b/dear_petition/petition/types/tests/test_addendum.py @@ -9,9 +9,7 @@ def test_calculate_checkmark_3b_string(offense_record1, offense_record2): - checkmark_3b_string = addendum.calculate_checkmark_3b_string( - [offense_record1, offense_record2] - ) + checkmark_3b_string = addendum.calculate_checkmark_3b_string([offense_record1, offense_record2]) assert ( checkmark_3b_string == f"{offense_record1.file_no} {offense_record1.description}, {offense_record2.file_no} {offense_record2.description}" @@ -62,7 +60,4 @@ def test_create_checkmark_3b_addendum_form_with_too_many_records( ).update(active=False) addendum.create_checkmark_3b_addendum_form(petition, petition_document) assert petition.base_document.form_specific_data["is_checkmark_3b_checked"] - assert ( - petition.base_document.form_specific_data["charged_desc_string"] - == "See addendum" - ) + assert petition.base_document.form_specific_data["charged_desc_string"] == "See addendum" diff --git a/dear_petition/petition/types/tests/test_adult_felonies.py b/dear_petition/petition/types/tests/test_adult_felonies.py index e81e780f..f356ddac 100644 --- a/dear_petition/petition/types/tests/test_adult_felonies.py +++ b/dear_petition/petition/types/tests/test_adult_felonies.py @@ -9,20 +9,59 @@ @pytest.mark.parametrize( - "action, disposition_method, severity, date, should_be_included", [ + "action, disposition_method, severity, date, should_be_included", + [ # records that have data as they would from Portal (no action) ("", "District Guilty - Judge", SEVERITIES.FELONY, datetime(2014, 8, 1), True), - ("", "District Not Guilty - Judge", SEVERITIES.FELONY, datetime(2014, 8, 1), False), # exclude because not Portal guilty disposition method - ("", "District Guilty - Judge", SEVERITIES.MISDEMEANOR, datetime(2014, 8, 1), False), # exclude because misdemeanor severity - ("", "District Guilty - Judge", SEVERITIES.FELONY, datetime(2024, 8, 1), False), # exclude because too recent + ( + "", + "District Not Guilty - Judge", + SEVERITIES.FELONY, + datetime(2014, 8, 1), + False, + ), # exclude because not Portal guilty disposition method + ( + "", + "District Guilty - Judge", + SEVERITIES.MISDEMEANOR, + datetime(2014, 8, 1), + False, + ), # exclude because misdemeanor severity + ( + "", + "District Guilty - Judge", + SEVERITIES.FELONY, + datetime(2024, 8, 1), + False, + ), # exclude because too recent # records that have data as they would from CIPRS (disposition_method not one seen in Portal) (CONVICTED, "Disposed By Judge", SEVERITIES.FELONY, datetime(2014, 8, 1), True), - (CHARGED, "Disposed By Judge", SEVERITIES.FELONY, datetime(2014, 8, 1), False), # exclude because not convicted action - (CONVICTED, "Disposed By Judge", SEVERITIES.MISDEMEANOR, datetime(2014, 8, 1), False), # exclude because misdemeanor severity - (CONVICTED, "Disposed By Judge", SEVERITIES.FELONY, datetime(2024, 8, 1), False), # exclude because too recent - ] + ( + CHARGED, + "Disposed By Judge", + SEVERITIES.FELONY, + datetime(2014, 8, 1), + False, + ), # exclude because not convicted action + ( + CONVICTED, + "Disposed By Judge", + SEVERITIES.MISDEMEANOR, + datetime(2014, 8, 1), + False, + ), # exclude because misdemeanor severity + ( + CONVICTED, + "Disposed By Judge", + SEVERITIES.FELONY, + datetime(2024, 8, 1), + False, + ), # exclude because too recent + ], ) -def test_adult_felonies(action, disposition_method, severity, date, should_be_included, batch, record1): +def test_adult_felonies( + action, disposition_method, severity, date, should_be_included, batch, record1 +): offense = Offense.objects.create( ciprs_record=record1, disposition_method=disposition_method, diff --git a/dear_petition/petition/types/tests/test_adult_misdemeanors.py b/dear_petition/petition/types/tests/test_adult_misdemeanors.py index a22a2d3b..29538c7f 100644 --- a/dear_petition/petition/types/tests/test_adult_misdemeanors.py +++ b/dear_petition/petition/types/tests/test_adult_misdemeanors.py @@ -9,20 +9,59 @@ @pytest.mark.parametrize( - "action, disposition_method, severity, date, should_be_included", [ + "action, disposition_method, severity, date, should_be_included", + [ # records that have data as they would from Portal (no action) ("", "District Guilty - Judge", SEVERITIES.MISDEMEANOR, datetime(2019, 8, 1), True), - ("", "District Not Guilty - Judge", SEVERITIES.MISDEMEANOR, datetime(2019, 8, 1), False), # exclude because not Portal guilty disposition method - ("", "District Guilty - Judge", SEVERITIES.FELONY, datetime(2019, 8, 1), False), # exclude because felony severity - ("", "District Guilty - Judge", SEVERITIES.MISDEMEANOR, datetime(2024, 8, 1), False), # exclude because too recent + ( + "", + "District Not Guilty - Judge", + SEVERITIES.MISDEMEANOR, + datetime(2019, 8, 1), + False, + ), # exclude because not Portal guilty disposition method + ( + "", + "District Guilty - Judge", + SEVERITIES.FELONY, + datetime(2019, 8, 1), + False, + ), # exclude because felony severity + ( + "", + "District Guilty - Judge", + SEVERITIES.MISDEMEANOR, + datetime(2024, 8, 1), + False, + ), # exclude because too recent # records that have data as they would from CIPRS (disposition_method not one seen in Portal) (CONVICTED, "Disposed By Judge", SEVERITIES.MISDEMEANOR, datetime(2019, 8, 1), True), - (CHARGED, "Disposed By Judge", SEVERITIES.MISDEMEANOR, datetime(2019, 8, 1), False), # exclude because not convicted action - (CONVICTED, "Disposed By Judge", SEVERITIES.FELONY, datetime(2019, 8, 1), False), # exclude because felony severity - (CONVICTED, "Disposed By Judge", SEVERITIES.MISDEMEANOR, datetime(2024, 8, 1), False), # exclude because too recent - ] + ( + CHARGED, + "Disposed By Judge", + SEVERITIES.MISDEMEANOR, + datetime(2019, 8, 1), + False, + ), # exclude because not convicted action + ( + CONVICTED, + "Disposed By Judge", + SEVERITIES.FELONY, + datetime(2019, 8, 1), + False, + ), # exclude because felony severity + ( + CONVICTED, + "Disposed By Judge", + SEVERITIES.MISDEMEANOR, + datetime(2024, 8, 1), + False, + ), # exclude because too recent + ], ) -def test_adult_misdemeanors(action, disposition_method, severity, date, should_be_included, batch, record1): +def test_adult_misdemeanors( + action, disposition_method, severity, date, should_be_included, batch, record1 +): offense = Offense.objects.create( ciprs_record=record1, disposition_method=disposition_method, diff --git a/dear_petition/petition/types/tests/test_dismissed.py b/dear_petition/petition/types/tests/test_dismissed.py index 5784187c..a3a3d24e 100644 --- a/dear_petition/petition/types/tests/test_dismissed.py +++ b/dear_petition/petition/types/tests/test_dismissed.py @@ -14,15 +14,24 @@ @pytest.mark.parametrize( - "action, disposition_method, should_be_included", [ + "action, disposition_method, should_be_included", + [ # records that have data as they would from Portal (no action) ("", "No Probable Cause Found", True), - ("", "District Guilty - Judge", False), # exclude because not Portal dismissed disposition method + ( + "", + "District Guilty - Judge", + False, + ), # exclude because not Portal dismissed disposition method # records that have data as they would from CIPRS (disposition_method not one seen in Portal) (CHARGED, "No Probable Cause", True), (CONVICTED, "No Probable Cause", False), # exclude because not charged action - (CHARGED, "Disposed By Judge", False), # exclude because not CIPRS dismissed disposition method - ] + ( + CHARGED, + "Disposed By Judge", + False, + ), # exclude because not CIPRS dismissed disposition method + ], ) def test_dismissed(action, disposition_method, should_be_included, batch, record1): offense = Offense.objects.create( @@ -52,9 +61,7 @@ def test_infraction_severity_offense_record(batch, dismissed_offense): assert traffic_record in batch.dismissed_offense_records() -@pytest.mark.parametrize( - "jurisdiction", [constants.DISTRICT_COURT, constants.SUPERIOR_COURT] -) +@pytest.mark.parametrize("jurisdiction", [constants.DISTRICT_COURT, constants.SUPERIOR_COURT]) def test_offense_records_by_jurisdiction(batch, jurisdiction): """Offense records helper function should allow filtering by jurisdiction.""" ciprs_record = CIPRSRecordFactory(jurisdiction=jurisdiction, batch=batch) diff --git a/dear_petition/petition/types/tests/test_distinct_petitions.py b/dear_petition/petition/types/tests/test_distinct_petitions.py index e316bef1..8f29bae6 100644 --- a/dear_petition/petition/types/tests/test_distinct_petitions.py +++ b/dear_petition/petition/types/tests/test_distinct_petitions.py @@ -27,9 +27,7 @@ def test_distinct_petition__many(batch): method = constants.CIPRS_DISPOSITION_METHODS_DISMISSED[0] for jurisdiction in [constants.DISTRICT_COURT, constants.SUPERIOR_COURT]: for county in ["DURHAM", "WAKE"]: - record = CIPRSRecordFactory( - jurisdiction=jurisdiction, county=county, batch=batch - ) + record = CIPRSRecordFactory(jurisdiction=jurisdiction, county=county, batch=batch) offense = OffenseFactory(disposition_method=method, ciprs_record=record) OffenseRecordFactory(action="CHARGED", offense=offense) petition_types = identify_distinct_petitions(batch.dismissed_offense_records()) diff --git a/dear_petition/petition/types/tests/test_not_guilty.py b/dear_petition/petition/types/tests/test_not_guilty.py index 9fb30256..11eb1d5e 100644 --- a/dear_petition/petition/types/tests/test_not_guilty.py +++ b/dear_petition/petition/types/tests/test_not_guilty.py @@ -12,16 +12,37 @@ @pytest.mark.parametrize( - "action, verdict, disposition_method, should_be_included", [ + "action, verdict, disposition_method, should_be_included", + [ # records that have data as they would from Portal (no action or verdict) ("", "", "District Not Guilty - Judge", True), - ("", "", "District Guilty - Judge", False), # exclude because not Portal not-guilty disposition method + ( + "", + "", + "District Guilty - Judge", + False, + ), # exclude because not Portal not-guilty disposition method # records that have data as they would from CIPRS (disposition_method not one seen in Portal) (CHARGED, VERDICT_NOT_GUILTY, "Disposed By Judge", True), - (CONVICTED, VERDICT_NOT_GUILTY, "Disposed By Judge", False), # exclude because not charged action - (CHARGED, VERDICT_GUILTY, "Disposed By Judge", False), # exclude because not not-guilty verdict - (CHARGED, VERDICT_NOT_GUILTY, "Dismissed by Court", False), # exclude because meets dismissed criteria - ] + ( + CONVICTED, + VERDICT_NOT_GUILTY, + "Disposed By Judge", + False, + ), # exclude because not charged action + ( + CHARGED, + VERDICT_GUILTY, + "Disposed By Judge", + False, + ), # exclude because not not-guilty verdict + ( + CHARGED, + VERDICT_NOT_GUILTY, + "Dismissed by Court", + False, + ), # exclude because meets dismissed criteria + ], ) def test_not_guilty(action, verdict, disposition_method, should_be_included, batch, record1): offense = Offense.objects.create( diff --git a/dear_petition/petition/types/tests/test_underaged_convictions.py b/dear_petition/petition/types/tests/test_underaged_convictions.py index 50485b58..2a7ae833 100644 --- a/dear_petition/petition/types/tests/test_underaged_convictions.py +++ b/dear_petition/petition/types/tests/test_underaged_convictions.py @@ -12,9 +12,7 @@ def test_no_dob_conviction_not_included(batch, record1, non_dismissed_offense): # This tests the scenario where the record has no DOB (aka Portal), nor has the user added a DOB for the client. record1.dob = None record1.save() - offense_record = OffenseRecordFactory( - action="CONVICTED", offense=non_dismissed_offense - ) + offense_record = OffenseRecordFactory(action="CONVICTED", offense=non_dismissed_offense) assert offense_record not in batch.underaged_conviction_records() @@ -22,9 +20,7 @@ def test_underaged_conviction_included(batch, record1, non_dismissed_offense): record1.dob = datetime(2000, 1, 2) record1.offense_date = datetime(2018, 1, 1) record1.save() - offense_record = OffenseRecordFactory( - action="CONVICTED", offense=non_dismissed_offense - ) + offense_record = OffenseRecordFactory(action="CONVICTED", offense=non_dismissed_offense) assert offense_record in batch.underaged_conviction_records() @@ -32,22 +28,18 @@ def test_overaged_conviction_not_included(batch, record1, non_dismissed_offense) record1.dob = datetime(2000, 1, 1) record1.offense_date = datetime(2018, 1, 1) record1.save() - offense_record = OffenseRecordFactory( - action="CONVICTED", offense=non_dismissed_offense - ) + offense_record = OffenseRecordFactory(action="CONVICTED", offense=non_dismissed_offense) assert offense_record not in batch.underaged_conviction_records() def test_underaged_conviction_using_client_dob_included(batch, record1, non_dismissed_offense): # This tests the scenario where the record has no DOB (aka Portal), but the user has included a DOB for the client - + record1.dob = None record1.offense_date = datetime(2018, 1, 1) record1.save() - offense_record = OffenseRecordFactory( - action="CONVICTED", offense=non_dismissed_offense - ) + offense_record = OffenseRecordFactory(action="CONVICTED", offense=non_dismissed_offense) batch.client.dob = datetime(2000, 1, 2) batch.client.save() @@ -55,14 +47,14 @@ def test_underaged_conviction_using_client_dob_included(batch, record1, non_dism assert offense_record in batch.underaged_conviction_records() -def test_saving_client_dob_recalculates_underaged_convictions(batch, record1, non_dismissed_offense): +def test_saving_client_dob_recalculates_underaged_convictions( + batch, record1, non_dismissed_offense +): record1.dob = None record1.offense_date = datetime(2018, 1, 1) record1.save() - offense_record = OffenseRecordFactory( - action="CONVICTED", offense=non_dismissed_offense - ) + offense_record = OffenseRecordFactory(action="CONVICTED", offense=non_dismissed_offense) batch.client.dob = datetime(2000, 1, 2) batch.client.save() @@ -73,4 +65,3 @@ def test_saving_client_dob_recalculates_underaged_convictions(batch, record1, no batch.client.save() assert offense_record not in batch.underaged_conviction_records() - diff --git a/dear_petition/petition/types/underaged_convictions.py b/dear_petition/petition/types/underaged_convictions.py index 600574b1..6fcbdaa1 100644 --- a/dear_petition/petition/types/underaged_convictions.py +++ b/dear_petition/petition/types/underaged_convictions.py @@ -14,7 +14,6 @@ def get_offense_records(batch, jurisdiction=""): - qs = OffenseRecord.objects.filter(offense__ciprs_record__batch=batch) if not qs.exists(): return qs @@ -24,7 +23,9 @@ def get_offense_records(batch, jurisdiction=""): else: dob = resolve_dob_from_offense_records(qs) if not dob: - return OffenseRecord.objects.none() # We can't determine this petition type without the date of birth + return ( + OffenseRecord.objects.none() + ) # We can't determine this petition type without the date of birth if jurisdiction: qs = qs.filter(offense__ciprs_record__jurisdiction=jurisdiction) diff --git a/dear_petition/petition/utils.py b/dear_petition/petition/utils.py index 6bbfa111..c7886fdf 100644 --- a/dear_petition/petition/utils.py +++ b/dear_petition/petition/utils.py @@ -165,11 +165,7 @@ def get_ordered_offense_records(petition_document): qs = ( petition_document.offense_records.filter(petitionoffenserecord__active=True) .select_related("offense__ciprs_record") - .annotate( - first_two_digits_file_number_chars=Substr( - "offense__ciprs_record__file_no", 1, 2 - ) - ) + .annotate(first_two_digits_file_number_chars=Substr("offense__ciprs_record__file_no", 1, 2)) .annotate( first_two_digits_file_number=Cast( "first_two_digits_file_number_chars", output_field=IntegerField() @@ -216,4 +212,4 @@ def resolve_dob_from_offense_records(qs): f"This batch has multiple birthdates. Using the earliest birthdate {earliest_dob}" ) - return earliest_dob \ No newline at end of file + return earliest_dob diff --git a/dear_petition/portal/etl/extract.py b/dear_petition/portal/etl/extract.py index eda03c26..13ab4611 100644 --- a/dear_petition/portal/etl/extract.py +++ b/dear_petition/portal/etl/extract.py @@ -29,5 +29,5 @@ def parse_party_information(soup): return PartyInfo( defendant_name=party_info.parse_defendant_name(soup), defendant_race=party_info.parse_defendant_race(soup) or "", - defendant_sex=party_info.parse_defendant_sex(soup) or "" + defendant_sex=party_info.parse_defendant_sex(soup) or "", ) diff --git a/dear_petition/portal/etl/models.py b/dear_petition/portal/etl/models.py index 351469fc..bf01a607 100644 --- a/dear_petition/portal/etl/models.py +++ b/dear_petition/portal/etl/models.py @@ -32,7 +32,7 @@ class Charge(BaseModel): @field_validator("offense_date", "filed_date", "arrest_date", mode="before") @classmethod def parse_date(cls, v): - return parse_date(v); + return parse_date(v) def transform_severity(self): """Attempt to convert Portal's degree to CIPRS severity""" @@ -53,7 +53,7 @@ class CaseInfo(BaseModel): @field_validator("case_status_date", mode="before") @classmethod def parse_date(cls, v): - return parse_date(v); + return parse_date(v) class PartyInfo(BaseModel): @@ -72,7 +72,7 @@ class Disposition(BaseModel): @field_validator("event_date", mode="before") @classmethod def parse_date(cls, v): - return parse_date(v); + return parse_date(v) def transform_disposition_method(self) -> str: return self.criminal_disposition diff --git a/dear_petition/portal/etl/parsers/case_info.py b/dear_petition/portal/etl/parsers/case_info.py index 08490f54..a1288ea9 100644 --- a/dear_petition/portal/etl/parsers/case_info.py +++ b/dear_petition/portal/etl/parsers/case_info.py @@ -23,8 +23,8 @@ def parse_case_information(soup): degree=parse_charge_degree(tr=tr) or "", offense_date=parse_charge_offense_date(tr=tr) or None, filed_date=parse_charge_filed_date(tr=tr) or None, - agency=parse_charge_agency(tr.findNext('tr')) or '', - arrest_date = parse_arrest_date(soup) or None, + agency=parse_charge_agency(tr.findNext("tr")) or "", + arrest_date=parse_arrest_date(soup) or None, ) ) ci = CaseInfo( @@ -46,9 +46,7 @@ def parse_case_type(soup):