From c3f031fcdd1993d5376ad6fe313ef5410790fc76 Mon Sep 17 00:00:00 2001 From: marekbiczysko Date: Thu, 24 Oct 2024 09:49:58 +0200 Subject: [PATCH] models changes black black migrations, drop generic foreign keys usage black fixture fix ut, migrations migrations merge fix ut migration merge fix --- src/hct_mis_api/apps/core/hope_redirect.py | 3 + .../management/commands/generatefixtures.py | 21 +- .../apps/core/management/commands/initdemo.py | 2 - src/hct_mis_api/apps/core/utils.py | 4 +- src/hct_mis_api/apps/grievance/filters.py | 4 +- src/hct_mis_api/apps/grievance/fixtures.py | 10 +- .../grievance/migrations/0074_migration.py | 62 +++ src/hct_mis_api/apps/grievance/models.py | 22 +- src/hct_mis_api/apps/grievance/schema.py | 8 +- .../services/payment_verification_services.py | 4 +- ...ticket_based_on_payment_record_services.py | 8 +- .../apps/household/fixtures/data.json | 9 - .../household/migrations/0189_migration.py | 48 ++ .../household/migrations/0190_migration.py | 23 + src/hct_mis_api/apps/household/models.py | 29 +- src/hct_mis_api/apps/payment/admin.py | 20 +- .../apps/payment/api/serializers.py | 4 +- src/hct_mis_api/apps/payment/api/views.py | 8 +- src/hct_mis_api/apps/payment/celery_tasks.py | 4 +- src/hct_mis_api/apps/payment/filters.py | 18 +- src/hct_mis_api/apps/payment/fixtures.py | 415 ++--------------- .../apps/payment/migrations/0148_migration.py | 36 ++ .../apps/payment/migrations/0149_migration.py | 213 +++++++++ .../apps/payment/migrations/0150_migration.py | 106 +++++ .../apps/payment/migrations/0151_migration.py | 45 ++ src/hct_mis_api/apps/payment/models.py | 420 ++++++++++++++---- src/hct_mis_api/apps/payment/mutations.py | 45 +- src/hct_mis_api/apps/payment/schema.py | 28 +- .../services/create_payment_verifications.py | 2 +- .../payment/services/dashboard_service.py | 17 +- .../payment/services/payment_plan_services.py | 7 +- .../verification_plan_crud_services.py | 8 +- ...erification_plan_status_change_services.py | 12 +- .../tasks/CheckRapidProVerificationTask.py | 10 +- src/hct_mis_api/apps/payment/utils.py | 34 +- ...lsx_payment_plan_export_per_fsp_service.py | 4 +- ...lsx_payment_plan_per_fsp_import_service.py | 4 +- .../xlsx/xlsx_verification_export_service.py | 10 +- .../xlsx/xlsx_verification_import_service.py | 8 +- src/hct_mis_api/apps/program/fixtures.py | 2 +- src/hct_mis_api/apps/program/schema.py | 6 +- .../services/generate_report_service.py | 12 +- src/hct_mis_api/apps/targeting/models.py | 66 +-- src/hct_mis_api/apps/targeting/mutations.py | 2 + .../services/targeting_stats_refresher.py | 1 + src/hct_mis_api/apps/targeting/validators.py | 2 +- src/hct_mis_api/apps/utils/models.py | 7 + .../create_payment_snapshot.py | 2 +- .../migrate_data_to_representations.py | 44 +- .../migrate_grievance_for_sync.py | 2 +- .../migrate_grievance_to_representations.py | 2 +- tests/selenium/filters/test_filters.py | 28 +- .../test_grievance_tickets.py | 12 +- .../test_managerial_console.py | 18 +- .../payment_module/test_payment_plans.py | 1 - .../test_payment_verification.py | 17 +- tests/selenium/people/test_people.py | 12 +- .../test_people_periodic_data_update.py | 10 +- .../program_details/test_program_details.py | 1 - tests/unit/apps/core/test_exchange_rates.py | 23 +- tests/unit/apps/core/test_hope_redirect.py | 22 +- .../test_filter_already_existing_tickets.py | 14 +- .../test_grievance_create_complaint_ticket.py | 28 +- .../test_grievance_create_sensitive_ticket.py | 56 +-- ...ance_update_payment_verification_ticket.py | 22 +- .../apps/household/test_dashboard_queries.py | 29 +- .../test_detecting_paid_hhs_loaded_via_sf.py | 8 +- .../apps/household/test_household_admin.py | 2 +- ...st_household_delivered_quantities_query.py | 13 +- .../test_household_status_endpoint.py | 6 +- .../services/test_dashboard_service.py | 24 +- .../test_action_payment_plan_mutation.py | 6 +- .../payment/test_all_payment_plan_queries.py | 15 +- .../apps/payment/test_all_payment_records.py | 28 +- .../unit/apps/payment/test_build_snapshot.py | 4 - tests/unit/apps/payment/test_build_summary.py | 30 +- ...chart_total_transferred_cash_by_country.py | 10 +- ...st_create_payment_verification_mutation.py | 22 +- .../apps/payment/test_dashboard_queries.py | 36 +- .../test_delete_verification_mutation.py | 14 +- .../test_discard_verification_mutation.py | 22 +- .../apps/payment/test_exclude_households.py | 5 +- .../test_export_xlsx_verification_mutation.py | 9 +- .../payment/test_finish_verification_plan.py | 25 +- tests/unit/apps/payment/test_fixtures.py | 2 - .../apps/payment/test_fsp_in_payment_plan.py | 12 +- ...test_fsp_xlsx_template_get_column_value.py | 8 +- ...import_export_payment_plan_payment_list.py | 7 +- .../apps/payment/test_import_verifications.py | 45 +- ...test_invalid_xlsx_verification_mutation.py | 11 +- tests/unit/apps/payment/test_models.py | 8 +- .../payment/test_payment_gateway_service.py | 5 - .../apps/payment/test_payment_notification.py | 4 +- .../test_payment_plan_pdf_export_service.py | 3 +- .../test_payment_plan_reconciliation.py | 12 +- .../payment/test_payment_plan_services.py | 31 +- .../apps/payment/test_payment_plan_views.py | 8 +- .../test_payment_token_and_order_numbers.py | 2 +- .../test_payment_verification_mutations.py | 21 +- .../test_rapid_pro_verification_task.py | 57 +-- tests/unit/apps/payment/test_sample_size.py | 16 +- ...erification_plan_status_change_services.py | 42 +- .../apps/program/test_all_programs_query.py | 2 +- .../apps/program/test_cash_plan_queries.py | 12 +- .../apps/program/test_dashboard_queries.py | 51 +-- tests/unit/apps/program/test_program_cycle.py | 8 +- .../program/test_program_cycle_rest_api.py | 2 +- .../unit/apps/program/test_update_program.py | 1 + tests/unit/apps/program/test_validators.py | 2 +- .../apps/reporting/test_report_service.py | 56 +-- .../apps/reporting/test_reporting_choices.py | 4 +- .../test_create_payment_snapshot.py | 5 - .../test_mass_withdraw_sudan_hhs.py | 2 +- .../test_migrate_data_to_representations.py | 81 +--- ...ate_data_to_representations_performance.py | 44 +- ...st_migrate_data_to_representations_unit.py | 60 +-- ...st_migrate_grievance_to_representations.py | 35 +- 117 files changed, 1655 insertions(+), 1459 deletions(-) create mode 100644 src/hct_mis_api/apps/grievance/migrations/0074_migration.py create mode 100644 src/hct_mis_api/apps/household/migrations/0189_migration.py create mode 100644 src/hct_mis_api/apps/household/migrations/0190_migration.py create mode 100644 src/hct_mis_api/apps/payment/migrations/0148_migration.py create mode 100644 src/hct_mis_api/apps/payment/migrations/0149_migration.py create mode 100644 src/hct_mis_api/apps/payment/migrations/0150_migration.py create mode 100644 src/hct_mis_api/apps/payment/migrations/0151_migration.py diff --git a/src/hct_mis_api/apps/core/hope_redirect.py b/src/hct_mis_api/apps/core/hope_redirect.py index b04661c306..e0cb6ed8e2 100644 --- a/src/hct_mis_api/apps/core/hope_redirect.py +++ b/src/hct_mis_api/apps/core/hope_redirect.py @@ -89,6 +89,7 @@ def _get_business_area_slug_from_obj(self) -> str: class HopeRedirectCashPlan(HopeRedirect): + # TODO TP what is this? def url(self) -> str: business_area_slug = self.get_business_area_slug() @@ -108,6 +109,7 @@ def _get_cash_plan(self) -> Optional[CashPlan]: class HopeRedirectPayment(HopeRedirect): + # TODO TP what is this? def url(self) -> str: business_area_slug = self.get_business_area_slug() @@ -128,6 +130,7 @@ def _get_payment_verification(self) -> Optional[PaymentVerification]: class HopeRedirectTargetPopulation(HopeRedirect): + # TODO TP what is this? def url(self) -> str: business_area_slug = self.get_business_area_slug() diff --git a/src/hct_mis_api/apps/core/management/commands/generatefixtures.py b/src/hct_mis_api/apps/core/management/commands/generatefixtures.py index 00e2c1ae18..9ab8a34d4f 100644 --- a/src/hct_mis_api/apps/core/management/commands/generatefixtures.py +++ b/src/hct_mis_api/apps/core/management/commands/generatefixtures.py @@ -25,8 +25,8 @@ ) from hct_mis_api.apps.household.models import DocumentType from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, ) @@ -124,11 +124,10 @@ def _generate_program_with_dependencies(options: Dict, business_area_index: int) business_area=business_area, ) for _ in range(cash_plans_amount): - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( program=program, business_area=business_area, ) - cash_plan.save() for _ in range(payment_record_amount): registration_data_import = RegistrationDataImportFactory(imported_by=user, business_area=business_area) household, individuals = create_household_for_fixtures( @@ -146,17 +145,17 @@ def _generate_program_with_dependencies(options: Dict, business_area_index: int) if household.admin_area: program.admin_areas.add(household.admin_area) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, target_population=target_population, delivered_quantity_usd=None, business_area=business_area, ) - payment_record.delivered_quantity_usd = Decimal( - cash_plan.exchange_rate * payment_record.delivered_quantity + payment.delivered_quantity_usd = Decimal( + payment_plan.exchange_rate * payment.delivered_quantity ).quantize(Decimal(".01")) - payment_record.save() + payment.save() should_create_grievance = random.choice((True, False)) if should_create_grievance: @@ -174,13 +173,13 @@ def _generate_program_with_dependencies(options: Dict, business_area_index: int) SensitiveGrievanceTicketWithoutExtrasFactory, household=household, individual=random.choice(individuals), - payment_record=payment_record if should_contain_payment_record else None, + payment=payment if should_contain_payment_record else None, ), "complaint": partial( GrievanceComplaintTicketWithoutExtrasFactory, household=household, individual=random.choice(individuals), - payment_record=payment_record if should_contain_payment_record else None, + payment=payment if should_contain_payment_record else None, ), } diff --git a/src/hct_mis_api/apps/core/management/commands/initdemo.py b/src/hct_mis_api/apps/core/management/commands/initdemo.py index 53400a9d27..d065b825d0 100644 --- a/src/hct_mis_api/apps/core/management/commands/initdemo.py +++ b/src/hct_mis_api/apps/core/management/commands/initdemo.py @@ -65,7 +65,6 @@ from hct_mis_api.apps.payment.fixtures import ( generate_delivery_mechanisms, generate_payment_plan, - generate_real_cash_plans, generate_reconciled_payment_plan, update_fsps, ) @@ -149,7 +148,6 @@ def handle(self, *args: Any, **options: Any) -> None: self.stdout.write("Generating payment plan...") generate_payment_plan() self.stdout.write("Generating real cash plans...") - generate_real_cash_plans() self.stdout.write("Generating reconciled payment plan...") generate_reconciled_payment_plan() self.stdout.write("Updating FSPs...") diff --git a/src/hct_mis_api/apps/core/utils.py b/src/hct_mis_api/apps/core/utils.py index e495f30f04..ef4e407768 100644 --- a/src/hct_mis_api/apps/core/utils.py +++ b/src/hct_mis_api/apps/core/utils.py @@ -458,11 +458,11 @@ def is_valid_uuid(uuid_str: str) -> bool: def decode_and_get_payment_object(encoded_id: str, required: bool) -> Optional[Any]: - from hct_mis_api.apps.payment.utils import get_payment_items_sequence_qs + from hct_mis_api.apps.payment.models import Payment if required or encoded_id is not None: decoded_id = decode_id_string(encoded_id) - qs = get_payment_items_sequence_qs() + qs = Payment.objects.filter(excluded=False, conflicted=False) try: return qs.get(id=decoded_id) except Exception: diff --git a/src/hct_mis_api/apps/grievance/filters.py b/src/hct_mis_api/apps/grievance/filters.py index 9d09befaa3..b5eb9d0dea 100644 --- a/src/hct_mis_api/apps/grievance/filters.py +++ b/src/hct_mis_api/apps/grievance/filters.py @@ -103,7 +103,7 @@ class GrievanceTicketFilter(FilterSet): fsp = CharFilter(method="fsp_filter") cash_plan = CharFilter( field_name="payment_verification_ticket_details", - lookup_expr="payment_verification__payment_verification_plan__payment_plan_object_id", + lookup_expr="payment_verification__payment_verification_plan__payment_plan_id", ) created_at_range = DateTimeRangeFilter(field_name="created_at") permissions = MultipleChoiceFilter(choices=Permissions.choices(), method="permissions_filter") @@ -332,7 +332,7 @@ def prepare_ticket_filters(self, lookup: str, obj: GrievanceTicket) -> Q: ticket_type in ("complaint_ticket_details", "sensitive_ticket_details") and real_lookup == "payment_record" ): - q_obj |= Q(**{f"{ticket_type}__payment_object_id": str(obj.id)}) + q_obj |= Q(**{f"{ticket_type}__payment_id": str(obj.id)}) elif real_lookup: q_obj |= Q(**{f"{ticket_type}__{real_lookup}": obj}) return q_obj diff --git a/src/hct_mis_api/apps/grievance/fixtures.py b/src/hct_mis_api/apps/grievance/fixtures.py index c8f6ed5fde..f2add77bea 100644 --- a/src/hct_mis_api/apps/grievance/fixtures.py +++ b/src/hct_mis_api/apps/grievance/fixtures.py @@ -30,10 +30,7 @@ TicketSystemFlaggingDetails, ) from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import ( - PaymentRecordFactory, - PaymentVerificationFactory, -) +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentVerificationFactory from hct_mis_api.apps.payment.models import PaymentVerification @@ -91,7 +88,7 @@ def create_extras(obj, create: bool, extracted: bool, **kwargs: Any) -> None: ) obj.household = household obj.individual = individuals[0] - obj.payment_obj = PaymentRecordFactory(household=household, currency="EUR") + obj.payment = PaymentFactory(household=household, currency="EUR") obj.save() @@ -118,8 +115,7 @@ def create_extras(obj, create: bool, extracted: bool, **kwargs: Any) -> None: ) obj.household = household obj.individual = individuals[0] - obj.payment_object_id = PaymentRecordFactory(household=household, currency="EUR").id - obj.payment_content_type_id = 80 + obj.payment = PaymentFactory(household=household, currency="EUR") obj.save() diff --git a/src/hct_mis_api/apps/grievance/migrations/0074_migration.py b/src/hct_mis_api/apps/grievance/migrations/0074_migration.py new file mode 100644 index 0000000000..2489d0c9f0 --- /dev/null +++ b/src/hct_mis_api/apps/grievance/migrations/0074_migration.py @@ -0,0 +1,62 @@ +# Generated by Django 3.2.25 on 2024-09-25 17:16 + +from django.db import migrations, models + + +def migrate_payment_tickets_generic_foreign_key_to_onetoone(apps, schema_editor): + TicketComplaintDetails = apps.get_model("grievance", "TicketComplaintDetails") + TicketSensitiveDetails = apps.get_model("grievance", "TicketSensitiveDetails") + + Payment = apps.get_model("payment", "Payment") + ContentType = apps.get_model("contenttypes", "ContentType") + + ticket_complaint_details_to_update = [] + ticket_sensitive_details_to_update = [] + + for model in [TicketComplaintDetails, TicketSensitiveDetails]: + for ticket_details in model.objects.exclude(payment_content_type__isnull=True, payment_object_id__isnull=True): + if ticket_details.payment_content_type.model == "payment": + related_instance = Payment.objects.get(id=ticket_details.payment_object_id) + ticket_details.payment = related_instance + if model == TicketComplaintDetails: + ticket_complaint_details_to_update.append(ticket_details) + else: + ticket_sensitive_details_to_update.append(ticket_details) + + TicketComplaintDetails.objects.bulk_update(ticket_complaint_details_to_update, ["payment"]) + TicketSensitiveDetails.objects.bulk_update(ticket_sensitive_details_to_update, ["payment"]) + + +class Migration(migrations.Migration): + + dependencies = [ + ("grievance", "0073_migration"), + ("payment", "0149_migration"), + ] + + operations = [ + migrations.AddField( + model_name="ticketcomplaintdetails", + name="payment", + field=models.OneToOneField( + to="payment.Payment", + null=True, # Temporarily allow nulls for migration purposes + on_delete=models.CASCADE, + related_name="ticket_complaint_details", + ), + ), + migrations.AddField( + model_name="ticketsensitivedetails", + name="payment", + field=models.OneToOneField( + to="payment.Payment", + null=True, # Temporarily allow nulls for migration purposes + on_delete=models.CASCADE, + related_name="ticket_sensitive_details", + ), + ), + migrations.RunPython( + migrate_payment_tickets_generic_foreign_key_to_onetoone, + migrations.RunPython.noop, + ), + ] diff --git a/src/hct_mis_api/apps/grievance/models.py b/src/hct_mis_api/apps/grievance/models.py index d8fd5090e6..21f90cb6dc 100644 --- a/src/hct_mis_api/apps/grievance/models.py +++ b/src/hct_mis_api/apps/grievance/models.py @@ -28,7 +28,7 @@ URGENCY_NOT_SET, ) from hct_mis_api.apps.household.models import Individual -from hct_mis_api.apps.payment.models import PaymentRecord, PaymentVerification +from hct_mis_api.apps.payment.models import PaymentVerification, Payment from hct_mis_api.apps.utils.models import ( AdminUrlMixin, ConcurrencyModel, @@ -628,7 +628,7 @@ class TicketNote(TimeStampedUUIDModel): } -class TicketComplaintDetails(GenericPaymentTicket): +class TicketComplaintDetails(GenericPaymentTicket): # TODO TP drop GenericPaymentTicket STATUS_FLOW = GENERAL_STATUS_FLOW ticket = models.OneToOneField( @@ -648,12 +648,18 @@ class TicketComplaintDetails(GenericPaymentTicket): on_delete=models.CASCADE, null=True, ) + payment = models.OneToOneField( + Payment, + on_delete=models.CASCADE, + null=True, + related_name="ticket_complaint_details", + ) class Meta: verbose_name_plural = "Ticket Complaint Details" -class TicketSensitiveDetails(GenericPaymentTicket): +class TicketSensitiveDetails(GenericPaymentTicket): # TODO TP drop GenericPaymentTicket STATUS_FLOW = GENERAL_STATUS_FLOW ticket = models.OneToOneField( @@ -673,6 +679,12 @@ class TicketSensitiveDetails(GenericPaymentTicket): on_delete=models.CASCADE, null=True, ) + payment = models.OneToOneField( + Payment, + on_delete=models.CASCADE, + null=True, + related_name="ticket_sensitive_details", + ) class Meta: verbose_name_plural = "Ticket Sensitive Details" @@ -955,9 +967,9 @@ def individual(self) -> Optional["Individual"]: return getattr(self.payment_record, "head_of_household", None) @property - def payment_record(self) -> Optional["PaymentRecord"]: + def payment_record(self) -> Optional["Payment"]: # TODO: need to double check this property sometimes return null ??? - return getattr(self.payment_verification, "payment_obj", None) + return getattr(self.payment_verification, "payment", None) class Meta: verbose_name_plural = "Ticket Payment Verification Details" diff --git a/src/hct_mis_api/apps/grievance/schema.py b/src/hct_mis_api/apps/grievance/schema.py index f6779653af..8986893b67 100644 --- a/src/hct_mis_api/apps/grievance/schema.py +++ b/src/hct_mis_api/apps/grievance/schema.py @@ -181,8 +181,8 @@ def resolve_individual(grievance_ticket: GrievanceTicket, info: Any) -> Optional @staticmethod def resolve_payment_record(grievance_ticket: GrievanceTicket, info: Any) -> Optional[Any]: payment_verification = getattr(grievance_ticket.ticket_details, "payment_verification", None) - payment_obj = getattr(grievance_ticket.ticket_details, "payment_obj", None) - return getattr(payment_verification, "payment_obj", None) if payment_verification else payment_obj + payment_obj = getattr(grievance_ticket.ticket_details, "payment", None) + return getattr(payment_verification, "payment", None) if payment_verification else payment_obj @staticmethod def resolve_admin(grievance_ticket: GrievanceTicket, info: Any) -> Optional[str]: @@ -247,7 +247,7 @@ class Meta: connection_class = ExtendedConnection def resolve_payment_record(self, info: Any) -> Optional[Any]: - return getattr(self, "payment_obj", None) + return getattr(self, "payment", None) class TicketSensitiveDetailsNode(DjangoObjectType): @@ -260,7 +260,7 @@ class Meta: connection_class = ExtendedConnection def resolve_payment_record(self, info: Any) -> Optional[Any]: - return getattr(self, "payment_obj", None) + return getattr(self, "payment", None) class TicketIndividualDataUpdateDetailsNode(DjangoObjectType): diff --git a/src/hct_mis_api/apps/grievance/services/payment_verification_services.py b/src/hct_mis_api/apps/grievance/services/payment_verification_services.py index 8b7203aa07..65ad7b00b3 100644 --- a/src/hct_mis_api/apps/grievance/services/payment_verification_services.py +++ b/src/hct_mis_api/apps/grievance/services/payment_verification_services.py @@ -23,8 +23,8 @@ def update_payment_verification_service( if payment_verification_details.new_status == PaymentVerification.STATUS_NOT_RECEIVED: status = payment_verification_details.new_status elif ( - payment_verification.payment_obj - and payment_verification_details.new_received_amount == payment_verification.payment_obj.delivered_quantity + payment_verification.payment + and payment_verification_details.new_received_amount == payment_verification.payment.delivered_quantity ): status = PaymentVerification.STATUS_RECEIVED else: diff --git a/src/hct_mis_api/apps/grievance/services/ticket_based_on_payment_record_services.py b/src/hct_mis_api/apps/grievance/services/ticket_based_on_payment_record_services.py index b39c2b5aee..5774479140 100644 --- a/src/hct_mis_api/apps/grievance/services/ticket_based_on_payment_record_services.py +++ b/src/hct_mis_api/apps/grievance/services/ticket_based_on_payment_record_services.py @@ -58,7 +58,7 @@ def create_tickets_based_on_payment_records_service( model.objects.create( individual=individual, household=household, - payment_obj=payment_record, + payment=payment_record, ticket=ticket, ) ticket.refresh_from_db() @@ -88,9 +88,7 @@ def update_ticket_based_on_payment_record_service( if payment_record_id := input_data.get("payment_record"): node_name, obj_id = b64decode(payment_record_id).decode().split(":") - payment_record: Union["Payment", "PaymentRecord"] = get_object_or_404( # type: ignore - Payment if node_name == "PaymentNode" else PaymentRecord, id=obj_id - ) - ticket_details.payment_obj = payment_record + payment_record: "Payment" = get_object_or_404(Payment, id=obj_id) + ticket_details.payment = payment_record ticket_details.save() return grievance_ticket diff --git a/src/hct_mis_api/apps/household/fixtures/data.json b/src/hct_mis_api/apps/household/fixtures/data.json index ff0882dafd..9e7e224d00 100644 --- a/src/hct_mis_api/apps/household/fixtures/data.json +++ b/src/hct_mis_api/apps/household/fixtures/data.json @@ -126,7 +126,6 @@ "collect_individual_data": "1", "currency": "USD", "unhcr_id": "", - "user_fields": {}, "detail_id": "4", "total_cash_received_usd": null, "total_cash_received": null, @@ -205,7 +204,6 @@ "collect_individual_data": "1", "currency": "USD", "unhcr_id": "", - "user_fields": {}, "detail_id": "3", "total_cash_received_usd": null, "total_cash_received": null, @@ -450,7 +448,6 @@ "first_registration_date": "1974-12-15", "last_registration_date": "1974-12-15", "flex_fields": {}, - "user_fields": {}, "enrolled_in_nutrition_programme": null, "administration_of_rutf": null, "unicef_id": "IND-74-0000.0001", @@ -547,7 +544,6 @@ "first_registration_date": "1988-06-15", "last_registration_date": "1988-06-15", "flex_fields": {}, - "user_fields": {}, "enrolled_in_nutrition_programme": null, "administration_of_rutf": null, "unicef_id": "IND-88-0000.0002", @@ -625,7 +621,6 @@ "first_registration_date": "1942-12-12", "last_registration_date": "1942-12-12", "flex_fields": {}, - "user_fields": {}, "enrolled_in_nutrition_programme": null, "administration_of_rutf": null, "unicef_id": "IND-42-0000.0003", @@ -703,7 +698,6 @@ "first_registration_date": "1969-06-22", "last_registration_date": "1969-06-22", "flex_fields": {}, - "user_fields": {}, "enrolled_in_nutrition_programme": null, "administration_of_rutf": null, "unicef_id": "IND-69-0000.0004", @@ -781,7 +775,6 @@ "first_registration_date": "1988-06-15", "last_registration_date": "1988-06-15", "flex_fields": {}, - "user_fields": {}, "enrolled_in_nutrition_programme": null, "administration_of_rutf": null, "unicef_id": "IND-88-0000.0005", @@ -859,7 +852,6 @@ "first_registration_date": "1988-06-15", "last_registration_date": "1988-06-15", "flex_fields": {}, - "user_fields": {}, "enrolled_in_nutrition_programme": null, "administration_of_rutf": null, "unicef_id": "IND-88-0000.0006", @@ -956,7 +948,6 @@ "first_registration_date": "1988-06-15", "last_registration_date": "1988-06-15", "flex_fields": {}, - "user_fields": {}, "enrolled_in_nutrition_programme": null, "administration_of_rutf": null, "unicef_id": "IND-88-0000.0999", diff --git a/src/hct_mis_api/apps/household/migrations/0189_migration.py b/src/hct_mis_api/apps/household/migrations/0189_migration.py new file mode 100644 index 0000000000..1a3427ef06 --- /dev/null +++ b/src/hct_mis_api/apps/household/migrations/0189_migration.py @@ -0,0 +1,48 @@ +# Generated by Django 3.2.25 on 2024-10-23 11:22 + +from django.db import migrations, models +from django.db.models import Q + + +def migrate_user_fields_to_internal_data(apps, schema_editor): + Individual = apps.get_model("household", "Individual") + Household = apps.get_model("household", "Household") + + households = Household.objects.exclude(Q(user_fields="") | Q(user_fields={})) + individuals = Individual.objects.exclude(Q(user_fields="") | Q(user_fields={})) + + updated_households = [] + updated_individuals = [] + + for household in households: + household.internal_data = household.user_fields + updated_households.append(household) + + for individual in individuals: + individual.internal_data = individual.user_fields + updated_individuals.append(individual) + + Household.objects.bulk_update(updated_households, ["internal_data"]) + Individual.objects.bulk_update(updated_individuals, ["internal_data"]) + + +class Migration(migrations.Migration): + + dependencies = [ + ("household", "0188_migration"), + ] + + operations = [ + migrations.RunPython( + migrate_user_fields_to_internal_data, + migrations.RunPython.noop, + ), + migrations.RemoveField( + model_name="household", + name="user_fields", + ), + migrations.RemoveField( + model_name="individual", + name="user_fields", + ), + ] diff --git a/src/hct_mis_api/apps/household/migrations/0190_migration.py b/src/hct_mis_api/apps/household/migrations/0190_migration.py new file mode 100644 index 0000000000..e4db330187 --- /dev/null +++ b/src/hct_mis_api/apps/household/migrations/0190_migration.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.25 on 2024-10-23 11:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('household', '0189_migration'), + ] + + operations = [ + migrations.AddField( + model_name='household', + name='internal_data', + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name='individual', + name='internal_data', + field=models.JSONField(default=dict), + ), + ] diff --git a/src/hct_mis_api/apps/household/models.py b/src/hct_mis_api/apps/household/models.py index 0e1f0feee7..030ea1cc6a 100644 --- a/src/hct_mis_api/apps/household/models.py +++ b/src/hct_mis_api/apps/household/models.py @@ -39,6 +39,7 @@ AbstractSyncable, AdminUrlMixin, ConcurrencyModel, + InternalDataFieldModel, MergeStatusModel, RepresentationManager, SoftDeletableRepresentationMergeStatusModel, @@ -336,6 +337,7 @@ def business_area(self) -> Optional[BusinessArea]: class Household( + InternalDataFieldModel, SoftDeletableRepresentationMergeStatusModelWithDate, TimeStampedUUIDModel, AbstractSyncable, @@ -507,7 +509,6 @@ class CollectType(models.TextChoices): collect_individual_data = models.CharField(max_length=250, choices=COLLECT_TYPES, default=COLLECT_TYPE_UNKNOWN) currency = models.CharField(max_length=250, choices=CURRENCY_CHOICES, default=BLANK) unhcr_id = models.CharField(max_length=250, blank=True, default=BLANK, db_index=True) - user_fields = JSONField(default=dict, blank=True) detail_id = models.CharField( max_length=150, blank=True, null=True, help_text="Kobo asset ID, Xlsx row ID, Aurora source ID" ) @@ -593,9 +594,7 @@ def status(self) -> str: def withdraw(self, tag: Optional[Any] = None) -> None: self.withdrawn = True self.withdrawn_date = timezone.now() - user_fields = self.user_fields or {} - user_fields["withdrawn_tag"] = tag - self.user_fields = user_fields + self.internal_data["withdrawn_tag"] = tag self.save() household_withdrawn.send(sender=self.__class__, instance=self) @@ -605,13 +604,13 @@ def unwithdraw(self) -> None: self.save() def set_sys_field(self, key: str, value: Any) -> None: - if "sys" not in self.user_fields: - self.user_fields["sys"] = {} - self.user_fields["sys"][key] = value + if "sys" not in self.internal_data: + self.internal_data["sys"] = {} + self.internal_data["sys"][key] = value def get_sys_field(self, key: str) -> Any: - if "sys" in self.user_fields: - return self.user_fields["sys"][key] + if "sys" in self.internal_data: + return self.internal_data["sys"][key] return None def set_admin_areas(self, new_admin_area: Optional[Area] = None, save: bool = True) -> None: @@ -868,6 +867,7 @@ def business_area(self) -> Optional[BusinessArea]: class Individual( + InternalDataFieldModel, SoftDeletableRepresentationMergeStatusModelWithDate, TimeStampedUUIDModel, AbstractSyncable, @@ -987,7 +987,6 @@ class Individual( first_registration_date = models.DateField() last_registration_date = models.DateField() flex_fields = JSONField(default=dict, blank=True, encoder=FlexFieldsEncoder) - user_fields = JSONField(default=dict, blank=True) enrolled_in_nutrition_programme = models.BooleanField(null=True) administration_of_rutf = models.BooleanField(null=True) deduplication_golden_record_status = models.CharField( @@ -1182,16 +1181,6 @@ class Meta: verbose_name = "Individual" indexes = (GinIndex(fields=["vector_column"]),) - def set_sys_field(self, key: str, value: Any) -> None: - if "sys" not in self.user_fields: - self.user_fields["sys"] = {} - self.user_fields["sys"][key] = value - - def get_sys_field(self, key: str) -> Any: - if "sys" in self.user_fields: - return self.user_fields["sys"][key] - return None - def recalculate_data(self, save: bool = True) -> Tuple[Any, List[str]]: update_fields = ["disability"] diff --git a/src/hct_mis_api/apps/payment/admin.py b/src/hct_mis_api/apps/payment/admin.py index 0e4f060dc4..17b55ebe34 100644 --- a/src/hct_mis_api/apps/payment/admin.py +++ b/src/hct_mis_api/apps/payment/admin.py @@ -136,7 +136,7 @@ def import_payment_records(self, request: HttpRequest) -> Any: @admin.register(PaymentVerificationPlan) class PaymentVerificationPlanAdmin(LinkedObjectsMixin, HOPEModelAdminBase): - list_display = ("payment_plan_obj", "status", "verification_channel") + list_display = ("payment_plan", "status", "verification_channel") list_filter = ( ("status", ChoicesFieldComboFilter), ("verification_channel", ChoicesFieldComboFilter), @@ -200,11 +200,11 @@ class PaymentVerificationAdmin(HOPEModelAdminBase): raw_id_fields = ("payment_verification_plan", "payment_content_type") def payment_plan_name(self, obj: PaymentVerification) -> str: - payment_plan = obj.payment_verification_plan.payment_plan_obj + payment_plan = obj.payment_verification_plan.payment_plan return getattr(payment_plan, "name", "~no name~") def household(self, obj: PaymentVerification) -> str: - payment = obj.payment_obj + payment = obj.payment return payment.household.unicef_id if payment else "" def get_queryset(self, request: HttpRequest) -> QuerySet: @@ -213,10 +213,10 @@ def get_queryset(self, request: HttpRequest) -> QuerySet: .get_queryset(request) .select_related("payment_verification_plan") .prefetch_related( - "payment_obj", - "payment_obj__household", - "payment_verification_plan__payment_plan_obj", - "payment_verification_plan__payment_plan_obj__business_area", + "payment", + "payment__household", + "payment_verification_plan__payment_plan", + "payment_verification_plan__payment_plan__business_area", ) ) @@ -252,14 +252,14 @@ def payments(self, request: HttpRequest, pk: str) -> TemplateResponse: @admin.register(PaymentPlan) class PaymentPlanAdmin(HOPEModelAdminBase, PaymentPlanCeleryTasksMixin): - list_display = ("unicef_id", "program", "status", "target_population") + list_display = ("unicef_id", "program_cycle", "status", "target_population") list_filter = ( ("status", ChoicesFieldComboFilter), ("business_area", AutoCompleteFilter), - ("program__id", ValueFilter), + ("program_cycle__program__id", ValueFilter), ("target_population", AutoCompleteFilter), ) - raw_id_fields = ("business_area", "program", "target_population", "created_by", "program_cycle") + raw_id_fields = ("business_area", "target_population", "created_by", "program_cycle") search_fields = ("id", "unicef_id") def has_delete_permission(self, request: HttpRequest, obj: Optional[Any] = None) -> bool: diff --git a/src/hct_mis_api/apps/payment/api/serializers.py b/src/hct_mis_api/apps/payment/api/serializers.py index 57aa929915..7aaaf403b6 100644 --- a/src/hct_mis_api/apps/payment/api/serializers.py +++ b/src/hct_mis_api/apps/payment/api/serializers.py @@ -25,8 +25,8 @@ class PaymentPlanSerializer(serializers.ModelSerializer): target_population = serializers.CharField(source="target_population.name") currency = serializers.CharField(source="get_currency_display") follow_ups = FollowUpPaymentPlanSerializer(many=True, read_only=True) - program = serializers.CharField(source="program.name") - program_id = Base64ModelField(model_name="Program") + program = serializers.CharField(source="program_cycle.program.name") + program_id = Base64ModelField(model_name="Program", source="program_cycle.program.id") last_approval_process_by = serializers.SerializerMethodField() class Meta: diff --git a/src/hct_mis_api/apps/payment/api/views.py b/src/hct_mis_api/apps/payment/api/views.py index 2f610c8b82..daf09d4a81 100644 --- a/src/hct_mis_api/apps/payment/api/views.py +++ b/src/hct_mis_api/apps/payment/api/views.py @@ -73,7 +73,7 @@ class PaymentPlanViewSet(BusinessAreaProgramMixin, PaymentPlanMixin, mixins.List def get_queryset(self) -> QuerySet: business_area = self.get_business_area() program = self.get_program() - return PaymentPlan.objects.filter(business_area=business_area, program=program) + return PaymentPlan.objects.filter(business_area=business_area, program_cycle__program=program) class PaymentPlanManagerialViewSet(BusinessAreaMixin, PaymentPlanMixin, mixins.ListModelMixin, GenericViewSet): @@ -93,7 +93,7 @@ def get_queryset(self) -> QuerySet: PaymentPlan.Status.IN_REVIEW, PaymentPlan.Status.ACCEPTED, ], - program__in=program_ids, + program_cycle__program__in=program_ids, ) @etag_decorator(PaymentPlanKeyConstructor) @@ -139,7 +139,7 @@ def _perform_payment_plan_status_action( if not self.request.user.has_permission( self._get_action_permission(input_data["action"]), business_area, - payment_plan.program_id, + payment_plan.program_cycle.program_id, ): raise PermissionDenied( f"You do not have permission to perform action {input_data['action']} " @@ -161,7 +161,7 @@ def _perform_payment_plan_status_action( mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=request.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program_cycle.program.pk, old_object=old_payment_plan, new_object=payment_plan, ) diff --git a/src/hct_mis_api/apps/payment/celery_tasks.py b/src/hct_mis_api/apps/payment/celery_tasks.py index 5b4407312b..c0cb37b4ab 100644 --- a/src/hct_mis_api/apps/payment/celery_tasks.py +++ b/src/hct_mis_api/apps/payment/celery_tasks.py @@ -449,9 +449,9 @@ def payment_plan_exclude_beneficiaries( from hct_mis_api.apps.payment.models import Payment, PaymentPlan - payment_plan = PaymentPlan.objects.select_related("program").get(id=payment_plan_id) + payment_plan = PaymentPlan.objects.select_related("program_cycle__program").get(id=payment_plan_id) # for social worker program exclude Individual unicef_id - is_social_worker_program = payment_plan.program.is_social_worker_program + is_social_worker_program = payment_plan.program_cycle.program.is_social_worker_program set_sentry_business_area_tag(payment_plan.business_area.name) pp_payment_items = payment_plan.payment_items.select_related("household") payment_plan_title = "Follow-up Payment Plan" if payment_plan.is_follow_up else "Payment Plan" diff --git a/src/hct_mis_api/apps/payment/filters.py b/src/hct_mis_api/apps/payment/filters.py index 70c5e13389..5feb724601 100644 --- a/src/hct_mis_api/apps/payment/filters.py +++ b/src/hct_mis_api/apps/payment/filters.py @@ -2,7 +2,6 @@ from typing import Any, List from uuid import UUID -from django.contrib.contenttypes.models import ContentType from django.db.models import Case, Count, IntegerField, Q, QuerySet, Value, When from django.db.models.functions import Lower from django.shortcuts import get_object_or_404 @@ -148,11 +147,8 @@ def search_filter(self, qs: QuerySet, name: str, value: str) -> QuerySet: def payment_plan_filter(self, qs: QuerySet, name: str, value: str) -> QuerySet: node_name, obj_id = b64decode(value).decode().split(":") - # content type for PaymentPlan or CashPlan - ct_id = ContentType.objects.filter(app_label="payment", model=node_name[:-4].lower()).first().pk return qs.filter( - payment_verification_plan__payment_plan_object_id=obj_id, - payment_verification_plan__payment_plan_content_type_id=ct_id, + payment_verification_plan__payment_plan_id=obj_id, ) def business_area_filter(self, qs: QuerySet, name: str, value: str) -> QuerySet: @@ -195,7 +191,7 @@ def filter_queryset(self, queryset: QuerySet) -> QuerySet: object_type = cleaned_data.get("object_type") object_id = cleaned_data.get("object_id") plan_object = (PaymentPlan if object_type == self.PLAN_TYPE_PAYMENT else CashPlan).objects.get(pk=object_id) - verifications_ids = plan_object.payment_verification_plan.all().values_list("pk", flat=True) + verifications_ids = plan_object.payment_verification_plans.all().values_list("pk", flat=True) return queryset.filter(object_id__in=verifications_ids) def object_id_filter(self, qs: QuerySet, name: str, value: UUID) -> QuerySet: @@ -351,7 +347,7 @@ def source_payment_plan_filter(self, qs: QuerySet, name: str, value: str) -> "Qu return PaymentPlan.objects.filter(source_payment_plan_id=decode_id_string(value)) def filter_by_program(self, qs: "QuerySet", name: str, value: str) -> "QuerySet[PaymentPlan]": - return qs.filter(program_id=decode_id_string_required(value)) + return qs.filter(program_cycle__program_id=decode_id_string_required(value)) def filter_by_program_cycle(self, qs: "QuerySet", name: str, value: str) -> "QuerySet[PaymentPlan]": return qs.filter(program_cycle_id=decode_id_string_required(value)) @@ -430,7 +426,7 @@ def cash_plan_and_payment_plan_filter(queryset: ExtendedQuerySetSequence, **kwar queryset = queryset.filter(business_area__slug=business_area) if program: - queryset = queryset.filter(program=decode_id_string(program)) + queryset = queryset.filter(program_cycle__program=decode_id_string(program)) if start_date_gte: queryset = queryset.filter(start_date__gte=start_date_gte) @@ -466,7 +462,7 @@ def cash_plan_and_payment_plan_ordering(queryset: ExtendedQuerySetSequence, orde if order_by == "verification_status": qs = queryset.order_by(reverse + "custom_order") elif order_by == "unicef_id": - qs = sorted(queryset, key=lambda o: o.get_unicef_id, reverse=bool(reverse)) + qs = sorted(queryset, key=lambda o: o.unicef_id, reverse=bool(reverse)) elif order_by == "dispersion_date": # TODO this field is empty at the moment qs = queryset @@ -490,7 +486,7 @@ def payment_record_and_payment_filter(queryset: ExtendedQuerySetSequence, **kwar queryset = queryset.filter(household__id=decode_id_string(household)) if program: - queryset = queryset.filter(parent__program=decode_id_string(program)) + queryset = queryset.filter(parent__program=decode_id_string(program)) # TODO TP payment_cycle__program return queryset @@ -500,7 +496,7 @@ def payment_record_and_payment_ordering(queryset: ExtendedQuerySetSequence, orde order_by = order_by[1:] if reverse else order_by if order_by == "ca_id": - qs = sorted(queryset, key=lambda o: o.get_unicef_id, reverse=bool(reverse)) + qs = sorted(queryset, key=lambda o: o.unicef_id, reverse=bool(reverse)) elif order_by in ("head_of_household", "entitlement_quantity", "delivered_quantity", "delivery_date"): order_by_dict = {f"{order_by}__isnull": True} qs_null = list(queryset.filter(**order_by_dict)) diff --git a/src/hct_mis_api/apps/payment/fixtures.py b/src/hct_mis_api/apps/payment/fixtures.py index 123df63ea3..2f26a8ebdf 100644 --- a/src/hct_mis_api/apps/payment/fixtures.py +++ b/src/hct_mis_api/apps/payment/fixtures.py @@ -2,8 +2,8 @@ import string from datetime import timedelta from decimal import Decimal -from random import choice, randint -from typing import Any, Optional, Union +from random import randint +from typing import Any, Optional from uuid import UUID from django.utils import timezone @@ -28,18 +28,10 @@ IndividualRoleInHouseholdFactory, create_household, ) -from hct_mis_api.apps.household.models import ( - MALE, - REFUGEE, - ROLE_PRIMARY, - Household, - Individual, -) -from hct_mis_api.apps.payment.delivery_mechanisms import DeliveryMechanismChoices +from hct_mis_api.apps.household.models import MALE, ROLE_PRIMARY, Household, Individual from hct_mis_api.apps.payment.models import ( Approval, ApprovalProcess, - CashPlan, DeliveryMechanism, DeliveryMechanismData, DeliveryMechanismPerPaymentPlan, @@ -50,20 +42,15 @@ Payment, PaymentPlan, PaymentPlanSplit, - PaymentRecord, PaymentVerification, PaymentVerificationPlan, PaymentVerificationSummary, - ServiceProvider, ) from hct_mis_api.apps.payment.utils import to_decimal -from hct_mis_api.apps.program.fixtures import ProgramCycleFactory, ProgramFactory +from hct_mis_api.apps.program.fixtures import ProgramCycleFactory from hct_mis_api.apps.program.models import Program from hct_mis_api.apps.registration_data.fixtures import RegistrationDataImportFactory -from hct_mis_api.apps.targeting.fixtures import ( - TargetingCriteriaFactory, - TargetPopulationFactory, -) +from hct_mis_api.apps.targeting.fixtures import TargetPopulationFactory from hct_mis_api.apps.targeting.models import ( TargetingCriteria, TargetingCriteriaRule, @@ -83,97 +70,10 @@ def update_kwargs_with_usd_currency(kwargs: Any) -> Any: class PaymentVerificationSummaryFactory(DjangoModelFactory): - payment_plan_obj = factory.SubFactory("payment.fixtures.CashPlanFactory") - class Meta: model = PaymentVerificationSummary -class CashPlanFactory(DjangoModelFactory): - class Meta: - model = CashPlan - - ca_id = factory.Sequence(lambda n: f"PP-0000-00-1122334{n}") - business_area = factory.LazyAttribute(lambda o: BusinessArea.objects.first()) - program = factory.SubFactory(ProgramFactory) - status_date = factory.Faker( - "date_time_this_decade", - before_now=False, - after_now=True, - tzinfo=utc, - ) - status = factory.fuzzy.FuzzyChoice( - CashPlan.STATUS_CHOICE, - getter=lambda c: c[0], - ) - name = factory.Faker( - "sentence", - nb_words=6, - variable_nb_words=True, - ext_word_list=None, - ) - distribution_level = "Registration Group" - dispersion_date = factory.Faker( - "date_time_this_decade", - before_now=False, - after_now=True, - tzinfo=utc, - ) - coverage_duration = factory.fuzzy.FuzzyInteger(1, 4) - coverage_unit = factory.Faker( - "random_element", - elements=["Day(s)", "Week(s)", "Month(s)", "Year(s)"], - ) - comments = factory.Faker( - "sentence", - nb_words=6, - variable_nb_words=True, - ext_word_list=None, - ) - delivery_type = factory.fuzzy.FuzzyChoice( - DeliveryMechanismChoices.DELIVERY_TYPE_CHOICES, - getter=lambda c: c[0], - ) - assistance_measurement = factory.Faker("currency_name") - assistance_through = factory.Faker("random_element", elements=["ING", "Bank of America", "mBank"]) - vision_id = factory.Faker("uuid4") - funds_commitment = factory.fuzzy.FuzzyInteger(1000, 99999999) - exchange_rate = factory.fuzzy.FuzzyDecimal(0.1, 9.9) - down_payment = factory.fuzzy.FuzzyInteger(1000, 99999999) - validation_alerts_count = factory.fuzzy.FuzzyInteger(1, 3) - total_persons_covered = factory.fuzzy.FuzzyInteger(1, 4) - total_persons_covered_revised = factory.fuzzy.FuzzyInteger(1, 4) - - total_entitled_quantity = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_entitled_quantity_revised = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_delivered_quantity = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_undelivered_quantity = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - - total_entitled_quantity_usd = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_entitled_quantity_revised_usd = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_delivered_quantity_usd = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_undelivered_quantity_usd = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - - @factory.post_generation - def payment_verification_summary(self, create: bool, extracted: bool, **kwargs: Any) -> None: - if not create: - return - - PaymentVerificationSummaryFactory(payment_plan_obj=self) - - -class ServiceProviderFactory(DjangoModelFactory): - class Meta: - model = ServiceProvider - - business_area = factory.LazyAttribute(lambda o: BusinessArea.objects.first()) - ca_id = factory.Iterator(CaIdIterator("SRV")) - full_name = factory.Faker("company") - short_name = factory.LazyAttribute(lambda o: o.full_name[0:3]) - country = factory.Faker("country_code") - vision_id = factory.fuzzy.FuzzyInteger(1342342, 9999999932) - - class DeliveryMechanismFactory(DjangoModelFactory): payment_gateway_id = factory.Faker("uuid4") code = factory.Faker("uuid4") @@ -215,68 +115,8 @@ class Meta: xlsx_template = factory.SubFactory(FinancialServiceProviderXlsxTemplateFactory) -class PaymentRecordFactory(DjangoModelFactory): - class Meta: - model = PaymentRecord - - business_area = factory.LazyAttribute(lambda o: BusinessArea.objects.first()) - status = factory.fuzzy.FuzzyChoice( - PaymentRecord.STATUS_CHOICE, - getter=lambda c: c[0], - ) - full_name = factory.Faker("name") - status_date = factory.Faker( - "date_time_this_decade", - before_now=False, - after_now=True, - tzinfo=utc, - ) - ca_id = factory.Iterator(CaIdIterator("PR")) - ca_hash_id = factory.Faker("uuid4") - parent = factory.SubFactory(CashPlanFactory) - household = factory.SubFactory(HouseholdFactory) - total_persons_covered = factory.fuzzy.FuzzyInteger(1, 7) - distribution_modality = factory.Faker( - "sentence", - nb_words=6, - variable_nb_words=True, - ext_word_list=None, - ) - target_population = factory.SubFactory(TargetPopulationFactory) - entitlement_card_number = factory.Faker("ssn") - entitlement_card_status = factory.fuzzy.FuzzyChoice( - PaymentRecord.ENTITLEMENT_CARD_STATUS_CHOICE, - getter=lambda c: c[0], - ) - entitlement_card_issue_date = factory.Faker( - "date_time_this_decade", - before_now=True, - after_now=False, - tzinfo=utc, - ) - currency = factory.Faker("currency_code") - entitlement_quantity = factory.fuzzy.FuzzyDecimal(100.0, 10000.0) - entitlement_quantity_usd = factory.fuzzy.FuzzyDecimal(100.0, 10000.0) - delivered_quantity = factory.fuzzy.FuzzyDecimal(100.0, 10000.0) - delivered_quantity_usd = factory.fuzzy.FuzzyDecimal(100.0, 10000.0) - delivery_date = factory.Faker( - "date_time_this_decade", - before_now=True, - after_now=False, - tzinfo=utc, - ) - service_provider = factory.SubFactory(ServiceProviderFactory) - registration_ca_id = factory.Faker("uuid4") - - @classmethod - def _create(cls, model_class: Any, *args: Any, **kwargs: Any) -> "PaymentRecord": - instance = model_class(**update_kwargs_with_usd_currency(kwargs)) - instance.save() - return instance - - class PaymentVerificationPlanFactory(DjangoModelFactory): - payment_plan_obj = factory.SubFactory(CashPlanFactory) + payment_plan = factory.SubFactory("hct_mis_api.apps.payment.fixtures.PaymentPlanFactory") status = factory.fuzzy.FuzzyChoice( ((PaymentVerificationPlan.STATUS_PENDING, "pending"),), getter=lambda c: c[0], @@ -301,7 +141,7 @@ class Meta: class PaymentVerificationFactory(DjangoModelFactory): - payment_obj = factory.SubFactory(PaymentRecordFactory) + payment = factory.SubFactory("hct_mis_api.apps.payment.fixtures.PaymentFactory") payment_verification_plan = factory.Iterator(PaymentVerificationPlan.objects.all()) status = factory.fuzzy.FuzzyChoice( PaymentVerification.STATUS_CHOICES, @@ -375,137 +215,6 @@ def cycle(self, create: bool, extracted: bool, **kwargs: Any) -> None: ProgramCycleFactory(program=self, **kwargs) -class RealCashPlanFactory(DjangoModelFactory): - class Meta: - model = CashPlan - - business_area = factory.LazyAttribute(lambda o: BusinessArea.objects.first()) - ca_id = factory.Iterator(CaIdIterator("CSH")) - ca_hash_id = factory.Faker("uuid4") - program = factory.SubFactory(RealProgramFactory) - status_date = factory.Faker( - "date_time_this_decade", - before_now=True, - after_now=False, - tzinfo=utc, - ) - status = factory.fuzzy.FuzzyChoice( - CashPlan.STATUS_CHOICE, - getter=lambda c: c[0], - ) - name = factory.Faker( - "sentence", - nb_words=6, - variable_nb_words=True, - ext_word_list=None, - ) - distribution_level = "Registration Group" - dispersion_date = factory.Faker( - "date_time_this_decade", - before_now=False, - after_now=True, - tzinfo=utc, - ) - coverage_duration = factory.fuzzy.FuzzyInteger(1, 4) - coverage_unit = factory.Faker( - "random_element", - elements=["Day(s)", "Week(s)", "Month(s)", "Year(s)"], - ) - comments = factory.Faker( - "sentence", - nb_words=6, - variable_nb_words=True, - ext_word_list=None, - ) - delivery_type = factory.fuzzy.FuzzyChoice( - DeliveryMechanismChoices.DELIVERY_TYPE_CHOICES, - getter=lambda c: c[0], - ) - assistance_measurement = factory.Faker("currency_name") - assistance_through = factory.LazyAttribute(lambda o: ServiceProvider.objects.order_by("?").first().ca_id) - vision_id = factory.fuzzy.FuzzyInteger(123534, 12353435234) - funds_commitment = factory.fuzzy.FuzzyInteger(1000, 99999999) - exchange_rate = factory.fuzzy.FuzzyDecimal(0.1, 9.9) - down_payment = factory.fuzzy.FuzzyInteger(1000, 99999999) - validation_alerts_count = factory.fuzzy.FuzzyInteger(1, 3) - total_persons_covered = factory.fuzzy.FuzzyInteger(1, 4) - total_persons_covered_revised = factory.fuzzy.FuzzyInteger(1, 4) - - total_entitled_quantity = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_entitled_quantity_revised = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_delivered_quantity = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - total_undelivered_quantity = factory.fuzzy.FuzzyDecimal(20000.0, 90000000.0) - - service_provider = factory.LazyAttribute(lambda o: ServiceProvider.objects.order_by("?").first()) - - @factory.post_generation - def payment_verification_summary(self, create: bool, extracted: bool, **kwargs: Any) -> None: - if not create: - return - - PaymentVerificationSummaryFactory(payment_plan_obj=self) - - @factory.post_generation - def cycle(self, create: bool, extracted: bool, **kwargs: Any) -> None: - if not create: - return - ProgramCycleFactory(program=self.program, **kwargs) - - -class RealPaymentRecordFactory(DjangoModelFactory): - class Meta: - model = PaymentRecord - - business_area = factory.LazyAttribute(lambda o: BusinessArea.objects.first()) - status = factory.fuzzy.FuzzyChoice( - PaymentRecord.STATUS_CHOICE, - getter=lambda c: c[0], - ) - full_name = factory.Faker("name") - status_date = factory.Faker( - "date_time_this_decade", - before_now=True, - after_now=False, - tzinfo=utc, - ) - ca_id = factory.Iterator(CaIdIterator("PR")) - ca_hash_id = factory.Faker("uuid4") - household = factory.LazyAttribute(lambda o: Household.objects.order_by("?").first()) - head_of_household = factory.LazyAttribute(lambda o: o.household.head_of_household) - total_persons_covered = factory.fuzzy.FuzzyInteger(1, 7) - distribution_modality = factory.Faker( - "sentence", - nb_words=6, - variable_nb_words=True, - ext_word_list=None, - ) - target_population = factory.SubFactory(TargetPopulationFactory) - entitlement_card_number = factory.Faker("ssn") - entitlement_card_status = factory.fuzzy.FuzzyChoice( - PaymentRecord.ENTITLEMENT_CARD_STATUS_CHOICE, - getter=lambda c: c[0], - ) - entitlement_card_issue_date = factory.Faker( - "date_time_this_decade", - before_now=True, - after_now=False, - tzinfo=utc, - ) - delivery_type = factory.LazyAttribute(lambda o: DeliveryMechanism.objects.order_by("?").first()) - currency = factory.Faker("currency_code") - entitlement_quantity = factory.fuzzy.FuzzyDecimal(100.0, 10000.0) - delivered_quantity = factory.LazyAttribute(lambda o: Decimal(randint(10, int(o.entitlement_quantity)))) - delivered_quantity_usd = factory.LazyAttribute(lambda o: Decimal(randint(10, int(o.entitlement_quantity)))) - delivery_date = factory.Faker( - "date_time_this_decade", - before_now=True, - after_now=False, - tzinfo=utc, - ) - service_provider = factory.LazyAttribute(lambda o: ServiceProvider.objects.order_by("?").first()) - registration_ca_id = factory.Faker("uuid4") - - class PaymentPlanFactory(DjangoModelFactory): class Meta: model = PaymentPlan @@ -532,8 +241,7 @@ class Meta: created_by = factory.SubFactory(UserFactory) unicef_id = factory.Faker("uuid4") target_population = factory.SubFactory(TargetPopulationFactory) - program = factory.SubFactory(RealProgramFactory) - program_cycle = factory.LazyAttribute(lambda o: o.program.cycles.first()) + program_cycle = factory.SubFactory(ProgramCycleFactory) currency = factory.fuzzy.FuzzyChoice(CURRENCY_CHOICES, getter=lambda c: c[0]) dispersion_start_date = factory.Faker( @@ -662,7 +370,7 @@ class Meta: def create_payment_verification_plan_with_status( - cash_plan: Union[CashPlan, PaymentPlan], + payment_plan: PaymentPlan, user: "User", business_area: BusinessArea, program: Program, @@ -671,11 +379,10 @@ def create_payment_verification_plan_with_status( verification_channel: Optional[str] = None, create_failed_payments: bool = False, ) -> PaymentVerificationPlan: - if not cash_plan.payment_verification_summary.exists(): - PaymentVerificationSummary.objects.create( - payment_plan_obj=cash_plan, - ) - payment_verification_plan = PaymentVerificationPlanFactory(payment_plan_obj=cash_plan) + if not hasattr(payment_plan, "payment_verification_summary"): + PaymentVerificationSummary.objects.create(payment_plan=payment_plan) + + payment_verification_plan = PaymentVerificationPlanFactory(payment_plan=payment_plan) payment_verification_plan.status = status if verification_channel: payment_verification_plan.verification_channel = verification_channel @@ -695,39 +402,34 @@ def create_payment_verification_plan_with_status( household.programs.add(program) - currency = getattr(cash_plan, "currency", None) + currency = getattr(payment_plan, "currency", None) if currency is None: currency = "PLN" - if isinstance(cash_plan, CashPlan): - payment_record = PaymentRecordFactory( - parent=cash_plan, household=household, target_population=target_population, currency=currency - ) - else: - additional_args = {} - if create_failed_payments: # create only two failed Payments - if n == 2: - additional_args = { - "delivered_quantity": to_decimal(0), - "delivered_quantity_usd": to_decimal(0), - "status": Payment.STATUS_NOT_DISTRIBUTED, - } - if n == 3: - additional_args = { - "delivered_quantity": None, - "delivered_quantity_usd": None, - "status": Payment.STATUS_ERROR, - } - payment_record = PaymentFactory( - parent=cash_plan, - household=household, - currency=currency, - **additional_args, - ) + additional_args = {} + if create_failed_payments: # create only two failed Payments + if n == 2: + additional_args = { + "delivered_quantity": to_decimal(0), + "delivered_quantity_usd": to_decimal(0), + "status": Payment.STATUS_NOT_DISTRIBUTED, + } + if n == 3: + additional_args = { + "delivered_quantity": None, + "delivered_quantity_usd": None, + "status": Payment.STATUS_ERROR, + } + payment_record = PaymentFactory( + parent=payment_plan, + household=household, + currency=currency, + **additional_args, + ) pv = PaymentVerificationFactory( payment_verification_plan=payment_verification_plan, - payment_obj=payment_record, + payment=payment_record, status=PaymentVerification.STATUS_PENDING, ) pv.set_pending() @@ -736,51 +438,6 @@ def create_payment_verification_plan_with_status( return payment_verification_plan -def generate_real_cash_plans() -> None: - if ServiceProvider.objects.count() < 3: - ServiceProviderFactory.create_batch(3) - program = Program.objects.filter(name="Test Program").first() or RealProgramFactory(status=Program.ACTIVE) - cash_plans = RealCashPlanFactory.create_batch(3, program=program) - for cash_plan in cash_plans: - generate_payment_verification_plan_with_status = choice([True, False, False]) - targeting_criteria = TargetingCriteriaFactory() - - rule = TargetingCriteriaRule.objects.create(targeting_criteria=targeting_criteria) - TargetingCriteriaRuleFilter.objects.create( - targeting_criteria_rule=rule, comparison_method="EQUALS", field_name="residence_status", arguments=[REFUGEE] - ) - target_population = TargetPopulationFactory( - program=program, - status=TargetPopulation.STATUS_OPEN, - targeting_criteria=targeting_criteria, - ) - full_rebuild(target_population) - target_population.status = TargetPopulation.STATUS_READY_FOR_CASH_ASSIST - target_population.save() - RealPaymentRecordFactory.create_batch( - 5, - target_population=target_population, - parent=cash_plan, - ) - - if generate_payment_verification_plan_with_status: - root = User.objects.get(username="root") - create_payment_verification_plan_with_status( - cash_plan, - root, - cash_plan.business_area, - target_population.program, - target_population, - PaymentVerificationPlan.STATUS_ACTIVE, - ) - - program.households.set( - PaymentRecord.objects.exclude(status=PaymentRecord.STATUS_ERROR) - .filter(parent__in=cash_plans) - .values_list("household__id", flat=True) - ) - - def generate_reconciled_payment_plan() -> None: afghanistan = BusinessArea.objects.get(slug="afghanistan") root = User.objects.get(username="root") @@ -797,7 +454,6 @@ def generate_reconciled_payment_plan() -> None: status_date=now, status=PaymentPlan.Status.ACCEPTED, created_by=root, - program=tp.program, program_cycle=tp.program.cycles.first(), total_delivered_quantity=999, total_entitled_quantity=2999, @@ -974,7 +630,6 @@ def generate_payment_plan() -> None: dispersion_end_date=now + timedelta(days=14), status_date=now, created_by=root, - program=program, program_cycle=program_cycle, )[0] diff --git a/src/hct_mis_api/apps/payment/migrations/0148_migration.py b/src/hct_mis_api/apps/payment/migrations/0148_migration.py new file mode 100644 index 0000000000..3cd5d942cd --- /dev/null +++ b/src/hct_mis_api/apps/payment/migrations/0148_migration.py @@ -0,0 +1,36 @@ +# Generated by Django 3.2.25 on 2024-09-30 09:00 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('program', '0053_migration'), + ('payment', '0147_migration'), + ] + + operations = [ + migrations.RemoveField( + model_name='financialserviceprovider', + name='delivery_mechanisms_choices', + ), + migrations.RemoveField( + model_name='payment', + name='delivery_type_choice', + ), + migrations.RemoveField( + model_name='paymentplan', + name='program', + ), + migrations.RemoveField( + model_name='paymentrecord', + name='delivery_type_choice', + ), + migrations.AlterField( + model_name='paymentplan', + name='program_cycle', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payment_plans', to='program.programcycle'), + ), + ] diff --git a/src/hct_mis_api/apps/payment/migrations/0149_migration.py b/src/hct_mis_api/apps/payment/migrations/0149_migration.py new file mode 100644 index 0000000000..3b06f5c72a --- /dev/null +++ b/src/hct_mis_api/apps/payment/migrations/0149_migration.py @@ -0,0 +1,213 @@ +# Generated by Django 3.2.25 on 2024-10-23 23:15 + +from django.db import migrations, models + + +def get_status(status: str) -> str: + mapping = {"Transaction Successful": "Distribution Successful"} + return mapping.get(status, status) + + +def migrate_cash_plan_to_payment_plan(apps, schema_editor): + # TODO TP move to external script + DeliveryMechanism = apps.get_model("payment", "DeliveryMechanism") + PaymentPlan = apps.get_model("payment", "PaymentPlan") + CashPlan = apps.get_model("payment", "CashPlan") + Payment = apps.get_model("payment", "Payment") + PaymentRecord = apps.get_model("payment", "PaymentRecord") + ServiceProvider = apps.get_model("payment", "ServiceProvider") + FinancialServiceProvider = apps.get_model("payment", "FinancialServiceProvider") + DeliveryMechanismPerPaymentPlan = apps.get_model("payment", "DeliveryMechanismPerPaymentPlan") + ContentType = apps.get_model("contenttypes", "ContentType") + + content_type_for_payment_plan = ContentType.objects.get_for_model(PaymentPlan) + content_type_for_payment = ContentType.objects.get_for_model(Payment) + + delivery_type_to_obj = {obj.name: obj for obj in DeliveryMechanism.objects.all()} + + for sp in ServiceProvider.objects.all(): + if not sp.cash_plans.exists(): + continue + + if FinancialServiceProvider.objects.filter(vision_vendor_number=sp.vision_id).exists(): + continue + + delivery_mechanisms = set(sp.cash_plans.all().values_list("delivery_type", flat=True)) + + fsp = FinancialServiceProvider.objects.create( + name=sp.full_name, + vision_vendor_number=sp.vision_id, + communication_channel="API", + internal_data={ + "is_cash_assist": True, + "business_area": sp.business_area, + "country": sp.country, + "ca_id": sp.ca_id, + "short_name": sp.short_name, + }, + ) + fsp.delivery_mechanisms.set([delivery_type_to_obj[dt] for dt in delivery_mechanisms]) + + for cp in CashPlan.objects.all(): + + if not cp.payment_items.exists(): + continue + + # get target populations from payment records + target_populations = set(cp.payment_items.values_list("target_population", flat=True)) + # for each target population create a payment plan within tp.payment_cycle + for tp in target_populations: + payment_records = cp.payment_items.filter(target_population=tp) + first_record = payment_records.first() + delivery_mechanism = delivery_type_to_obj[first_record.delivery_type] + currency = first_record.currency + + # create payment plan + + pp = PaymentPlan.objects.create( + status=PaymentPlan.Status.FINISHED, + name=tp.name, + business_area=tp.business_area, + created_by=tp.created_by, + target_population=tp, + program_cycle=tp.program_cycle, + currency=currency, + dispersion_start_date=cp.start_date, + dispersion_end_date=cp.dispersion_date, + start_date=cp.start_date or tp.program_cycle.start_date, + end_date=cp.end_date or tp.program_cycle.end_date, + status_date=cp.status_date, + exchange_rate=cp.exchange_rate, + total_entitled_quantity=cp.total_entitled_quantity, + total_entitled_quantity_usd=cp.total_entitled_quantity_usd, + total_entitled_quantity_revised=cp.total_entitled_quantity_revised, + total_entitled_quantity_revised_usd=cp.total_entitled_quantity_revised_usd, + total_delivered_quantity=cp.total_delivered_quantity, + total_delivered_quantity_usd=cp.total_delivered_quantity_usd, + total_undelivered_quantity=cp.total_undelivered_quantity, + total_undelivered_quantity_usd=cp.total_undelivered_quantity_usd, + unicef_id=cp.ca_id, + internal_data={ + "is_cash_assist": True, + "name": cp.name, + "ca_hash_id": cp.ca_hash_id, + "distribution_level": cp.distribution_level, + "coverage_duration": cp.coverage_duration, + "coverage_unit": cp.coverage_unit, + "comments": cp.comments, + "assistance_measurement": cp.assistance_measurement, + "assistance_through": cp.assistance_through, + "vision_id": cp.vision_id, + "funds_commitment": cp.funds_commitment, + "down_payment": cp.down_payment, + "validation_alerts_count": cp.validation_alerts_count, + "total_persons_covered": cp.total_persons_covered, + "total_persons_covered_revised": cp.total_persons_covered_revised, + }, + ) + + DeliveryMechanismPerPaymentPlan.objects.update_or_create( + payment_plan=pp, + delivery_mechanism=delivery_mechanism, + sent_date=cp.status_date, + delivery_mechanism_order=1, + created_by=tp.created_by, + financial_service_provider=FinancialServiceProvider.objects.get( + vision_vendor_number=cp.service_provider.vision_id + ), + ) + + # migrate payment verification summary, payment verification plans + + if payment_verification_summary := cp.payment_verification_summary.first(): + payment_verification_summary.payment_plan_content_type_id = content_type_for_payment_plan.id + payment_verification_summary.payment_plan_object_id = pp.id + payment_verification_summary.save() + + if payment_verification_plan := cp.payment_verification_plan.first(): + payment_verification_plan.payment_plan_content_type_id = content_type_for_payment_plan.id + payment_verification_plan.payment_plan_object_id = pp.id + payment_verification_plan.save() + + for record in cp.payment_items.filter(target_population=tp): + payment = Payment.objects.create( + unicef_id=record.ca_id, + parent=pp, + business_area=pp.business_area, + status=get_status(record.status), + status_date=record.status_date, + household=record.household, + head_of_household=record.head_of_household, + collector=record.head_of_household, + delivery_type=record.delivery_type, + currency=record.currency, + entitlement_quantity=record.entitlement_quantity, + entitlement_quantity_usd=record.entitlement_quantity_usd, + delivered_quantity=record.delivered_quantity, + delivered_quantity_usd=record.delivered_quantity_usd, + delivery_date=record.delivery_date, + transaction_reference_id=record.transaction_reference_id, + transaction_status_blockchain_link=record.transaction_status_blockchain_link, + financial_service_provider=FinancialServiceProvider.objects.get( + vision_vendor_number=record.service_provider.vision_id + ), + program=tp.program_cycle.program, + internal_data={ + "ca_hash_id": record.ca_hash_id, + "full_name": record.full_name, + "total_persons_covered": record.total_persons_covered, + "distribution_modality": record.distribution_modality, + "target_population_cash_assist_id": record.target_population_cash_assist_id, + "target_population": record.target_population_id, + "entitlement_card_number": record.entitlement_card_number, + "entitlement_card_status": record.entitlement_card_status, + "entitlement_card_issue_date": record.entitlement_card_issue_date, + "vision_id": record.vision_id, + "registration_ca_id": record.registration_ca_id, + "service_provider": record.service_provider_id, + }, + ) + + if verification := record.payment_record_verification.first(): + verification.payment_content_type_id = content_type_for_payment.id + verification.payment_object_id = payment.id + verification.save() + + if ticket_complaint_details := record.ticket_complaint_details.first(): + ticket_complaint_details.payment_content_type_id = content_type_for_payment.id + ticket_complaint_details.payment_object_id = payment.id + ticket_complaint_details.save() + + if ticket_sensitive_details := record.ticket_sensitive_details.first(): + ticket_sensitive_details.payment_content_type_id = content_type_for_payment.id + ticket_sensitive_details.payment_object_id = payment.id + ticket_sensitive_details.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("payment", "0148_migration"), + ] + + operations = [ + migrations.AddField( + model_name="paymentplan", + name="internal_data", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="payment", + name="internal_data", + field=models.JSONField(default=dict), + ), + migrations.AddField( + model_name="financialserviceprovider", + name="internal_data", + field=models.JSONField(default=dict), + ), + migrations.RunPython( + migrate_cash_plan_to_payment_plan, + migrations.RunPython.noop, + ), + ] diff --git a/src/hct_mis_api/apps/payment/migrations/0150_migration.py b/src/hct_mis_api/apps/payment/migrations/0150_migration.py new file mode 100644 index 0000000000..0510437510 --- /dev/null +++ b/src/hct_mis_api/apps/payment/migrations/0150_migration.py @@ -0,0 +1,106 @@ +# Generated by Django 3.2.25 on 2024-09-30 09:00 + +from django.db import migrations, models + + +def migrate_payment_verification_plan_generic_foreign_key_to_foreign_key(apps, schema_editor): + PaymentVerificationPlan = apps.get_model("payment", "PaymentVerificationPlan") + PaymentPlan = apps.get_model("payment", "PaymentPlan") + ContentType = apps.get_model("contenttypes", "ContentType") + + verification_plans_to_update = [] + for verification_plan in PaymentVerificationPlan.objects.exclude( + payment_plan_content_type__isnull=True, payment_plan_object_id__isnull=True + ): + if verification_plan.payment_plan_content_type.model == "paymentplan": + payment_plan = PaymentPlan.objects.get(id=verification_plan.payment_plan_object_id) + verification_plan.payment_plan = payment_plan + verification_plans_to_update.append(verification_plan) + + PaymentVerificationPlan.objects.bulk_update(verification_plans_to_update, ["payment_plan"]) + + +def migrate_payment_verification_summary_generic_foreign_key_to_onetoone(apps, schema_editor): + PaymentVerificationSummary = apps.get_model("payment", "PaymentVerificationSummary") + PaymentPlan = apps.get_model("payment", "PaymentPlan") + ContentType = apps.get_model("contenttypes", "ContentType") + + verification_summaries_to_update = [] + for verification_summary in PaymentVerificationSummary.objects.exclude( + payment_plan_content_type__isnull=True, payment_plan_object_id__isnull=True + ): + if verification_summary.payment_plan_content_type.model == "paymentplan": + related_instance = PaymentPlan.objects.get(id=verification_summary.payment_plan_object_id) + verification_summary.payment_plan = related_instance + verification_summaries_to_update.append(verification_summary) + + PaymentVerificationSummary.objects.bulk_update(verification_summaries_to_update, ["payment_plan"]) + + +def migrate_payment_verification_generic_foreign_key_to_onetoone(apps, schema_editor): + PaymentVerification = apps.get_model("payment", "PaymentVerification") + Payment = apps.get_model("payment", "Payment") + ContentType = apps.get_model("contenttypes", "ContentType") + + verifications_to_update = [] + for verification in PaymentVerification.objects.exclude( + payment_content_type__isnull=True, payment_object_id__isnull=True + ): + if verification.payment_content_type.model == "payment": + related_instance = Payment.objects.get(id=verification.payment_object_id) + verification.payment = related_instance + verifications_to_update.append(verification) + + PaymentVerification.objects.bulk_update(verifications_to_update, ["payment"]) + + +class Migration(migrations.Migration): + + dependencies = [ + ("payment", "0149_migration"), + ] + + operations = [ + migrations.AddField( + model_name="paymentverificationplan", + name="payment_plan", + field=models.ForeignKey( + to="payment.PaymentPlan", + null=True, # Temporarily allow nulls for migration purposes + on_delete=models.CASCADE, + related_name="payment_verification_plans", + ), + ), + migrations.RunPython( + migrate_payment_verification_plan_generic_foreign_key_to_foreign_key, + migrations.RunPython.noop, + ), + migrations.AddField( + model_name="paymentverificationsummary", + name="payment_plan", + field=models.OneToOneField( + to="payment.PaymentPlan", + null=True, # Temporarily allow nulls for migration purposes + on_delete=models.CASCADE, + related_name="payment_verification_summary", + ), + ), + migrations.RunPython( + migrate_payment_verification_summary_generic_foreign_key_to_onetoone, + migrations.RunPython.noop, + ), + migrations.AddField( + model_name="paymentverification", + name="payment", + field=models.OneToOneField( + to="payment.Payment", + null=True, # Temporarily allow nulls for migration purposes + on_delete=models.CASCADE, + related_name="payment_verification", + ), + ), + migrations.RunPython( + migrate_payment_verification_generic_foreign_key_to_onetoone, + migrations.RunPython.noop, + ), + ] diff --git a/src/hct_mis_api/apps/payment/migrations/0151_migration.py b/src/hct_mis_api/apps/payment/migrations/0151_migration.py new file mode 100644 index 0000000000..a9dd5db8c0 --- /dev/null +++ b/src/hct_mis_api/apps/payment/migrations/0151_migration.py @@ -0,0 +1,45 @@ +# Generated by Django 3.2.25 on 2024-10-31 12:46 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('payment', '0150_migration'), + ] + + operations = [ + migrations.AlterField( + model_name='paymentverification', + name='payment_content_type', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='paymentverification', + name='payment_object_id', + field=models.UUIDField(null=True), + ), + migrations.AlterField( + model_name='paymentverificationplan', + name='payment_plan_content_type', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='paymentverificationplan', + name='payment_plan_object_id', + field=models.UUIDField(null=True), + ), + migrations.AlterField( + model_name='paymentverificationsummary', + name='payment_plan_content_type', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='paymentverificationsummary', + name='payment_plan_object_id', + field=models.UUIDField(null=True), + ), + ] diff --git a/src/hct_mis_api/apps/payment/models.py b/src/hct_mis_api/apps/payment/models.py index 11033fe011..8ffe6a70cf 100644 --- a/src/hct_mis_api/apps/payment/models.py +++ b/src/hct_mis_api/apps/payment/models.py @@ -48,7 +48,6 @@ from multiselectfield import MultiSelectField from psycopg2._range import NumericRange -from hct_mis_api.apps.account.models import HorizontalChoiceArrayField from hct_mis_api.apps.activity_log.utils import create_mapping_dict from hct_mis_api.apps.core.currencies import CURRENCY_CHOICES, USDC from hct_mis_api.apps.core.exchange_rates import ExchangeRates @@ -76,6 +75,7 @@ from hct_mis_api.apps.utils.models import ( AdminUrlMixin, ConcurrencyModel, + InternalDataFieldModel, MergedManager, MergeStatusModel, PendingManager, @@ -184,12 +184,10 @@ class Meta: @property def get_unicef_id(self) -> str: - # TODO: maybe 'ca_id' rename to 'unicef_id'? return self.ca_id if isinstance(self, CashPlan) else self.unicef_id def get_exchange_rate(self, exchange_rates_client: Optional["ExchangeRateClient"] = None) -> float: if self.currency == USDC: - # TODO: is it good place for that? # exchange rate for Digital currency return 1.0 @@ -296,9 +294,6 @@ class GenericPayment(TimeStampedUUIDModel): status_date = models.DateTimeField() household = models.ForeignKey("household.Household", on_delete=models.CASCADE) head_of_household = models.ForeignKey("household.Individual", on_delete=models.CASCADE, null=True) - delivery_type_choice = models.CharField( - choices=DeliveryMechanismChoices.DELIVERY_TYPE_CHOICES, max_length=32, null=True - ) # TODO MB drop later delivery_type = models.ForeignKey("payment.DeliveryMechanism", on_delete=models.SET_NULL, null=True) currency = models.CharField( max_length=4, @@ -431,7 +426,14 @@ def delivery_mechanism(self) -> Optional[str]: return self.payment_plan.delivery_mechanisms.first().delivery_mechanism -class PaymentPlan(ConcurrencyModel, SoftDeletableModel, GenericPaymentPlan, UnicefIdentifiedModel, AdminUrlMixin): +class PaymentPlan( + TimeStampedUUIDModel, + InternalDataFieldModel, + ConcurrencyModel, + SoftDeletableModel, + UnicefIdentifiedModel, + AdminUrlMixin, +): ACTIVITY_LOG_MAPPING = create_mapping_dict( [ "status", @@ -453,6 +455,26 @@ class PaymentPlan(ConcurrencyModel, SoftDeletableModel, GenericPaymentPlan, Unic ] ) + # class Status(models.TextChoices): + # TP_OPEN = "OPEN" + # TP_LOCKED = "LOCKED" + # TP_PROCESSING = "PROCESSING" + # TP_STEFICON_WAIT = "STEFICON_WAIT" + # TP_STEFICON_RUN = "STEFICON_RUN" + # TP_STEFICON_COMPLETED = "STEFICON_COMPLETED" + # TP_STEFICON_ERROR = "STEFICON_ERROR" + # + # DRAFT = "DRAFT" + # PREPARING = "PREPARING", "Preparing" + # OPEN = "OPEN", "Open" + # LOCKED = "LOCKED", "Locked" + # LOCKED_FSP = "LOCKED_FSP", "Locked FSP" + # IN_APPROVAL = "IN_APPROVAL", "In Approval" + # IN_AUTHORIZATION = "IN_AUTHORIZATION", "In Authorization" + # IN_REVIEW = "IN_REVIEW", "In Review" + # ACCEPTED = "ACCEPTED", "Accepted" + # FINISHED = "FINISHED", "Finished" + class Status(models.TextChoices): PREPARING = "PREPARING", "Preparing" OPEN = "OPEN", "Open" @@ -498,9 +520,72 @@ class Action(models.TextChoices): FINISH = "FINISH", "Finish" SEND_TO_PAYMENT_GATEWAY = "SEND_TO_PAYMENT_GATEWAY", "Send to Payment Gateway" - program_cycle = models.ForeignKey( - "program.ProgramCycle", related_name="payment_plans", null=True, blank=True, on_delete=models.CASCADE + usd_fields = [ + "total_entitled_quantity_usd", + "total_entitled_quantity_revised_usd", + "total_delivered_quantity_usd", + "total_undelivered_quantity_usd", + ] + + business_area = models.ForeignKey("core.BusinessArea", on_delete=models.CASCADE) + status_date = models.DateTimeField() + start_date = models.DateTimeField( + db_index=True, + blank=True, + null=True, + ) + end_date = models.DateTimeField( + db_index=True, + blank=True, + null=True, + ) + exchange_rate = models.DecimalField(decimal_places=8, blank=True, null=True, max_digits=14) + + total_entitled_quantity = models.DecimalField( + decimal_places=2, + max_digits=12, + validators=[MinValueValidator(Decimal("0"))], + db_index=True, + null=True, + ) + total_entitled_quantity_usd = models.DecimalField( + decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal("0"))], null=True, blank=True ) + total_entitled_quantity_revised = models.DecimalField( + decimal_places=2, + max_digits=12, + validators=[MinValueValidator(Decimal("0"))], + db_index=True, + null=True, + blank=True, + ) + total_entitled_quantity_revised_usd = models.DecimalField( + decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal("0"))], null=True, blank=True + ) + total_delivered_quantity = models.DecimalField( + decimal_places=2, + max_digits=12, + validators=[MinValueValidator(Decimal("0"))], + db_index=True, + null=True, + blank=True, + ) + total_delivered_quantity_usd = models.DecimalField( + decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal("0"))], null=True, blank=True + ) + total_undelivered_quantity = models.DecimalField( + decimal_places=2, + max_digits=12, + validators=[MinValueValidator(Decimal("0"))], + db_index=True, + null=True, + blank=True, + ) + total_undelivered_quantity_usd = models.DecimalField( + decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal("0"))], null=True, blank=True + ) + + program_cycle = models.ForeignKey("program.ProgramCycle", related_name="payment_plans", on_delete=models.CASCADE) created_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.PROTECT, @@ -548,18 +633,22 @@ class Action(models.TextChoices): blank=True, ) steficon_applied_date = models.DateTimeField(blank=True, null=True) - payment_verification_summary = GenericRelation( - "payment.PaymentVerificationSummary", - content_type_field="payment_plan_content_type", - object_id_field="payment_plan_object_id", - related_query_name="payment_plan", - ) - payment_verification_plan = GenericRelation( - "payment.PaymentVerificationPlan", - content_type_field="payment_plan_content_type", - object_id_field="payment_plan_object_id", - related_query_name="payment_plan", - ) + + # # TODO TP DROP + # payment_verification_summary = GenericRelation( + # "payment.PaymentVerificationSummary", + # content_type_field="payment_plan_content_type", + # object_id_field="payment_plan_object_id", + # related_query_name="payment_plan", + # ) + # # TODO TP DROP + # payment_verification_plan = GenericRelation( + # "payment.PaymentVerificationPlan", + # content_type_field="payment_plan_content_type", + # object_id_field="payment_plan_object_id", + # related_query_name="payment_plan", + # ) + source_payment_plan = models.ForeignKey( "self", null=True, blank=True, on_delete=models.CASCADE, related_name="follow_ups" ) @@ -811,10 +900,8 @@ def status_mark_as_reviewed(self) -> None: def status_finished(self) -> None: self.status_date = timezone.now() - if not self.payment_verification_summary.exists(): - PaymentVerificationSummary.objects.create( - payment_plan_obj=self, - ) + if not hasattr(self, "payment_verification_summary"): + PaymentVerificationSummary.objects.create(payment_plan=self) @transition( field=status, @@ -944,7 +1031,6 @@ def imported_file_name(self) -> str: @property def is_reconciled(self) -> bool: - # TODO what in case of active grievance tickets? if not self.eligible_payments.exists(): return False @@ -1014,7 +1100,7 @@ def unsuccessful_payments(self) -> "QuerySet": status__in=[ Payment.STATUS_ERROR, # delivered_quantity < 0 (-1) Payment.STATUS_NOT_DISTRIBUTED, # delivered_quantity == 0 - Payment.STATUS_FORCE_FAILED, # TODO remove force failed? + Payment.STATUS_FORCE_FAILED, ] ) @@ -1045,9 +1131,8 @@ def payments_used_in_follow_payment_plans(self) -> "QuerySet": return Payment.objects.filter(parent__source_payment_plan_id=self.id, excluded=False) @property - def get_program(self) -> "Program": - # TODO will update after add feature with 'program_cycle' and migrate all data - return self.program_cycle.program if self.program_cycle else self.program + def program(self) -> "Program": + return self.program_cycle.program def _get_last_approval_process_data(self) -> ModifiedData: approval_process = hasattr(self, "approval_process") and self.approval_process.first() @@ -1103,6 +1188,45 @@ def can_send_to_payment_gateway(self) -> bool: ).exists() ) + # from generic pp + def get_exchange_rate(self, exchange_rates_client: Optional["ExchangeRateClient"] = None) -> float: + if self.currency == USDC: + # exchange rate for Digital currency USDC to USD + return 1.0 + + if exchange_rates_client is None: + exchange_rates_client = ExchangeRates() + + return exchange_rates_client.get_exchange_rate_for_currency_code(self.currency, self.currency_exchange_date) + + def available_payment_records( + self, + payment_verification_plan: Optional["PaymentVerificationPlan"] = None, + extra_validation: Optional[Callable] = None, + ) -> QuerySet: + params = Q(status__in=GenericPayment.ALLOW_CREATE_VERIFICATION, delivered_quantity__gt=0) + + if payment_verification_plan: + params &= Q( + Q(payment_verification__isnull=True) + | Q(payment_verification__payment_verification_plan=payment_verification_plan) + ) + else: + params &= Q(payment_verification__isnull=True) + + payment_records = self.payment_items.select_related("head_of_household").filter(params).distinct() + + if extra_validation: + payment_records = list(map(lambda pr: pr.pk, filter(extra_validation, payment_records))) + + qs = Payment.objects.filter(pk__in=payment_records) + + return qs + + @property + def can_create_payment_verification_plan(self) -> int: + return self.available_payment_records().count() > 0 + class FlexFieldArrayField(ArrayField): def formfield(self, form_class: Optional[Any] = ..., choices_form_class: Optional[Any] = ..., **kwargs: Any) -> Any: @@ -1402,7 +1526,7 @@ def __str__(self) -> str: return f"{self.financial_service_provider.name} - {self.xlsx_template} - {self.delivery_mechanism}" # pragma: no cover -class FinancialServiceProvider(LimitBusinessAreaModelMixin, TimeStampedUUIDModel): +class FinancialServiceProvider(InternalDataFieldModel, LimitBusinessAreaModelMixin, TimeStampedUUIDModel): COMMUNICATION_CHANNEL_API = "API" COMMUNICATION_CHANNEL_SFTP = "SFTP" COMMUNICATION_CHANNEL_XLSX = "XLSX" @@ -1422,9 +1546,6 @@ class FinancialServiceProvider(LimitBusinessAreaModelMixin, TimeStampedUUIDModel ) name = models.CharField(max_length=100, unique=True) vision_vendor_number = models.CharField(max_length=100, unique=True) - delivery_mechanisms_choices = HorizontalChoiceArrayField( - models.CharField(choices=DeliveryMechanismChoices.DELIVERY_TYPE_CHOICES, max_length=32), null=True - ) # TODO MB drop later delivery_mechanisms = models.ManyToManyField("payment.DeliveryMechanism") distribution_limit = models.DecimalField( decimal_places=2, @@ -1644,7 +1765,6 @@ def currency_exchange_date(self) -> datetime: return self.dispersion_date def unicef_id(self) -> str: - # TODO: maybe 'ca_id' rename to 'unicef_id'? return self.ca_id @property @@ -1708,7 +1828,6 @@ class PaymentRecord(ConcurrencyModel, AdminUrlMixin, GenericPayment): object_id_field="payment_object_id", related_query_name="payment_record", ) - ticket_sensitive_details = GenericRelation( "grievance.TicketSensitiveDetails", content_type_field="payment_content_type", @@ -1724,7 +1843,125 @@ def get_revert_mark_as_failed_status(self, delivered_quantity: Decimal) -> str: return self.STATUS_SUCCESS -class Payment(SoftDeletableModel, GenericPayment, UnicefIdentifiedModel, AdminUrlMixin, SignatureMixin): +class Payment( + TimeStampedUUIDModel, + InternalDataFieldModel, + SoftDeletableModel, + UnicefIdentifiedModel, + AdminUrlMixin, + SignatureMixin, +): + # GenericPayment fields + + usd_fields = ["delivered_quantity_usd", "entitlement_quantity_usd"] + + STATUS_SUCCESS = "Transaction Successful" + STATUS_ERROR = "Transaction Erroneous" + STATUS_DISTRIBUTION_SUCCESS = "Distribution Successful" + STATUS_NOT_DISTRIBUTED = "Not Distributed" + STATUS_FORCE_FAILED = "Force failed" + STATUS_DISTRIBUTION_PARTIAL = "Partially Distributed" + STATUS_PENDING = "Pending" + # Payment Gateway statuses + STATUS_SENT_TO_PG = "Sent to Payment Gateway" + STATUS_SENT_TO_FSP = "Sent to FSP" + STATUS_MANUALLY_CANCELLED = "Manually Cancelled" + + STATUS_CHOICE = ( + (STATUS_DISTRIBUTION_SUCCESS, _("Distribution Successful")), # Delivered Fully + (STATUS_NOT_DISTRIBUTED, _("Not Distributed")), # Not Delivered + (STATUS_SUCCESS, _("Transaction Successful")), # Delivered Fully + (STATUS_ERROR, _("Transaction Erroneous")), # Unsuccessful + (STATUS_FORCE_FAILED, _("Force failed")), # Force Failed + (STATUS_DISTRIBUTION_PARTIAL, _("Partially Distributed")), # Delivered Partially + (STATUS_PENDING, _("Pending")), # Pending + (STATUS_SENT_TO_PG, _("Sent to Payment Gateway")), + (STATUS_SENT_TO_FSP, _("Sent to FSP")), + (STATUS_MANUALLY_CANCELLED, _("Manually Cancelled")), + ) + + ALLOW_CREATE_VERIFICATION = (STATUS_SUCCESS, STATUS_DISTRIBUTION_SUCCESS, STATUS_DISTRIBUTION_PARTIAL) + PENDING_STATUSES = (STATUS_PENDING, STATUS_SENT_TO_PG, STATUS_SENT_TO_FSP) + + ENTITLEMENT_CARD_STATUS_ACTIVE = "ACTIVE" + ENTITLEMENT_CARD_STATUS_INACTIVE = "INACTIVE" + ENTITLEMENT_CARD_STATUS_CHOICE = Choices( + (ENTITLEMENT_CARD_STATUS_ACTIVE, _("Active")), + (ENTITLEMENT_CARD_STATUS_INACTIVE, _("Inactive")), + ) + + business_area = models.ForeignKey("core.BusinessArea", on_delete=models.CASCADE) + status = models.CharField( + max_length=255, + choices=STATUS_CHOICE, + default=STATUS_PENDING, + ) + status_date = models.DateTimeField() + household = models.ForeignKey("household.Household", on_delete=models.CASCADE) + head_of_household = models.ForeignKey("household.Individual", on_delete=models.CASCADE, null=True) + delivery_type = models.ForeignKey("payment.DeliveryMechanism", on_delete=models.SET_NULL, null=True) + currency = models.CharField( + max_length=4, + ) + entitlement_quantity = models.DecimalField( + decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal("0.00"))], null=True, blank=True + ) + entitlement_quantity_usd = models.DecimalField( + decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal("0.00"))], null=True, blank=True + ) + delivered_quantity = models.DecimalField( + decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal("0.00"))], null=True, blank=True + ) + delivered_quantity_usd = models.DecimalField( + decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal("0.00"))], null=True, blank=True + ) + delivery_date = models.DateTimeField(null=True, blank=True) + transaction_reference_id = models.CharField(max_length=255, null=True, blank=True) # transaction_id + transaction_status_blockchain_link = models.CharField(max_length=255, null=True, blank=True) + + def mark_as_failed(self) -> None: + if self.status is self.STATUS_FORCE_FAILED: + raise ValidationError("Status shouldn't be failed") + self.status = self.STATUS_FORCE_FAILED + self.status_date = timezone.now() + self.delivered_quantity = 0 + self.delivered_quantity_usd = 0 + self.delivery_date = None + + def revert_mark_as_failed(self, delivered_quantity: Decimal, delivery_date: datetime) -> None: + if self.status != self.STATUS_FORCE_FAILED: + raise ValidationError("Only payment marked as force failed can be reverted") + if self.entitlement_quantity is None: + raise ValidationError("Entitlement quantity need to be set in order to revert") + + self.status = self.get_revert_mark_as_failed_status(delivered_quantity) + self.status_date = timezone.now() + self.delivered_quantity = delivered_quantity + self.delivery_date = delivery_date + + @property + def payment_status(self) -> str: + status = "-" + if self.status == GenericPayment.STATUS_PENDING: + status = "Pending" + + elif self.status in (GenericPayment.STATUS_DISTRIBUTION_SUCCESS, GenericPayment.STATUS_SUCCESS): + status = "Delivered Fully" + + elif self.status == GenericPayment.STATUS_DISTRIBUTION_PARTIAL: + status = "Delivered Partially" + + elif self.status == GenericPayment.STATUS_NOT_DISTRIBUTED: + status = "Not Delivered" + + elif self.status == GenericPayment.STATUS_ERROR: + status = "Unsuccessful" + + elif self.status == GenericPayment.STATUS_FORCE_FAILED: + status = "Force Failed" + + return status + parent = models.ForeignKey( "payment.PaymentPlan", on_delete=models.CASCADE, @@ -1737,12 +1974,14 @@ class Payment(SoftDeletableModel, GenericPayment, UnicefIdentifiedModel, AdminUr "payment.FinancialServiceProvider", on_delete=models.PROTECT, null=True ) collector = models.ForeignKey("household.Individual", on_delete=models.CASCADE, related_name="collector_payments") - payment_verification = GenericRelation( - "payment.PaymentVerification", - content_type_field="payment_content_type", - object_id_field="payment_object_id", - related_query_name="payment", - ) + + # # TODO TP DROP + # payment_verification = GenericRelation( + # "payment.PaymentVerification", + # content_type_field="payment_content_type", + # object_id_field="payment_object_id", + # related_query_name="payment", + # ) source_payment = models.ForeignKey( "self", null=True, blank=True, on_delete=models.CASCADE, related_name="follow_ups" @@ -1765,19 +2004,21 @@ class Payment(SoftDeletableModel, GenericPayment, UnicefIdentifiedModel, AdminUr null=True, validators=[MinValueValidator(1000000), MaxValueValidator(9999999), payment_token_and_order_number_validator], ) # 7 digits - ticket_complaint_details = GenericRelation( - "grievance.TicketComplaintDetails", - content_type_field="payment_content_type", - object_id_field="payment_object_id", - related_query_name="payment", - ) - ticket_sensitive_details = GenericRelation( - "grievance.TicketSensitiveDetails", - content_type_field="payment_content_type", - object_id_field="payment_object_id", - related_query_name="payment", - ) + # # TODO TP DROP + # ticket_complaint_details = GenericRelation( + # "grievance.TicketComplaintDetails", + # content_type_field="payment_content_type", + # object_id_field="payment_object_id", + # related_query_name="payment", + # ) + # ticket_sensitive_details = GenericRelation( + # "grievance.TicketSensitiveDetails", + # content_type_field="payment_content_type", + # object_id_field="payment_object_id", + # related_query_name="payment", + # ) + additional_collector_name = models.CharField( max_length=64, blank=True, @@ -1924,11 +2165,18 @@ class PaymentVerificationPlan(TimeStampedUUIDModel, ConcurrencyModel, UnicefIden (VERIFICATION_CHANNEL_XLSX, "XLSX"), ) status = models.CharField(max_length=50, choices=STATUS_CHOICES, default=STATUS_PENDING, db_index=True) - payment_plan_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) - payment_plan_object_id = UUIDField() + + # TODO TP DROP + payment_plan_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True) + payment_plan_object_id = UUIDField(null=True) payment_plan_obj: "Union[PaymentPlan, CashPlan]" = GenericForeignKey( "payment_plan_content_type", "payment_plan_object_id" ) # type: ignore + + payment_plan = models.ForeignKey( + "payment.PaymentPlan", on_delete=models.CASCADE, related_name="payment_verification_plans", null=True + ) + sampling = models.CharField(max_length=50, choices=SAMPLING_CHOICES) verification_channel = models.CharField(max_length=50, choices=VERIFICATION_CHANNEL_CHOICES) sample_size = models.PositiveIntegerField(null=True, blank=True) @@ -1951,13 +2199,14 @@ class PaymentVerificationPlan(TimeStampedUUIDModel, ConcurrencyModel, UnicefIden class Meta: ordering = ("created_at",) + # TODO TP DROP indexes = [ models.Index(fields=["payment_plan_content_type", "payment_plan_object_id"]), ] @property def business_area(self) -> BusinessArea: - return self.payment_plan_obj.business_area + return self.payment_plan.business_area @property def get_xlsx_verification_file(self) -> FileTemp: @@ -2006,33 +2255,18 @@ def can_activate(self) -> bool: PaymentVerificationPlan.STATUS_RAPID_PRO_ERROR, ) - @property - def get_payment_plan(self) -> Union["PaymentPlan", "CashPlan", None]: - try: - # use GFK instead of self.payment_plan_content_type.model_class().objects.get(pk=self.payment_plan_object_id) - return self.payment_plan_obj - except ObjectDoesNotExist: - return None - @property def get_program(self) -> Optional["Program"]: - if payment_plan := self.get_payment_plan: - program = ( - payment_plan.program_cycle.program - if isinstance(payment_plan, PaymentPlan) and payment_plan.program_cycle - else payment_plan.program - ) - return program - return None + return self.payment_plan.program_cycle.program def build_summary(payment_plan: Optional[Any]) -> None: - statuses_count = payment_plan.get_payment_verification_plans.aggregate( + statuses_count = payment_plan.payment_verification_plans.aggregate( active=Count("pk", filter=Q(status=PaymentVerificationSummary.STATUS_ACTIVE)), pending=Count("pk", filter=Q(status=PaymentVerificationSummary.STATUS_PENDING)), finished=Count("pk", filter=Q(status=PaymentVerificationSummary.STATUS_FINISHED)), ) - summary = payment_plan.get_payment_verification_summary + summary = payment_plan.payment_verification_summary if statuses_count["active"] >= 1: summary.mark_as_active() elif statuses_count["finished"] >= 1 and statuses_count["active"] == 0 and statuses_count["pending"] == 0: @@ -2051,7 +2285,7 @@ def build_summary(payment_plan: Optional[Any]) -> None: dispatch_uid="update_verification_status_in_cash_plan", ) def update_verification_status_in_cash_plan(sender: Any, instance: PaymentVerificationPlan, **kwargs: Any) -> None: - build_summary(instance.payment_plan_obj) + build_summary(instance.payment_plan) @receiver( @@ -2062,7 +2296,7 @@ def update_verification_status_in_cash_plan(sender: Any, instance: PaymentVerifi def update_verification_status_in_cash_plan_on_delete( sender: Any, instance: PaymentVerificationPlan, **kwargs: Any ) -> None: - build_summary(instance.payment_plan_obj) + build_summary(instance.payment_plan) class PaymentVerification(TimeStampedUUIDModel, ConcurrencyModel, AdminUrlMixin): @@ -2089,9 +2323,19 @@ class PaymentVerification(TimeStampedUUIDModel, ConcurrencyModel, AdminUrlMixin) on_delete=models.CASCADE, related_name="payment_record_verifications", ) - payment_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) - payment_object_id = UUIDField() + + # TODO TP DROP + payment_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True) + payment_object_id = UUIDField(null=True) payment_obj = GenericForeignKey("payment_content_type", "payment_object_id") + + payment = models.OneToOneField( + "payment.Payment", + on_delete=models.CASCADE, + related_name="payment_verification", + null=True, + ) + status = models.CharField(max_length=50, choices=STATUS_CHOICES, default=STATUS_PENDING) status_date = models.DateTimeField(null=True) received_amount = models.DecimalField( @@ -2129,7 +2373,7 @@ def is_manually_editable(self) -> bool: @property def business_area(self) -> BusinessArea: - return self.payment_verification_plan.payment_plan_obj.business_area + return self.payment_verification_plan.payment_plan.business_area def set_pending(self) -> None: self.status_date = timezone.now() @@ -2151,11 +2395,21 @@ class PaymentVerificationSummary(TimeStampedUUIDModel): ) activation_date = models.DateTimeField(null=True) completion_date = models.DateTimeField(null=True) - payment_plan_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) - payment_plan_object_id = UUIDField() + + payment_plan = models.OneToOneField( + "payment.PaymentPlan", + on_delete=models.CASCADE, + related_name="payment_verification_summary", + null=True, + ) + + # TODO TP drop + payment_plan_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True) + payment_plan_object_id = UUIDField(null=True) payment_plan_obj = GenericForeignKey("payment_plan_content_type", "payment_plan_object_id") class Meta: + # TODO TP DROP indexes = [ models.Index(fields=["payment_plan_content_type", "payment_plan_object_id"]), ] diff --git a/src/hct_mis_api/apps/payment/mutations.py b/src/hct_mis_api/apps/payment/mutations.py index 0d21fd131d..e11fe3049f 100644 --- a/src/hct_mis_api/apps/payment/mutations.py +++ b/src/hct_mis_api/apps/payment/mutations.py @@ -2,7 +2,7 @@ import logging from datetime import date, datetime from decimal import Decimal -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional from zipfile import BadZipFile from django.db import transaction @@ -42,7 +42,6 @@ UpdatePaymentPlanInput, ) from hct_mis_api.apps.payment.models import ( - CashPlan, DeliveryMechanism, DeliveryMechanismPerPaymentPlan, FinancialServiceProvider, @@ -111,9 +110,7 @@ class Arguments: @transaction.atomic @raise_program_status_is(Program.FINISHED) def mutate(cls, root: Any, info: Any, input: Dict, **kwargs: Any) -> "CreateVerificationPlanMutation": - payment_plan_object: Union["CashPlan", "PaymentPlan"] = get_payment_plan_object( - input["cash_or_payment_plan_id"] - ) + payment_plan_object: "PaymentPlan" = get_payment_plan_object(input["cash_or_payment_plan_id"]) check_concurrency_version_in_mutation(kwargs.get("version"), payment_plan_object) @@ -158,7 +155,7 @@ def mutate(cls, root: Any, info: Any, input: Dict, **kwargs: Any) -> "EditPaymen payment_verification_plan = VerificationPlanCrudServices.update(payment_verification_plan, input) - payment_verification_plan.payment_plan_obj.refresh_from_db() + payment_verification_plan.payment_plan.refresh_from_db() log_create( PaymentVerificationPlan.ACTIVITY_LOG_MAPPING, "business_area", @@ -167,7 +164,7 @@ def mutate(cls, root: Any, info: Any, input: Dict, **kwargs: Any) -> "EditPaymen old_payment_verification_plan, payment_verification_plan, ) - return cls(payment_plan=payment_verification_plan.payment_plan_obj) + return cls(payment_plan=payment_verification_plan.payment_plan) class ActivatePaymentVerificationPlan(PermissionMutation, ValidationErrorMutationMixin): @@ -200,7 +197,7 @@ def processed_mutate( old_payment_verification_plan, payment_verification_plan, ) - return ActivatePaymentVerificationPlan(payment_plan=payment_verification_plan.payment_plan_obj) + return ActivatePaymentVerificationPlan(payment_plan=payment_verification_plan.payment_plan) class FinishPaymentVerificationPlan(PermissionMutation): @@ -234,7 +231,7 @@ def mutate( old_payment_verification_plan, payment_verification_plan, ) - return FinishPaymentVerificationPlan(payment_plan=payment_verification_plan.payment_plan_obj) + return FinishPaymentVerificationPlan(payment_plan=payment_verification_plan.payment_plan) class DiscardPaymentVerificationPlan(PermissionMutation): @@ -269,7 +266,7 @@ def mutate( old_payment_verification_plan, payment_verification_plan, ) - return cls(payment_plan=payment_verification_plan.payment_plan_obj) + return cls(payment_plan=payment_verification_plan.payment_plan) class InvalidPaymentVerificationPlan(PermissionMutation): @@ -303,7 +300,7 @@ def mutate( old_payment_verification_plan, payment_verification_plan, ) - return cls(payment_plan=payment_verification_plan.payment_plan_obj) + return cls(payment_plan=payment_verification_plan.payment_plan) class DeletePaymentVerificationPlan(PermissionMutation): @@ -321,7 +318,7 @@ def mutate( ) -> "DeletePaymentVerificationPlan": payment_verification_plan_id = decode_id_string(payment_verification_plan_id) payment_verification_plan = get_object_or_404(PaymentVerificationPlan, id=payment_verification_plan_id) - payment_plan = payment_verification_plan.payment_plan_obj + payment_plan = payment_verification_plan.payment_plan program_id = getattr(payment_verification_plan.get_program, "pk", None) check_concurrency_version_in_mutation(kwargs.get("version"), payment_verification_plan) @@ -384,7 +381,7 @@ def mutate( raise GraphQLError( f"You can only update status of payment verification for {PaymentVerificationPlan.STATUS_ACTIVE} cash plan verification" ) - delivered_amount = payment_verification.payment_obj.delivered_quantity + delivered_amount = payment_verification.payment.delivered_quantity if status == PaymentVerification.STATUS_PENDING and received_amount is not None: logger.error( f"Wrong status {PaymentVerification.STATUS_PENDING} when received_amount ({received_amount}) is not empty", @@ -486,7 +483,7 @@ def mutate( ) if not payment_verification.is_manually_editable: log_and_raise("You can only edit payment verification in first 10 minutes") - delivered_amount = payment_verification.payment_obj.delivered_quantity + delivered_amount = payment_verification.payment.delivered_quantity if received is None and received_amount is not None and received_amount == 0: log_and_raise("You can't set received_amount {received_amount} and not set received to NO") @@ -560,7 +557,7 @@ def mutate(cls, root: Any, info: Any, payment_verification_plan_id: str) -> "Exp payment_verification_plan.xlsx_file_exporting = True payment_verification_plan.save() create_payment_verification_plan_xlsx.delay(payment_verification_plan_id, info.context.user.pk) - return cls(payment_plan=payment_verification_plan.payment_plan_obj) + return cls(payment_plan=payment_verification_plan.payment_plan) class ImportXlsxPaymentVerificationPlanFile(PermissionMutation): @@ -596,7 +593,7 @@ def mutate( calculate_counts(payment_verification_plan) payment_verification_plan.xlsx_file_imported = True payment_verification_plan.save() - return ImportXlsxPaymentVerificationPlanFile(payment_verification_plan.payment_plan_obj, import_service.errors) + return ImportXlsxPaymentVerificationPlanFile(payment_verification_plan.payment_plan, import_service.errors) class MarkPaymentRecordAsFailedMutation(PermissionMutation): @@ -727,7 +724,7 @@ def mutate(cls, root: Any, info: Any, input: Dict, **kwargs: Any) -> "ActionPaym mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=info.context.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program.pk, old_object=old_payment_plan, new_object=payment_plan, ) @@ -776,7 +773,7 @@ def mutate(cls, root: Any, info: Any, input: Dict, **kwargs: Any) -> "CreatePaym mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=info.context.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program.pk, new_object=payment_plan, ) return cls(payment_plan=payment_plan) @@ -803,7 +800,7 @@ def mutate(cls, root: Any, info: Any, input: Dict, **kwargs: Any) -> "UpdatePaym mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=info.context.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program.pk, old_object=old_payment_plan, new_object=payment_plan, ) @@ -832,7 +829,7 @@ def mutate(cls, root: Any, info: Any, payment_plan_id: str, **kwargs: Any) -> "D mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=info.context.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program.pk, old_object=old_payment_plan, new_object=payment_plan, ) @@ -871,7 +868,7 @@ def mutate( mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=info.context.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program.pk, old_object=old_payment_plan, new_object=payment_plan, ) @@ -1049,7 +1046,7 @@ def mutate( mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=info.context.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program.pk, old_object=old_payment_plan, new_object=payment_plan, ) @@ -1102,7 +1099,7 @@ def mutate( mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=info.context.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program.pk, old_object=old_payment_plan, new_object=payment_plan, ) @@ -1152,7 +1149,7 @@ def mutate( mapping=PaymentPlan.ACTIVITY_LOG_MAPPING, business_area_field="business_area", user=info.context.user, - programs=payment_plan.get_program.pk, + programs=payment_plan.program.pk, old_object=old_payment_plan, new_object=payment_plan, ) diff --git a/src/hct_mis_api/apps/payment/schema.py b/src/hct_mis_api/apps/payment/schema.py index 556220dbda..b5587ad9ea 100644 --- a/src/hct_mis_api/apps/payment/schema.py +++ b/src/hct_mis_api/apps/payment/schema.py @@ -578,7 +578,6 @@ class PaymentPlanNode(BaseNodePermissionMixin, AdminUrlNodeMixin, DjangoObjectTy ) payment_verification_summary = graphene.Field( PaymentVerificationSummaryNode, - source="get_payment_verification_summary", ) bank_reconciliation_success = graphene.Int() bank_reconciliation_error = graphene.Int() @@ -604,7 +603,7 @@ def resolve_split_choices(self, info: Any, **kwargs: Any) -> List[Dict[str, Any] return to_choice_object(PaymentPlanSplit.SplitType.choices) def resolve_verification_plans(self, info: Any) -> graphene.List: - return self.get_payment_verification_plans + return self.payment_verification_plans.all() def resolve_payments_conflicts_count(self, info: Any) -> graphene.Int: return self.payment_items.filter(excluded=False, payment_plan_hard_conflicted=True).count() @@ -795,7 +794,7 @@ class CashPlanAndPaymentPlanNode(BaseNodePermissionMixin, AdminUrlNodeMixin, gra obj_type = graphene.String() id = graphene.String() - unicef_id = graphene.String(source="get_unicef_id") + unicef_id = graphene.String() verification_status = graphene.String() status = graphene.String() currency = graphene.String() @@ -824,7 +823,7 @@ def resolve_total_number_of_households(self, info: Any, **kwargs: Any) -> int: return self.payment_items.count() def resolve_verification_status(self, info: Any, **kwargs: Any) -> Optional[graphene.String]: - return self.get_payment_verification_summary.status if self.get_payment_verification_summary else None + return self.payment_verification_summary.status if self.payment_verification_summary else None def resolve_status(self, info: Any, **kwargs: Any) -> Optional[graphene.String]: return self.status @@ -833,7 +832,7 @@ def resolve_program_name(self, info: Any, **kwargs: Any) -> graphene.String: return self.program.name def resolve_verification_plans(self, info: Any, **kwargs: Any) -> graphene.List: - return self.payment_verification_plan.all() + return self.payment_verification_plans.all() # TODO: do we need this empty fields ?? def resolve_assistance_measurement(self, info: Any, **kwargs: Any) -> str: @@ -937,16 +936,13 @@ def resolve_id(self, info: Any, **kwargs: Any) -> graphene.String: def resolve_obj_type(self, info: Any, **kwargs: Any) -> str: return self.__class__.__name__ - def resolve_payment_verification_summary(self, info: Any, **kwargs: Any) -> graphene.Field: - return self.get_payment_verification_summary - def resolve_available_payment_records_count(self, info: Any, **kwargs: Any) -> graphene.Int: return self.payment_items.filter( status__in=PaymentRecord.ALLOW_CREATE_VERIFICATION, delivered_quantity__gt=0 ).count() def resolve_verification_plans(self, info: Any, **kwargs: Any) -> DjangoPermissionFilterConnectionField: - return self.get_payment_verification_plans + return self.payment_verification_plans.all() def resolve_total_entitled_quantity(self, info: Any, **kwargs: Any) -> graphene.Float: return self.total_entitled_quantity @@ -1165,8 +1161,7 @@ def get_fsps_for_delivery_mechanism(mechanism_name: str) -> List: ] def resolve_all_payment_verifications(self, info: Any, **kwargs: Any) -> QuerySet: - payment_qs = Payment.objects.filter(id=OuterRef("payment_object_id"), household__withdrawn=True) - payment_record_qs = Payment.objects.filter(id=OuterRef("payment_object_id"), household__withdrawn=True) + payment_qs = Payment.objects.filter(id=OuterRef("payment_id"), household__withdrawn=True) return ( PaymentVerification.objects.filter( @@ -1174,9 +1169,8 @@ def resolve_all_payment_verifications(self, info: Any, **kwargs: Any) -> QuerySe | Q(payment_verification_plan__status=PaymentVerificationPlan.STATUS_FINISHED) ) .annotate( - payment_obj__household__status=Case( + payment__household__status=Case( When(Exists(payment_qs), then=Value(STATUS_INACTIVE)), - When(Exists(payment_record_qs), then=Value(STATUS_INACTIVE)), default=Value(STATUS_ACTIVE), output_field=CharField(), ), @@ -1185,9 +1179,7 @@ def resolve_all_payment_verifications(self, info: Any, **kwargs: Any) -> QuerySe ) def resolve_sample_size(self, info: Any, input: Dict, **kwargs: Any) -> Dict[str, int]: - payment_plan_object: Union["CashPlan", "PaymentPlan"] = get_payment_plan_object( - input["cash_or_payment_plan_id"] - ) + payment_plan_object: "PaymentPlan" = get_payment_plan_object(input["cash_or_payment_plan_id"]) def get_payment_records( obj: Union["PaymentPlan", "CashPlan"], @@ -1480,9 +1472,7 @@ def resolve_all_cash_plans_and_payment_plans(self, info: Any, **kwargs: Any) -> delivery_mechanisms_per_pp_qs = DeliveryMechanismPerPaymentPlan.objects.filter( payment_plan=OuterRef("pk") ).distinct("delivery_mechanism") - payment_verification_summary_qs = PaymentVerificationSummary.objects.filter( - payment_plan_object_id=OuterRef("id") - ) + payment_verification_summary_qs = PaymentVerificationSummary.objects.filter(payment_plan_id=OuterRef("id")) if "is_payment_verification_page" in kwargs and kwargs.get("is_payment_verification_page"): payment_plan_qs = PaymentPlan.objects.filter(status=PaymentPlan.Status.FINISHED) diff --git a/src/hct_mis_api/apps/payment/services/create_payment_verifications.py b/src/hct_mis_api/apps/payment/services/create_payment_verifications.py index ccb0099396..32c597ff56 100644 --- a/src/hct_mis_api/apps/payment/services/create_payment_verifications.py +++ b/src/hct_mis_api/apps/payment/services/create_payment_verifications.py @@ -22,7 +22,7 @@ def create(self) -> None: payment_record_verification = PaymentVerification( status_date=timezone.now(), payment_verification_plan=self.payment_verification_plan, - payment_obj=payment_record, + payment=payment_record, received_amount=None, ) payment_record_verifications_to_create.append(payment_record_verification) diff --git a/src/hct_mis_api/apps/payment/services/dashboard_service.py b/src/hct_mis_api/apps/payment/services/dashboard_service.py index b6f3a0f845..4f155184d3 100644 --- a/src/hct_mis_api/apps/payment/services/dashboard_service.py +++ b/src/hct_mis_api/apps/payment/services/dashboard_service.py @@ -6,11 +6,8 @@ from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.household.models import Household -from hct_mis_api.apps.payment.models import PaymentRecord, PaymentVerification -from hct_mis_api.apps.payment.utils import ( - get_payment_items_for_dashboard, - get_payment_items_sequence_qs, -) +from hct_mis_api.apps.payment.models import Payment, PaymentRecord, PaymentVerification +from hct_mis_api.apps.payment.utils import get_payment_items_for_dashboard class PaymentVerificationChartQueryResponse(TypedDict): @@ -39,7 +36,9 @@ def payment_verification_chart_query( ) if program: - params &= Q(Q(payment__parent__program__id=program) | Q(payment_record__parent__program__id=program)) + params &= Q( + Q(payment__parent__program_cycle__program__id=program) | Q(payment_record__parent__program__id=program) + ) if administrative_area: inner_params = Q() @@ -74,10 +73,10 @@ def payment_verification_chart_query( "payments_count" ] all_payment_records_for_created_verifications = ( - get_payment_items_sequence_qs() + Payment.objects.filter(excluded=False, conflicted=False) .filter( - parent__in=payment_verifications.distinct("payment_verification_plan__payment_plan_object_id").values_list( - "payment_verification_plan__payment_plan_object_id", flat=True + parent__in=payment_verifications.distinct("payment_verification_plan__payment_plan_id").values_list( + "payment_verification_plan__payment_plan_id", flat=True ) ) .filter(status=PaymentRecord.STATUS_SUCCESS, delivered_quantity__gt=0) diff --git a/src/hct_mis_api/apps/payment/services/payment_plan_services.py b/src/hct_mis_api/apps/payment/services/payment_plan_services.py index 7a51cbacad..8fefb9df77 100644 --- a/src/hct_mis_api/apps/payment/services/payment_plan_services.py +++ b/src/hct_mis_api/apps/payment/services/payment_plan_services.py @@ -333,7 +333,7 @@ def create_payments(payment_plan: PaymentPlan) -> None: payments_to_create.append( Payment( parent=payment_plan, - program_id=payment_plan.program_id, + program_id=payment_plan.program_cycle.program_id, business_area_id=payment_plan.business_area_id, status=Payment.STATUS_PENDING, status_date=timezone.now(), @@ -395,7 +395,6 @@ def create(input_data: Dict, user: "User") -> PaymentPlan: business_area=business_area, created_by=user, target_population=target_population, - program=target_population.program, program_cycle=program_cycle, name=target_population.name, currency=input_data["currency"], @@ -443,7 +442,6 @@ def update(self, input_data: Dict) -> PaymentPlan: self.payment_plan.target_population.save() self.payment_plan.target_population = new_target_population - self.payment_plan.program = new_target_population.program self.payment_plan.program_cycle = new_target_population.program_cycle self.payment_plan.target_population.status = TargetPopulation.STATUS_ASSIGNED self.payment_plan.target_population.save() @@ -619,7 +617,7 @@ def create_follow_up_payments(self) -> None: Payment( parent=self.payment_plan, source_payment=payment, - program_id=self.payment_plan.program_id, + program_id=self.payment_plan.program_cycle.program_id, is_follow_up=True, business_area_id=payment.business_area_id, status=Payment.STATUS_PENDING, @@ -657,7 +655,6 @@ def create_follow_up( business_area=source_pp.business_area, created_by=user, target_population=source_pp.target_population, - program=source_pp.program, program_cycle=source_pp.program_cycle, currency=source_pp.currency, dispersion_start_date=dispersion_start_date, diff --git a/src/hct_mis_api/apps/payment/services/verification_plan_crud_services.py b/src/hct_mis_api/apps/payment/services/verification_plan_crud_services.py index 8d93c2849c..c18a93ecc6 100644 --- a/src/hct_mis_api/apps/payment/services/verification_plan_crud_services.py +++ b/src/hct_mis_api/apps/payment/services/verification_plan_crud_services.py @@ -1,6 +1,5 @@ from typing import TYPE_CHECKING, Any, Dict, Optional, Union -from django.contrib.admin.options import get_content_type_for_model from django.db.models import QuerySet from graphql import GraphQLError @@ -38,8 +37,7 @@ def create(cls, payment_plan: Union["PaymentPlan", "CashPlan"], input_data: Dict verifier.verify("verification_channel") payment_verification_plan = PaymentVerificationPlan() - payment_verification_plan.payment_plan_content_type = get_content_type_for_model(payment_plan) - payment_verification_plan.payment_plan_object_id = payment_plan.pk + payment_verification_plan.payment_plan = payment_plan payment_verification_plan.verification_channel = input_data.get("verification_channel") @@ -63,9 +61,9 @@ def update(cls, payment_verification_plan: PaymentVerificationPlan, input_data: raise GraphQLError("You can only edit PENDING Cash/Payment Plan Verification") payment_records = get_payment_records( - payment_verification_plan.payment_plan_obj, payment_verification_plan.verification_channel + payment_verification_plan.payment_plan, payment_verification_plan.verification_channel ) - sampling = Sampling(input_data, payment_verification_plan.payment_plan_obj, payment_records) + sampling = Sampling(input_data, payment_verification_plan.payment_plan, payment_records) pv_plan, payment_records_qs = sampling.process_sampling(payment_verification_plan) ProcessVerification(input_data, pv_plan).process() pv_plan.save() diff --git a/src/hct_mis_api/apps/payment/services/verification_plan_status_change_services.py b/src/hct_mis_api/apps/payment/services/verification_plan_status_change_services.py index 857d1868de..f479d5ea92 100644 --- a/src/hct_mis_api/apps/payment/services/verification_plan_status_change_services.py +++ b/src/hct_mis_api/apps/payment/services/verification_plan_status_change_services.py @@ -91,7 +91,7 @@ def _activate_rapidpro(self) -> None: api = RapidProAPI(business_area_slug, RapidProAPI.MODE_VERIFICATION) hoh_ids = [ - pv.payment_obj.household.head_of_household.pk + pv.payment.household.head_of_household.pk for pv in self.payment_verification_plan.payment_record_verifications.filter(sent_to_rapid_pro=False) ] individuals = Individual.objects.filter(pk__in=hoh_ids) @@ -107,7 +107,7 @@ def _activate_rapidpro(self) -> None: payment_verifications_to_upd = [] for pv in self.payment_verification_plan.payment_record_verifications.all(): - if pv.payment_obj.head_of_household in processed_individuals: + if pv.payment.head_of_household in processed_individuals: pv.sent_to_rapid_pro = True payment_verifications_to_upd.append(pv) PaymentVerification.objects.bulk_update(payment_verifications_to_upd, ("sent_to_rapid_pro",), 1000) @@ -137,7 +137,7 @@ def _create_grievance_ticket_for_status( if verifications.count() == 0: return - business_area = payment_verification_plan.payment_plan_obj.business_area + business_area = payment_verification_plan.payment_plan.business_area grievance_ticket_list = [] tickets_programs = [] GrievanceTicketProgramThrough = GrievanceTicket.programs.through @@ -145,12 +145,12 @@ def _create_grievance_ticket_for_status( grievance_ticket = GrievanceTicket( category=GrievanceTicket.CATEGORY_PAYMENT_VERIFICATION, business_area=business_area, - household_unicef_id=verification.payment_obj.household.unicef_id, - admin2_id=verification.payment_obj.household.admin2_id, + household_unicef_id=verification.payment.household.unicef_id, + admin2_id=verification.payment.household.admin2_id, ) grievance_ticket_list.append(grievance_ticket) # get program from parent GenericPaymentPlan.program - program = verification.payment_obj.parent.program + program = verification.payment.parent.program tickets_programs.append( GrievanceTicketProgramThrough(grievanceticket=grievance_ticket, program_id=program.id) diff --git a/src/hct_mis_api/apps/payment/tasks/CheckRapidProVerificationTask.py b/src/hct_mis_api/apps/payment/tasks/CheckRapidProVerificationTask.py index 7f6c11cb0e..a30ce0df0e 100644 --- a/src/hct_mis_api/apps/payment/tasks/CheckRapidProVerificationTask.py +++ b/src/hct_mis_api/apps/payment/tasks/CheckRapidProVerificationTask.py @@ -35,13 +35,13 @@ def execute(self) -> None: def _verify_cashplan_payment_verification(self, payment_verification_plan: PaymentVerificationPlan) -> None: payment_record_verifications = payment_verification_plan.payment_record_verifications.prefetch_related( - "payment_obj__head_of_household" + "payment__head_of_household" ) - business_area = payment_verification_plan.payment_plan_obj.business_area + business_area = payment_verification_plan.payment_plan.business_area payment_record_verifications_phone_number_dict = { - str(payment_verification.payment_obj.head_of_household.phone_no): payment_verification + str(payment_verification.payment.head_of_household.phone_no): payment_verification for payment_verification in payment_record_verifications - if payment_verification.payment_obj.head_of_household is not None + if payment_verification.payment.head_of_household is not None } api = RapidProAPI(business_area.slug, RapidProAPI.MODE_VERIFICATION) rapid_pro_results = api.get_mapped_flow_runs(payment_verification_plan.rapid_pro_flow_start_uuids) @@ -73,7 +73,7 @@ def _rapid_pro_results_to_payment_record_verification( payment_record_verification = payment_record_verifications_phone_number_dict.get(phone_number) if not payment_record_verification: return None - delivered_amount = payment_record_verification.payment_obj.delivered_quantity + delivered_amount = payment_record_verification.payment.delivered_quantity payment_record_verification.status = from_received_to_status(received, received_amount, delivered_amount) payment_record_verification.received_amount = received_amount return payment_record_verification diff --git a/src/hct_mis_api/apps/payment/utils.py b/src/hct_mis_api/apps/payment/utils.py index 5f6145742b..decdd20931 100644 --- a/src/hct_mis_api/apps/payment/utils.py +++ b/src/hct_mis_api/apps/payment/utils.py @@ -9,13 +9,10 @@ from django.shortcuts import get_object_or_404 from hct_mis_api.apps.core.exchange_rates import ExchangeRates -from hct_mis_api.apps.core.querysets import ExtendedQuerySetSequence from hct_mis_api.apps.core.utils import chart_create_filter_query, chart_get_filtered_qs from hct_mis_api.apps.payment.models import ( - CashPlan, Payment, PaymentPlan, - PaymentRecord, PaymentVerification, PaymentVerificationPlan, ) @@ -103,14 +100,14 @@ def get_payment_items_for_dashboard( if only_with_delivered_quantity: additional_filters["delivered_quantity_usd__gt"] = 0 return chart_get_filtered_qs( - get_payment_items_sequence_qs(), + Payment.objects.filter(excluded=False, conflicted=False), year, business_area_slug_filter={"business_area__slug": business_area_slug}, additional_filters={ **additional_filters, **chart_create_filter_query( filters, - program_id_path="parent__program__id", + program_id_path="parent__program_cycle__program__id", administrative_area_path="household__admin_area", ), }, @@ -143,30 +140,9 @@ def get_quantity_in_usd( return Decimal(amount / Decimal(exchange_rate)).quantize(Decimal(".01")) -def get_payment_items_sequence_qs() -> ExtendedQuerySetSequence: - return ExtendedQuerySetSequence( - Payment.objects.filter(excluded=False, conflicted=False), PaymentRecord.objects.all() - ) - - -def get_payment_cash_plan_items_sequence_qs() -> ExtendedQuerySetSequence: - return ExtendedQuerySetSequence(PaymentPlan.objects.all(), CashPlan.objects.all()) - - -def get_payment_plan_object(cash_or_payment_plan_id: str) -> Union["PaymentPlan", "CashPlan"]: - """ - get cash_or_payment_plan_id: "UGF5bWVudFBsYW5Ob2RlOmEz4YjA2NGJkMmJmMw==" - return CashPlan/PaymentPlan object or raise 404 - """ - node_name, obj_id = b64decode(cash_or_payment_plan_id).decode().split(":") - - payment_plan_object: Union["CashPlan", "PaymentPlan"] - if node_name == "CashPlanNode": - payment_plan_object = get_object_or_404(CashPlan, pk=obj_id) - else: - payment_plan_object = get_object_or_404(PaymentPlan, pk=obj_id) - - return payment_plan_object +def get_payment_plan_object(payment_plan_id: str) -> "PaymentPlan": + node_name, obj_id = b64decode(payment_plan_id).decode().split(":") + return get_object_or_404(PaymentPlan, pk=obj_id) def get_payment_delivered_quantity_status_and_value( diff --git a/src/hct_mis_api/apps/payment/xlsx/xlsx_payment_plan_export_per_fsp_service.py b/src/hct_mis_api/apps/payment/xlsx/xlsx_payment_plan_export_per_fsp_service.py index 000fde18eb..be749f0086 100644 --- a/src/hct_mis_api/apps/payment/xlsx/xlsx_payment_plan_export_per_fsp_service.py +++ b/src/hct_mis_api/apps/payment/xlsx/xlsx_payment_plan_export_per_fsp_service.py @@ -32,7 +32,9 @@ def check_if_token_or_order_number_exists_per_program(payment: Payment, field_name: str, token: int) -> bool: - return Payment.objects.filter(parent__program=payment.parent.program, **{field_name: token}).exists() + return Payment.objects.filter( + parent__program_cycle__program=payment.parent.program_cycle.program, **{field_name: token} + ).exists() def generate_token_and_order_numbers(payment: Payment) -> Payment: diff --git a/src/hct_mis_api/apps/payment/xlsx/xlsx_payment_plan_per_fsp_import_service.py b/src/hct_mis_api/apps/payment/xlsx/xlsx_payment_plan_per_fsp_import_service.py index 4ee9a5c5b7..c7d0306249 100644 --- a/src/hct_mis_api/apps/payment/xlsx/xlsx_payment_plan_per_fsp_import_service.py +++ b/src/hct_mis_api/apps/payment/xlsx/xlsx_payment_plan_per_fsp_import_service.py @@ -347,8 +347,8 @@ def _import_row(self, row: Row, exchange_rate: float) -> None: self.payments_to_save.append(payment) # update PaymentVerification status - if payment.payment_verification.exists(): - payment_verification = payment.payment_verification.first() + if hasattr(payment, "payment_verification"): + payment_verification = payment.payment_verification if payment_verification.status != PaymentVerification.STATUS_PENDING: if payment_verification.received_amount == delivered_quantity: diff --git a/src/hct_mis_api/apps/payment/xlsx/xlsx_verification_export_service.py b/src/hct_mis_api/apps/payment/xlsx/xlsx_verification_export_service.py index 6cf9909fa5..315076407f 100644 --- a/src/hct_mis_api/apps/payment/xlsx/xlsx_verification_export_service.py +++ b/src/hct_mis_api/apps/payment/xlsx/xlsx_verification_export_service.py @@ -81,7 +81,7 @@ def _get_headers(self) -> tuple: def __init__(self, payment_verification_plan: PaymentVerificationPlan) -> None: self.payment_verification_plan = payment_verification_plan - self.is_social_worker_program = payment_verification_plan.payment_plan_obj.program.is_social_worker_program + self.is_social_worker_program = payment_verification_plan.payment_plan.program.is_social_worker_program self.payment_record_verifications = payment_verification_plan.payment_record_verifications.all() self.HEADERS = self._get_headers() @@ -115,11 +115,11 @@ def _add_payment_record_verification_row(self, payment_record_verification: Paym self._add_payment_record_verification_row_for_household(payment_record_verification) def _add_payment_record_verification_row_for_people(self, payment_record_verification: PaymentVerification) -> None: - household = payment_record_verification.payment_obj.household - head_of_household = payment_record_verification.payment_obj.head_of_household + household = payment_record_verification.payment.household + head_of_household = payment_record_verification.payment.head_of_household payment_record_verification_row = ( - str(payment_record_verification.payment_object_id), - str(payment_record_verification.payment_obj.unicef_id) if payment_record_verification.payment_obj else "", + str(payment_record_verification.payment_id), + str(payment_record_verification.payment.unicef_id) if payment_record_verification.payment else "", self._to_received_column(payment_record_verification), str(head_of_household.full_name) if head_of_household else "", str(head_of_household.phone_no) if head_of_household else "", diff --git a/src/hct_mis_api/apps/payment/xlsx/xlsx_verification_import_service.py b/src/hct_mis_api/apps/payment/xlsx/xlsx_verification_import_service.py index d980ee9591..555c530e96 100644 --- a/src/hct_mis_api/apps/payment/xlsx/xlsx_verification_import_service.py +++ b/src/hct_mis_api/apps/payment/xlsx/xlsx_verification_import_service.py @@ -25,11 +25,9 @@ def __init__(self, cashplan_payment_verification: PaymentVerificationPlan, file: self.errors: List[XlsxError] = [] payment_record_verification_obj = self.cashplan_payment_verification.payment_record_verifications self.payment_record_verifications = payment_record_verification_obj.all() # .prefetch_related("payment") - self.payment_record_ids = [str(x.payment_object_id) for x in self.payment_record_verifications] - self.payment_record_verifications_dict = { - str(x.payment_object_id): x for x in self.payment_record_verifications - } - self.payment_records_dict = {str(x.payment_object_id): x.payment_obj for x in self.payment_record_verifications} + self.payment_record_ids = [str(x.payment_id) for x in self.payment_record_verifications] + self.payment_record_verifications_dict = {str(x.payment_id): x for x in self.payment_record_verifications} + self.payment_records_dict = {str(x.payment_id): x.payment for x in self.payment_record_verifications} self.payment_verifications_to_save = [] self.was_validation_run = False diff --git a/src/hct_mis_api/apps/program/fixtures.py b/src/hct_mis_api/apps/program/fixtures.py index 73524762c8..d83d4f8c85 100644 --- a/src/hct_mis_api/apps/program/fixtures.py +++ b/src/hct_mis_api/apps/program/fixtures.py @@ -40,7 +40,7 @@ class Meta: variable_nb_words=True, ext_word_list=None, ) - program = factory.SubFactory("program.fixtures.ProgramFactory") + program = factory.SubFactory("hct_mis_api.apps.program.fixtures.ProgramFactory") class ProgramFactory(DjangoModelFactory): diff --git a/src/hct_mis_api/apps/program/schema.py b/src/hct_mis_api/apps/program/schema.py index 2127c6070d..1177d820e0 100644 --- a/src/hct_mis_api/apps/program/schema.py +++ b/src/hct_mis_api/apps/program/schema.py @@ -356,9 +356,7 @@ def resolve_data_collecting_type_choices(self, info: Any, **kwargs: Any) -> List ) def resolve_all_cash_plans(self, info: Any, **kwargs: Any) -> QuerySet[CashPlan]: - payment_verification_summary_qs = PaymentVerificationSummary.objects.filter( - payment_plan_object_id=OuterRef("id") - ) + payment_verification_summary_qs = PaymentVerificationSummary.objects.filter(payment_plan_id=OuterRef("id")) return CashPlan.objects.annotate( custom_order=Case( @@ -386,7 +384,7 @@ def resolve_chart_programmes_by_sector(self, info: Any, business_area_slug: str, sector_choice_mapping = dict(Program.SECTOR_CHOICE) payment_items_qs: QuerySet = get_payment_items_for_dashboard(year, business_area_slug, filters, True) - programs_ids = payment_items_qs.values_list("parent__program__id", flat=True) + programs_ids = payment_items_qs.values_list("parent__program_cycle__program__id", flat=True) programs = Program.objects.filter(id__in=programs_ids).distinct() programmes_by_sector = ( diff --git a/src/hct_mis_api/apps/reporting/services/generate_report_service.py b/src/hct_mis_api/apps/reporting/services/generate_report_service.py index 7e52c8d1ae..7d8312cb4d 100644 --- a/src/hct_mis_api/apps/reporting/services/generate_report_service.py +++ b/src/hct_mis_api/apps/reporting/services/generate_report_service.py @@ -203,7 +203,7 @@ def _map_admin_area_names_from_ids(admin_areas_ids: list) -> str: def format_cash_plan_verification_row(cls, verification: PaymentVerificationPlan) -> tuple: return ( verification.id, - verification.payment_plan_obj.get_unicef_id, + verification.payment_plan_obj.unicef_id, verification.payment_plan_obj.program.name, cls._format_date(verification.activation_date), verification.status, @@ -269,21 +269,21 @@ def get_payment_verifications(report: Report) -> QuerySet: PaymentPlan.objects.filter(business_area=report.business_area).values_list("id", flat=True) ) filter_vars = { - "payment_verification_plan__payment_plan_object_id__in": pp_business_area_ids, + "payment_verification_plan__payment_plan_id__in": pp_business_area_ids, "payment_verification_plan__completion_date__isnull": False, "payment_verification_plan__completion_date__date__range": (report.date_from, report.date_to), } if report.program: pp_program_ids = list(PaymentPlan.objects.filter(program=report.program).values_list("id", flat=True)) - filter_vars["payment_verification_plan__payment_plan_object_id__in"] = pp_program_ids + filter_vars["payment_verification_plan__payment_plan_id__in"] = pp_program_ids return PaymentVerification.objects.filter(**filter_vars) @classmethod def format_payment_verification_row(cls, payment_verification: PaymentVerification) -> tuple: return ( payment_verification.payment_verification_plan.id, - payment_verification.payment_obj.unicef_id, - payment_verification.payment_verification_plan.get_payment_plan.get_unicef_id, + payment_verification.payment.unicef_id, + payment_verification.payment_verification_plan.payment_plan.unicef_id, cls._format_date(payment_verification.payment_verification_plan.completion_date), payment_verification.received_amount, payment_verification.status, @@ -304,7 +304,7 @@ def get_payment_plans(report: Report) -> QuerySet[PaymentPlan]: @classmethod def format_payment_plan_row(cls, payment_plan: PaymentPlan) -> tuple: return ( - payment_plan.get_unicef_id, + payment_plan.unicef_id, payment_plan.get_status_display(), payment_plan.total_households_count, payment_plan.get_currency_display(), diff --git a/src/hct_mis_api/apps/targeting/models.py b/src/hct_mis_api/apps/targeting/models.py index b5973104cc..4b9db0cb02 100644 --- a/src/hct_mis_api/apps/targeting/models.py +++ b/src/hct_mis_api/apps/targeting/models.py @@ -135,117 +135,121 @@ class TargetPopulation(SoftDeletableModel, TimeStampedUUIDModel, ConcurrencyMode StartEndSpaceValidator, ProhibitNullCharactersValidator(), ], - ) - ca_id = CICharField(max_length=255, null=True, blank=True) - ca_hash_id = CICharField(max_length=255, null=True, blank=True) + ) # TODO TP the same as PP name + ca_id = CICharField(max_length=255, null=True, blank=True) # TODO TP store in json + ca_hash_id = CICharField(max_length=255, null=True, blank=True) # TODO TP store in json created_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="target_populations", null=True, - ) - change_date = models.DateTimeField(null=True, blank=True) + ) # TODO TP -> PP created_by + change_date = models.DateTimeField(null=True, blank=True) # TODO TP pp.status_date changed_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="changed_target_populations", null=True, blank=True, - ) - finalized_at = models.DateTimeField(null=True, blank=True) + ) # TODO TP move to PP (status changed by?) + finalized_at = models.DateTimeField(null=True, blank=True) # TODO TP this is just a status change finalized_by = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="finalized_target_populations", null=True, blank=True, - ) - business_area = models.ForeignKey("core.BusinessArea", null=True, on_delete=models.CASCADE) - status = models.CharField(max_length=256, choices=STATUS_CHOICES, default=STATUS_OPEN, db_index=True) + ) # TODO TP this is just a status change + business_area = models.ForeignKey("core.BusinessArea", null=True, on_delete=models.CASCADE) # TODO TP exists in PP + status = models.CharField( + max_length=256, choices=STATUS_CHOICES, default=STATUS_OPEN, db_index=True + ) # TODO TP exists in PP build_status = models.CharField( max_length=256, choices=BUILD_STATUS_CHOICES, default=BUILD_STATUS_PENDING, db_index=True - ) - built_at = models.DateTimeField(null=True, blank=True) + ) # TODO TP move to PP with separate statuses + built_at = models.DateTimeField(null=True, blank=True) # TODO TP move to PP households = models.ManyToManyField( "household.Household", related_name="target_populations", through="HouseholdSelection", - ) + ) # TODO TP drop, create payments automatically program = models.ForeignKey( "program.Program", help_text="""Set only when the target population moves from draft to candidate list frozen state (approved)""", on_delete=models.PROTECT, - ) + ) # TODO TP exists in PP program_cycle = models.ForeignKey( "program.ProgramCycle", on_delete=models.CASCADE, related_name="target_populations" - ) + ) # TODO TP exists ALSO in PP ?! targeting_criteria = models.OneToOneField( "TargetingCriteria", blank=True, null=True, on_delete=models.SET_NULL, related_name="target_population", - ) + ) # TODO TP move to PP sent_to_datahub = models.BooleanField( default=False, help_text=""" Flag set when TP is processed by celery task """, db_index=True, - ) + ) # TODO TP store in json steficon_rule = models.ForeignKey( RuleCommit, null=True, on_delete=models.PROTECT, related_name="target_populations", blank=True, - ) - steficon_applied_date = models.DateTimeField(blank=True, null=True) + ) # TODO TP move to PP + steficon_applied_date = models.DateTimeField(blank=True, null=True) # TODO TP move to PP vulnerability_score_min = models.DecimalField( null=True, decimal_places=3, max_digits=6, help_text="Written by a tool such as Corticon.", blank=True, - ) + ) # TODO TP move to PP vulnerability_score_max = models.DecimalField( null=True, decimal_places=3, max_digits=6, help_text="Written by a tool such as Corticon.", blank=True, - ) - excluded_ids = models.TextField(blank=True) - exclusion_reason = models.TextField(blank=True) + ) # TODO TP move to PP + + excluded_ids = models.TextField(blank=True) # TODO TP move to PP, merge with PP.excluded_ids?? + exclusion_reason = models.TextField(blank=True) # TODO TP move to PP, merge with PP.exclusion_reason?? total_households_count = models.PositiveIntegerField( blank=True, null=True, - ) + ) # TODO TP exists in PP total_individuals_count = models.PositiveIntegerField( blank=True, null=True, - ) + ) # TODO TP exists in PP child_male_count = models.PositiveIntegerField( blank=True, null=True, - ) + ) # TODO TP exists in PP child_female_count = models.PositiveIntegerField( blank=True, null=True, - ) + ) # TODO TP exists in PP adult_male_count = models.PositiveIntegerField( blank=True, null=True, - ) + ) # TODO TP exists in PP adult_female_count = models.PositiveIntegerField( blank=True, null=True, - ) + ) # TODO TP exists in PP - # TODO: move to StorageFile - storage_file = models.OneToOneField(StorageFile, blank=True, null=True, on_delete=models.SET_NULL) + storage_file = models.OneToOneField( + StorageFile, blank=True, null=True, on_delete=models.SET_NULL + ) # TODO TP move to PP @property def excluded_household_ids(self) -> List: diff --git a/src/hct_mis_api/apps/targeting/mutations.py b/src/hct_mis_api/apps/targeting/mutations.py index 1a9a2b29a4..77984c1feb 100644 --- a/src/hct_mis_api/apps/targeting/mutations.py +++ b/src/hct_mis_api/apps/targeting/mutations.py @@ -39,6 +39,8 @@ ) from hct_mis_api.apps.targeting.models import ( HouseholdSelection, + TargetingCollectorBlockRuleFilter, + TargetingCollectorRuleFilterBlock, TargetingCriteria, TargetingCriteriaRule, TargetingCriteriaRuleFilter, diff --git a/src/hct_mis_api/apps/targeting/services/targeting_stats_refresher.py b/src/hct_mis_api/apps/targeting/services/targeting_stats_refresher.py index c41e0220f0..17f2ed4f78 100644 --- a/src/hct_mis_api/apps/targeting/services/targeting_stats_refresher.py +++ b/src/hct_mis_api/apps/targeting/services/targeting_stats_refresher.py @@ -9,6 +9,7 @@ from hct_mis_api.apps.targeting.models import TargetPopulation +# TODO TP move to payment plan def refresh_stats(target_population: TargetPopulation) -> TargetPopulation: households_ids = target_population.household_list.values_list("id", flat=True) diff --git a/src/hct_mis_api/apps/targeting/validators.py b/src/hct_mis_api/apps/targeting/validators.py index 5aebe5cf8a..aa80d357af 100644 --- a/src/hct_mis_api/apps/targeting/validators.py +++ b/src/hct_mis_api/apps/targeting/validators.py @@ -1,5 +1,5 @@ import logging -from typing import TYPE_CHECKING, Any, Dict +from typing import TYPE_CHECKING, Any, Dict, List from django.core.exceptions import ValidationError diff --git a/src/hct_mis_api/apps/utils/models.py b/src/hct_mis_api/apps/utils/models.py index 529505d456..39ad4bdf52 100644 --- a/src/hct_mis_api/apps/utils/models.py +++ b/src/hct_mis_api/apps/utils/models.py @@ -631,3 +631,10 @@ def discard_all(cls) -> None: @classmethod def purge(cls) -> None: app.control.purge() + + +class InternalDataFieldModel(models.Model): + internal_data = models.JSONField(default=dict) + + class Meta: + abstract = True diff --git a/src/hct_mis_api/one_time_scripts/create_payment_snapshot.py b/src/hct_mis_api/one_time_scripts/create_payment_snapshot.py index c56242c736..f53629f92f 100644 --- a/src/hct_mis_api/one_time_scripts/create_payment_snapshot.py +++ b/src/hct_mis_api/one_time_scripts/create_payment_snapshot.py @@ -26,7 +26,7 @@ def create_payment_snapshot() -> None: if program_qs: print(f"Processing {program_qs.count()} programs for {ba.name}.") for program in program_qs: - for payment_plan in PaymentPlan.all_objects.filter(program=program): + for payment_plan in PaymentPlan.all_objects.filter(program_cycle__program=program): payments_ids = list( payment_plan.eligible_payments.filter(household_snapshot__isnull=True) .values_list("id", flat=True) diff --git a/src/hct_mis_api/one_time_scripts/migrate_data_to_representations.py b/src/hct_mis_api/one_time_scripts/migrate_data_to_representations.py index 84eb814546..5d247a078c 100644 --- a/src/hct_mis_api/one_time_scripts/migrate_data_to_representations.py +++ b/src/hct_mis_api/one_time_scripts/migrate_data_to_representations.py @@ -23,7 +23,7 @@ IndividualIdentity, IndividualRoleInHousehold, ) -from hct_mis_api.apps.payment.models import Payment, PaymentRecord +from hct_mis_api.apps.payment.models import Payment from hct_mis_api.apps.program.models import Program from hct_mis_api.apps.registration_data.models import RegistrationDataImport from hct_mis_api.apps.targeting.models import HouseholdSelection, TargetPopulation @@ -598,8 +598,6 @@ def adjust_payment_objects(business_area: Optional[BusinessArea] = None) -> None for business_area in business_areas: logger.info(f"Adjusting payments for business area {business_area.name}") adjust_payments(business_area) # type: ignore - logger.info(f"Adjusting payment records for business area {business_area.name}") - adjust_payment_records(business_area) # type: ignore def adjust_payments(business_area: BusinessArea) -> None: @@ -654,46 +652,6 @@ def adjust_payments(business_area: BusinessArea) -> None: del payment_updates -def adjust_payment_records(business_area: BusinessArea) -> None: - """ - Adjust PaymentRecord individuals and households to their representations. - PaymentRecord is already related to program through TargetPopulation. - """ - payment_records_ids = list( - PaymentRecord.objects.filter( - target_population__program__business_area=business_area, household__is_original=True - ).values_list("pk", flat=True) - ) - payment_records_count = len(payment_records_ids) - for batch_start in range(0, payment_records_count, BATCH_SIZE): - batch_end = batch_start + BATCH_SIZE - logger.info(f"Adjusting payment records {batch_start} - {batch_end}/{payment_records_count}") - payment_record_updates = [] - - payment_records_batch = PaymentRecord.objects.filter(id__in=payment_records_ids[batch_start:batch_end]) - for payment_record in payment_records_batch: - payment_record_program = payment_record.target_population.program - if payment_record.head_of_household: - representation_head_of_household = get_individual_representation_per_program_by_old_individual_id( - program=payment_record_program, - old_individual_id=payment_record.head_of_household_id, - ) - else: - representation_head_of_household = None - representation_household = get_household_representation_per_program_by_old_household_id( - program=payment_record_program, - old_household_id=payment_record.household_id, - ) - payment_record.refresh_from_db() - if representation_household: - payment_record.head_of_household = representation_head_of_household - payment_record.household = representation_household - payment_record_updates.append(payment_record) - - PaymentRecord.objects.bulk_update(payment_record_updates, fields=["head_of_household_id", "household_id"]) - del payment_record_updates - - def handle_rdis(rdis: QuerySet, program: Program, hhs_to_ignore: Optional[QuerySet] = None) -> None: rdis_count = rdis.count() for i, rdi in enumerate(rdis): diff --git a/src/hct_mis_api/one_time_scripts/migrate_grievance_for_sync.py b/src/hct_mis_api/one_time_scripts/migrate_grievance_for_sync.py index 8532303a65..c97cb1547a 100644 --- a/src/hct_mis_api/one_time_scripts/migrate_grievance_for_sync.py +++ b/src/hct_mis_api/one_time_scripts/migrate_grievance_for_sync.py @@ -2030,7 +2030,7 @@ def handle_payment_related_tickets(business_area: Optional[BusinessArea] = None) .distinct() ) for payment_verification_ticket in payment_verification_tickets: - payment_obj = payment_verification_ticket.payment_verification.payment_obj + payment_obj = payment_verification_ticket.payment_verification.payment if isinstance(payment_obj, Payment): program = payment_obj.parent.target_population.program elif isinstance(payment_obj, PaymentRecord): diff --git a/src/hct_mis_api/one_time_scripts/migrate_grievance_to_representations.py b/src/hct_mis_api/one_time_scripts/migrate_grievance_to_representations.py index 86e60a1509..2693076b63 100644 --- a/src/hct_mis_api/one_time_scripts/migrate_grievance_to_representations.py +++ b/src/hct_mis_api/one_time_scripts/migrate_grievance_to_representations.py @@ -2080,7 +2080,7 @@ def handle_payment_related_tickets(business_area: Optional[BusinessArea] = None) .distinct() ) for payment_verification_ticket in payment_verification_tickets: - payment_obj = payment_verification_ticket.payment_verification.payment_obj + payment_obj = payment_verification_ticket.payment_verification.payment if isinstance(payment_obj, Payment): program = payment_obj.parent.target_population.program elif isinstance(payment_obj, PaymentRecord): diff --git a/tests/selenium/filters/test_filters.py b/tests/selenium/filters/test_filters.py index ba4a488c09..2cec6bfe7e 100644 --- a/tests/selenium/filters/test_filters.py +++ b/tests/selenium/filters/test_filters.py @@ -13,9 +13,10 @@ from hct_mis_api.apps.grievance.models import GrievanceTicket from hct_mis_api.apps.household.fixtures import create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentPlan, PaymentVerificationPlan from hct_mis_api.apps.program.models import Program @@ -172,23 +173,23 @@ def add_payment_verification() -> None: {"registration_data_import": registration_data_import}, ) - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( ca_id="PP-0000-00-11223344", name="TEST", - program=program, + program_cycle=program.cycles.first(), business_area=BusinessArea.objects.first(), ) - cash_plan2 = CashPlanFactory( + payment_plan2 = PaymentPlanFactory( ca_id="PP-0000-01-00000000", name="TEST", - program=program, + program_cycle=program.cycles.first(), business_area=BusinessArea.objects.first(), ) target_population = TargetPopulation.objects.first() - PaymentRecordFactory( - parent=cash_plan, + PaymentFactory( + parent=payment_plan, household=household, head_of_household=household.head_of_household, target_population=target_population, @@ -196,11 +197,18 @@ def add_payment_verification() -> None: delivered_quantity="21.36", currency="PLN", ) + PaymentVerificationSummaryFactory( + payment_plan=payment_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL + ) + PaymentVerificationSummaryFactory( + payment_plan=payment_plan2, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL + ) + PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL + payment_plan_obj=payment_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL ) PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan2, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL + payment_plan_obj=payment_plan2, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL ) diff --git a/tests/selenium/grievance/grievance_tickets/test_grievance_tickets.py b/tests/selenium/grievance/grievance_tickets/test_grievance_tickets.py index 2a16aefd6d..3275b7b1f4 100644 --- a/tests/selenium/grievance/grievance_tickets/test_grievance_tickets.py +++ b/tests/selenium/grievance/grievance_tickets/test_grievance_tickets.py @@ -24,7 +24,7 @@ create_household_and_individuals, ) from hct_mis_api.apps.household.models import HOST, Household, Individual -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.payment.models import PaymentRecord from hct_mis_api.apps.program.fixtures import ProgramFactory from hct_mis_api.apps.program.models import Program @@ -97,20 +97,18 @@ def hh_with_payment_record(household_without_disabilities: Household) -> Payment targeting_criteria=targeting_criteria, business_area=household_without_disabilities.business_area, ) - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( program=household_without_disabilities.program, business_area=household_without_disabilities.business_area, ) - cash_plan.save() - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household_without_disabilities, target_population=target_population, delivered_quantity_usd=None, business_area=household_without_disabilities.business_area, ) - payment_record.save() - return payment_record + return payment def find_text_of_label(element: WebElement) -> str: diff --git a/tests/selenium/managerial_console/test_managerial_console.py b/tests/selenium/managerial_console/test_managerial_console.py index 2d3e759560..a15e1adcb0 100644 --- a/tests/selenium/managerial_console/test_managerial_console.py +++ b/tests/selenium/managerial_console/test_managerial_console.py @@ -12,7 +12,7 @@ from hct_mis_api.apps.core.models import BusinessArea, DataCollectingType from hct_mis_api.apps.payment.fixtures import ApprovalProcessFactory, PaymentPlanFactory from hct_mis_api.apps.payment.models import PaymentPlan -from hct_mis_api.apps.program.fixtures import ProgramFactory +from hct_mis_api.apps.program.fixtures import ProgramCycleFactory, ProgramFactory from hct_mis_api.apps.program.models import Program from hct_mis_api.apps.targeting.fixtures import ( TargetingCriteriaFactory, @@ -53,15 +53,17 @@ def create_program( @pytest.fixture def create_payment_plan(create_active_test_program: Program, second_test_program: Program) -> PaymentPlan: + program_cycle_active = ProgramCycleFactory(program=create_active_test_program) + program_cycle_second = ProgramCycleFactory(program=second_test_program) PaymentPlanFactory( target_population=TargetPopulationFactory(program=second_test_program), - program=second_test_program, + program_cycle=program_cycle_second, status=PaymentPlan.Status.IN_APPROVAL, business_area=BusinessArea.objects.filter(slug="afghanistan").first(), ) targeting_criteria = TargetingCriteriaFactory() TargetPopulationFactory( - program=create_active_test_program, + program_cycle=program_cycle_active, status=TargetPopulation.STATUS_OPEN, targeting_criteria=targeting_criteria, ) @@ -75,7 +77,6 @@ def create_payment_plan(create_active_test_program: Program, second_test_program status_date=datetime.now(), status=PaymentPlan.Status.IN_APPROVAL, created_by=User.objects.first(), - program=tp.program, program_cycle=tp.program.cycles.first(), total_delivered_quantity=999, total_entitled_quantity=2999, @@ -111,23 +112,24 @@ def test_managerial_console_smoke_test( pageManagerialConsole.getReleaseButton().click() program = Program.objects.filter(name="Test Programm").first() + program_cycle = ProgramCycleFactory(program=program) PaymentPlanFactory( - program=program, + program_cycle=program_cycle, status=PaymentPlan.Status.IN_APPROVAL, business_area=BusinessArea.objects.filter(slug="afghanistan").first(), ) PaymentPlanFactory( - program=program, + program_cycle=program_cycle, status=PaymentPlan.Status.IN_AUTHORIZATION, business_area=BusinessArea.objects.filter(slug="afghanistan").first(), ) PaymentPlanFactory( - program=program, + program_cycle=program_cycle, status=PaymentPlan.Status.IN_REVIEW, business_area=BusinessArea.objects.filter(slug="afghanistan").first(), ) PaymentPlanFactory( - program=program, + program_cycle=program_cycle, status=PaymentPlan.Status.ACCEPTED, business_area=BusinessArea.objects.filter(slug="afghanistan").first(), ) diff --git a/tests/selenium/payment_module/test_payment_plans.py b/tests/selenium/payment_module/test_payment_plans.py index 252c9b0915..1ce3f69657 100644 --- a/tests/selenium/payment_module/test_payment_plans.py +++ b/tests/selenium/payment_module/test_payment_plans.py @@ -243,7 +243,6 @@ def payment_plan_create(program: Program, status: str = PaymentPlan.Status.LOCKE ) payment_plan = PaymentPlanFactory( - program=program, is_follow_up=False, status=status, program_cycle=program_cycle, diff --git a/tests/selenium/payment_verification/test_payment_verification.py b/tests/selenium/payment_verification/test_payment_verification.py index f905899342..195e1b3d00 100644 --- a/tests/selenium/payment_verification/test_payment_verification.py +++ b/tests/selenium/payment_verification/test_payment_verification.py @@ -15,10 +15,8 @@ from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.household.fixtures import create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, PaymentFactory, PaymentPlanFactory, - PaymentRecordFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, PaymentVerificationSummaryFactory, @@ -207,9 +205,9 @@ def payment_verification_creator(channel: str = PaymentVerificationPlan.VERIFICA {"registration_data_import": registration_data_import}, ) - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( name="TEST", - program=program, + program_cycle=program.cycles.first(), business_area=BusinessArea.objects.first(), start_date=datetime.now() - relativedelta(months=1), end_date=datetime.now() + relativedelta(months=1), @@ -222,8 +220,8 @@ def payment_verification_creator(channel: str = PaymentVerificationPlan.VERIFICA targeting_criteria=targeting_criteria, business_area=BusinessArea.objects.first(), ) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, head_of_household=household.head_of_household, target_population=target_population, @@ -232,17 +230,18 @@ def payment_verification_creator(channel: str = PaymentVerificationPlan.VERIFICA currency="PLN", status=GenericPayment.STATUS_DISTRIBUTION_SUCCESS, ) + PaymentVerificationSummaryFactory(payment_plan=payment_plan, verification_channel=channel) payment_verification_plan = PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan, + payment_plan_obj=payment_plan, verification_channel=channel, ) - pv_summary = cash_plan.get_payment_verification_summary + pv_summary = payment_plan.payment_verification_summary pv_summary.activation_date = datetime.now() - relativedelta(months=1) pv_summary.save() pv = PaymentVerificationFactory( - payment_obj=payment_record, + payment=payment, payment_verification_plan=payment_verification_plan, status=PV.STATUS_PENDING, ) diff --git a/tests/selenium/people/test_people.py b/tests/selenium/people/test_people.py index 065236e5ae..c44c2ae2c9 100644 --- a/tests/selenium/people/test_people.py +++ b/tests/selenium/people/test_people.py @@ -15,7 +15,7 @@ create_individual_document, ) from hct_mis_api.apps.household.models import HOST, SEEING, Individual -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.payment.models import GenericPayment, PaymentRecord from hct_mis_api.apps.program.fixtures import ProgramFactory from hct_mis_api.apps.program.models import Program @@ -64,9 +64,9 @@ def add_people(social_worker_program: Program) -> List: def add_people_with_payment_record(add_people: List) -> PaymentRecord: program = Program.objects.filter(name="Worker Program").first() - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( name="TEST", - program=program, + program_cycle=program.cycles.first(), business_area=BusinessArea.objects.first(), start_date=datetime.now() - relativedelta(months=1), end_date=datetime.now() + relativedelta(months=1), @@ -79,9 +79,9 @@ def add_people_with_payment_record(add_people: List) -> PaymentRecord: targeting_criteria=targeting_criteria, business_area=BusinessArea.objects.first(), ) - payment_record = PaymentRecordFactory( + payment = PaymentFactory( household=add_people[1], - parent=cash_plan, + parent=payment_plan, target_population=target_population, entitlement_quantity="21.36", delivered_quantity="21.36", @@ -90,7 +90,7 @@ def add_people_with_payment_record(add_people: List) -> PaymentRecord: ) add_people[1].total_cash_received_usd = "21.36" add_people[1].save() - return payment_record + return payment def get_program_with_dct_type_and_name( diff --git a/tests/selenium/people/test_people_periodic_data_update.py b/tests/selenium/people/test_people_periodic_data_update.py index c07729e89b..225f6e8d78 100644 --- a/tests/selenium/people/test_people_periodic_data_update.py +++ b/tests/selenium/people/test_people_periodic_data_update.py @@ -17,7 +17,7 @@ ) from hct_mis_api.apps.household.fixtures import create_household_and_individuals from hct_mis_api.apps.household.models import HOST, SEEING, Individual -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.payment.models import GenericPayment from hct_mis_api.apps.periodic_data_update.fixtures import ( PeriodicDataUpdateTemplateFactory, @@ -88,9 +88,9 @@ def date_attribute(program: Program) -> FlexibleAttribute: def individual(add_people: Individual) -> Individual: program = Program.objects.filter(name="Test Program").first() - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( name="TEST", - program=program, + program_cycle=program.cycles.first(), business_area=BusinessArea.objects.first(), start_date=datetime.now() - relativedelta(months=1), end_date=datetime.now() + relativedelta(months=1), @@ -103,9 +103,9 @@ def individual(add_people: Individual) -> Individual: targeting_criteria=targeting_criteria, business_area=BusinessArea.objects.first(), ) - PaymentRecordFactory( + PaymentFactory( household=add_people.household, - parent=cash_plan, + parent=payment_plan, target_population=target_population, entitlement_quantity="21.36", delivered_quantity="21.36", diff --git a/tests/selenium/program_details/test_program_details.py b/tests/selenium/program_details/test_program_details.py index 2973a7ad11..cc55451f79 100644 --- a/tests/selenium/program_details/test_program_details.py +++ b/tests/selenium/program_details/test_program_details.py @@ -169,7 +169,6 @@ def get_program_without_cycle_end_date( ) program_cycle = ProgramCycle.objects.get(program=program) PaymentPlanFactory( - program=program, program_cycle=program_cycle, total_entitled_quantity_usd=Decimal(1234.99), total_delivered_quantity_usd=Decimal(50.01), diff --git a/tests/unit/apps/core/test_exchange_rates.py b/tests/unit/apps/core/test_exchange_rates.py index 6312604c00..4d130948bd 100644 --- a/tests/unit/apps/core/test_exchange_rates.py +++ b/tests/unit/apps/core/test_exchange_rates.py @@ -16,10 +16,10 @@ from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.household.fixtures import create_household from hct_mis_api.apps.payment.fixtures import ( - RealCashPlanFactory, - RealPaymentRecordFactory, + FinancialServiceProviderFactory, + PaymentFactory, + PaymentPlanFactory, RealProgramFactory, - ServiceProviderFactory, ) from hct_mis_api.apps.payment.models import PaymentRecord from tests.unit.apps.core.test_files.exchange_rates_api_response import ( @@ -242,25 +242,26 @@ def setUpTestData(cls) -> None: create_household( household_args={"size": 2, "business_area": business_area}, ) - ServiceProviderFactory.create_batch(3) + FinancialServiceProviderFactory.create_batch(3) program = RealProgramFactory() - cash_plans_with_currency = ( + program = program.cycles.first() + payment_plans_with_currency = ( ( "PLN", - RealCashPlanFactory(program=program, dispersion_date=timezone.make_aware(datetime(2021, 4, 4))), + PaymentPlanFactory(program_cycle=program, dispersion_date=timezone.make_aware(datetime(2021, 4, 4))), ), # x_rate == 3.973 ( "AFN", - RealCashPlanFactory(program=program, dispersion_date=timezone.make_aware(datetime(2020, 3, 3))), + PaymentPlanFactory(program=program, dispersion_date=timezone.make_aware(datetime(2020, 3, 3))), ), # x_rate == 76.55 ( "USD", - RealCashPlanFactory(program=program, dispersion_date=timezone.make_aware(datetime(2020, 3, 3))), + PaymentPlanFactory(program=program, dispersion_date=timezone.make_aware(datetime(2020, 3, 3))), ), # x_rate == 1 ) - for currency, cash_plan in cash_plans_with_currency: - RealPaymentRecordFactory( - parent=cash_plan, + for currency, payment_plan in payment_plans_with_currency: + PaymentFactory( + parent=payment_plan, currency=currency, delivered_quantity=200, ) diff --git a/tests/unit/apps/core/test_hope_redirect.py b/tests/unit/apps/core/test_hope_redirect.py index 34f401ef9b..bb6cdcbe78 100644 --- a/tests/unit/apps/core/test_hope_redirect.py +++ b/tests/unit/apps/core/test_hope_redirect.py @@ -3,10 +3,11 @@ from hct_mis_api.apps.core.hope_redirect import HopeRedirect, get_hope_redirect from hct_mis_api.apps.household.fixtures import create_household_and_individuals from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentVerification, PaymentVerificationPlan from hct_mis_api.apps.program.fixtures import ProgramFactory @@ -31,11 +32,11 @@ def setUpTestData(cls) -> None: has_data_sharing_agreement=True, ) program = ProgramFactory(id="e6537f1e-27b5-4179-a443-d42498fb0478") - CashPlanFactory( + PaymentPlanFactory( id="0272dd2d-c41e-435d-9587-6ba280678c54", ca_id="B4M-21-CSH-00004", business_area=business_area, - program=program, + program_cycle=program.cycles.first(), ) household, _ = create_household_and_individuals( @@ -57,13 +58,14 @@ def setUpTestData(cls) -> None: ], ) - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( name="TEST", - program=program, + program_cycle=program.cycles.first(), business_area=business_area, ) + PaymentVerificationSummaryFactory(payment_plan=payment_plan) payment_verification_plan = PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan, status=PaymentVerificationPlan.STATUS_ACTIVE + payment_plan_obj=payment_plan, status=PaymentVerificationPlan.STATUS_ACTIVE ) target_population = TargetPopulationFactory( @@ -72,8 +74,8 @@ def setUpTestData(cls) -> None: targeting_criteria=(TargetingCriteriaFactory()), business_area=business_area, ) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, target_population=target_population, ca_id="P8F-21-CSH-00031-0000006", @@ -82,7 +84,7 @@ def setUpTestData(cls) -> None: PaymentVerificationFactory( id="a76bfe6f-c767-4b7f-9671-6df10b8095cc", payment_verification_plan=payment_verification_plan, - payment_obj=payment_record, + payment=payment, status=PaymentVerification.STATUS_PENDING, ) diff --git a/tests/unit/apps/grievance/test_filter_already_existing_tickets.py b/tests/unit/apps/grievance/test_filter_already_existing_tickets.py index 6e00ce4627..9ab98b0c21 100644 --- a/tests/unit/apps/grievance/test_filter_already_existing_tickets.py +++ b/tests/unit/apps/grievance/test_filter_already_existing_tickets.py @@ -21,7 +21,7 @@ ) from hct_mis_api.apps.grievance.models import GrievanceTicket from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.program.fixtures import ProgramFactory @@ -97,19 +97,19 @@ def setUpTestData(cls) -> None: {"given_name": "Jane", "family_name": "XDoe", "middle_name": "", "full_name": "Jane XDoe"}, ) program = ProgramFactory(business_area=cls.business_area) - cash_plan = CashPlanFactory(program=program, business_area=cls.business_area) - cls.payment_record = PaymentRecordFactory( + payment_plan = PaymentPlanFactory(program_cycle=program.cycles.first(), business_area=cls.business_area) + cls.payment = PaymentFactory( household=cls.household_1, full_name=cls.individuals_1[0].full_name, business_area=cls.business_area, - parent=cash_plan, + parent=payment_plan, currency="PLN", ) - cls.payment_record2 = PaymentRecordFactory( + cls.payment2 = PaymentFactory( household=cls.household_1, full_name=cls.individuals_1[0].full_name, business_area=cls.business_area, - parent=cash_plan, + parent=payment_plan, currency="PLN", ) grievance_1 = GrievanceTicketFactory( @@ -130,7 +130,7 @@ def setUpTestData(cls) -> None: cls.ticket = SensitiveGrievanceTicketWithoutExtrasFactory( household=cls.household_1, individual=cls.individuals_1[0], - payment_obj=cls.payment_record, + payment_obj=cls.payment, ticket=grievance_1, ) SensitiveGrievanceTicketWithoutExtrasFactory( diff --git a/tests/unit/apps/grievance/test_grievance_create_complaint_ticket.py b/tests/unit/apps/grievance/test_grievance_create_complaint_ticket.py index 970a861af8..4419aebc5e 100644 --- a/tests/unit/apps/grievance/test_grievance_create_complaint_ticket.py +++ b/tests/unit/apps/grievance/test_grievance_create_complaint_ticket.py @@ -14,7 +14,7 @@ from hct_mis_api.apps.geo.fixtures import AreaFactory, AreaTypeFactory from hct_mis_api.apps.grievance.models import GrievanceTicket from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.program.fixtures import ProgramFactory from hct_mis_api.apps.program.models import Program @@ -69,19 +69,19 @@ def setUpTestData(cls) -> None: cls.program = ProgramFactory(status=Program.ACTIVE, business_area=cls.business_area) cls.update_partner_access_to_program(partner, cls.program) - cash_plan = CashPlanFactory(program=cls.program, business_area=cls.business_area) - cls.payment_record = PaymentRecordFactory( + payment_plan = PaymentPlanFactory(program_cycle=cls.program.cycles.first(), business_area=cls.business_area) + cls.payment = PaymentFactory( household=cls.household, full_name=cls.individuals[0].full_name, business_area=cls.business_area, - parent=cash_plan, + parent=payment_plan, currency="PLN", ) - cls.second_payment_record = PaymentRecordFactory( + cls.second_payment = PaymentFactory( household=cls.household, full_name=f"{cls.individuals[0].full_name} second Individual", business_area=cls.business_area, - parent=cash_plan, + parent=payment_plan, currency="PLN", ) super().setUpTestData() @@ -101,7 +101,7 @@ def test_create_complaint_ticket(self, _: Any, permissions: List[Permissions]) - input_data = self._create_variables( household=self.id_to_base64(self.household.id, "HouseholdNode"), individual=self.id_to_base64(self.individuals[0].id, "IndividualNode"), - payment_records=[self.id_to_base64(self.payment_record.id, "PaymentRecordNode")], + payment_records=[self.id_to_base64(self.payment.id, "PaymentNode")], ) self.snapshot_graphql_request( @@ -110,15 +110,15 @@ def test_create_complaint_ticket(self, _: Any, permissions: List[Permissions]) - variables=input_data, ) - def test_create_a_ticket_per_payment_record(self) -> None: + def test_create_a_ticket_per_payment(self) -> None: self.create_user_role_with_permissions(self.user, [Permissions.GRIEVANCES_CREATE], self.business_area) input_data = self._create_variables( household=self.id_to_base64(self.household.id, "HouseholdNode"), individual=self.id_to_base64(self.individuals[0].id, "IndividualNode"), payment_records=[ - self.id_to_base64(self.payment_record.id, "PaymentRecordNode"), - self.id_to_base64(self.second_payment_record.id, "PaymentRecordNode"), + self.id_to_base64(self.payment.id, "PaymentNode"), + self.id_to_base64(self.second_payment.id, "PaymentNode"), ], ) @@ -169,8 +169,8 @@ def test_create_complaint_ticket_with_two_payment_records(self, _: Any, permissi household=self.id_to_base64(self.household.id, "HouseholdNode"), individual=self.id_to_base64(self.individuals[0].id, "IndividualNode"), payment_records=[ - self.id_to_base64(self.payment_record.id, "PaymentRecordNode"), - self.id_to_base64(self.second_payment_record.id, "PaymentRecordNode"), + self.id_to_base64(self.payment.id, "PaymentNode"), + self.id_to_base64(self.second_payment.id, "PaymentNode"), ], ) @@ -194,7 +194,7 @@ def test_create_complaint_ticket_without_household(self, _: Any, permissions: Li input_data = self._create_variables( individual=self.id_to_base64(self.individuals[0].id, "IndividualNode"), - payment_records=[self.id_to_base64(self.payment_record.id, "PaymentRecordNode")], + payment_records=[self.id_to_base64(self.payment.id, "PaymentNode")], ) self.snapshot_graphql_request( @@ -217,7 +217,7 @@ def test_create_complaint_ticket_without_individual(self, _: Any, permissions: L input_data = self._create_variables( household=self.id_to_base64(self.household.id, "HouseholdNode"), - payment_records=[self.id_to_base64(self.payment_record.id, "PaymentRecordNode")], + payment_records=[self.id_to_base64(self.payment.id, "PaymentNode")], ) self.snapshot_graphql_request( diff --git a/tests/unit/apps/grievance/test_grievance_create_sensitive_ticket.py b/tests/unit/apps/grievance/test_grievance_create_sensitive_ticket.py index 68c4f1e56b..d50f98a0f3 100644 --- a/tests/unit/apps/grievance/test_grievance_create_sensitive_ticket.py +++ b/tests/unit/apps/grievance/test_grievance_create_sensitive_ticket.py @@ -14,7 +14,7 @@ from hct_mis_api.apps.geo.fixtures import AreaFactory, AreaTypeFactory from hct_mis_api.apps.grievance.models import GrievanceTicket from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.program.fixtures import ProgramFactory from hct_mis_api.apps.program.models import Program @@ -63,24 +63,28 @@ def setUpTestData(cls) -> None: ) cls.admin_area = AreaFactory(name="City Test", area_type=area_type, p_code="asfdsfg") - cls.household, cls.individuals = create_household( + cls.household1, cls.individuals1 = create_household( + {"size": 1, "business_area": cls.business_area}, + {"given_name": "John", "family_name": "Doe", "middle_name": "", "full_name": "John Doe"}, + ) + cls.household2, cls.individuals2 = create_household( {"size": 1, "business_area": cls.business_area}, {"given_name": "John", "family_name": "Doe", "middle_name": "", "full_name": "John Doe"}, ) cls.program = ProgramFactory(status=Program.ACTIVE, business_area=cls.business_area) - cash_plan = CashPlanFactory(program=cls.program, business_area=cls.business_area) - cls.payment_record = PaymentRecordFactory( - household=cls.household, - full_name=cls.individuals[0].full_name, + payment_plan = PaymentPlanFactory(program_cycle=cls.program.cycles.first(), business_area=cls.business_area) + cls.payment = PaymentFactory( + household=cls.household1, + full_name=cls.individuals1[0].full_name, business_area=cls.business_area, - parent=cash_plan, + parent=payment_plan, currency="PLN", ) - cls.second_payment_record = PaymentRecordFactory( - household=cls.household, - full_name=f"{cls.individuals[0].full_name} second Individual", + cls.second_payment = PaymentFactory( + household=cls.household2, + full_name=f"{cls.individuals2[0].full_name} second Individual", business_area=cls.business_area, - parent=cash_plan, + parent=payment_plan, currency="PLN", ) cls.update_partner_access_to_program(partner, cls.program) @@ -111,8 +115,8 @@ def test_create_sensitive_ticket(self, _: Any, permissions: List[Permissions]) - "extras": { "category": { "sensitiveGrievanceTicketExtras": { - "household": self.id_to_base64(self.household.id, "HouseholdNode"), - "individual": self.id_to_base64(self.individuals[0].id, "IndividualNode"), + "household": self.id_to_base64(self.household1.id, "HouseholdNode"), + "individual": self.id_to_base64(self.individuals1[0].id, "IndividualNode"), } } }, @@ -150,8 +154,8 @@ def test_create_sensitive_ticket_wrong_extras(self, _: Any, permissions: List[Pe "extras": { "category": { "grievanceComplaintTicketExtras": { - "household": self.id_to_base64(self.household.id, "HouseholdNode"), - "individual": self.id_to_base64(self.individuals[0].id, "IndividualNode"), + "household": self.id_to_base64(self.household1.id, "HouseholdNode"), + "individual": self.id_to_base64(self.individuals1[0].id, "IndividualNode"), } } }, @@ -188,9 +192,9 @@ def test_create_sensitive_ticket_without_issue_type(self, _: Any, permissions: L "extras": { "category": { "sensitiveGrievanceTicketExtras": { - "household": self.id_to_base64(self.household.id, "HouseholdNode"), - "individual": self.id_to_base64(self.individuals[0].id, "IndividualNode"), - "paymentRecord": [self.id_to_base64(self.payment_record.id, "PaymentRecordNode")], + "household": self.id_to_base64(self.household1.id, "HouseholdNode"), + "individual": self.id_to_base64(self.individuals1[0].id, "IndividualNode"), + "paymentRecord": [self.id_to_base64(self.payment.id, "PaymentNode")], } } }, @@ -228,11 +232,11 @@ def test_create_sensitive_ticket_with_two_payment_records(self, _: Any, permissi "extras": { "category": { "sensitiveGrievanceTicketExtras": { - "household": self.id_to_base64(self.household.id, "HouseholdNode"), - "individual": self.id_to_base64(self.individuals[0].id, "IndividualNode"), + "household": self.id_to_base64(self.household1.id, "HouseholdNode"), + "individual": self.id_to_base64(self.individuals1[0].id, "IndividualNode"), "paymentRecord": [ - self.id_to_base64(self.payment_record.id, "PaymentRecordNode"), - self.id_to_base64(self.second_payment_record.id, "PaymentRecordNode"), + self.id_to_base64(self.payment.id, "PaymentNode"), + self.id_to_base64(self.second_payment.id, "PaymentNode"), ], } } @@ -271,8 +275,8 @@ def test_create_sensitive_ticket_without_payment_record(self, _: Any, permission "extras": { "category": { "sensitiveGrievanceTicketExtras": { - "household": self.id_to_base64(self.household.id, "HouseholdNode"), - "individual": self.id_to_base64(self.individuals[0].id, "IndividualNode"), + "household": self.id_to_base64(self.household1.id, "HouseholdNode"), + "individual": self.id_to_base64(self.individuals1[0].id, "IndividualNode"), } } }, @@ -310,7 +314,7 @@ def test_create_sensitive_ticket_without_household(self, _: Any, permissions: Li "extras": { "category": { "sensitiveGrievanceTicketExtras": { - "individual": self.id_to_base64(self.individuals[0].id, "IndividualNode") + "individual": self.id_to_base64(self.individuals1[0].id, "IndividualNode") } } }, @@ -348,7 +352,7 @@ def test_create_sensitive_ticket_without_individual(self, _: Any, permissions: L "extras": { "category": { "sensitiveGrievanceTicketExtras": { - "household": self.id_to_base64(self.household.id, "HouseholdNode") + "household": self.id_to_base64(self.household1.id, "HouseholdNode") } } }, diff --git a/tests/unit/apps/grievance/test_grievance_update_payment_verification_ticket.py b/tests/unit/apps/grievance/test_grievance_update_payment_verification_ticket.py index fa5c77ecc7..6d5ddfc98a 100644 --- a/tests/unit/apps/grievance/test_grievance_update_payment_verification_ticket.py +++ b/tests/unit/apps/grievance/test_grievance_update_payment_verification_ticket.py @@ -15,8 +15,8 @@ from hct_mis_api.apps.grievance.models import GrievanceTicket from hct_mis_api.apps.household.fixtures import create_household_and_individuals from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, ) @@ -74,11 +74,11 @@ def setUpTestData(cls) -> None: cls.program = ProgramFactory(id="e6537f1e-27b5-4179-a443-d42498fb0478", status=Program.ACTIVE) cls.update_partner_access_to_program(partner, cls.program) - CashPlanFactory( + PaymentPlanFactory( id="0272dd2d-c41e-435d-9587-6ba280678c54", - ca_id="B4M-21-CSH-00004", + unicef_id="B4M-21-CSH-00004", business_area=cls.business_area, - program=cls.program, + program_cycle=cls.program.cycles.first(), ) household, _ = create_household_and_individuals( @@ -100,13 +100,13 @@ def setUpTestData(cls) -> None: ], ) - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( name="TEST", - program=cls.program, + program_cycle=cls.program.cycles.first(), business_area=cls.business_area, ) payment_verification_plan = PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan, status=PaymentVerificationPlan.STATUS_ACTIVE + payment_plan=payment_plan, status=PaymentVerificationPlan.STATUS_ACTIVE ) target_population = TargetPopulationFactory( @@ -115,8 +115,8 @@ def setUpTestData(cls) -> None: targeting_criteria=(TargetingCriteriaFactory()), business_area=cls.business_area, ) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, target_population=target_population, ca_id="P8F-21-CSH-00031-123123", @@ -125,7 +125,7 @@ def setUpTestData(cls) -> None: payment_verification = PaymentVerificationFactory( id="a76bfe6f-c767-4b7f-9671-6df10b8095cc", payment_verification_plan=payment_verification_plan, - payment_obj=payment_record, + payment=payment, status=PaymentVerification.STATUS_RECEIVED_WITH_ISSUES, ) cls.ticket = TicketPaymentVerificationDetailsFactory(payment_verification=payment_verification) diff --git a/tests/unit/apps/household/test_dashboard_queries.py b/tests/unit/apps/household/test_dashboard_queries.py index e7c4cb1e82..1e4c230147 100644 --- a/tests/unit/apps/household/test_dashboard_queries.py +++ b/tests/unit/apps/household/test_dashboard_queries.py @@ -9,12 +9,7 @@ from hct_mis_api.apps.core.fixtures import create_afghanistan from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentFactory, - PaymentPlanFactory, - PaymentRecordFactory, -) +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.program.fixtures import ProgramFactory @@ -167,47 +162,47 @@ def setUpTestData(cls) -> None: "male_age_group_60_count": 0, }, ) - cash_plan1 = CashPlanFactory(program=cls.program_one) + payment_plan1 = PaymentPlanFactory(program_cycle=cls.program_one.cycles.first()) delivery_date = timezone.datetime(2021, 10, 10, tzinfo=utc) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=delivery_date, household=household1, delivered_quantity_usd=100, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=delivery_date, household=household2, delivered_quantity_usd=100, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=delivery_date, household=household3, delivered_quantity_usd=100, currency="PLN", ) - payment_plan1 = PaymentPlanFactory(program=cls.program_two) + payment_plan2 = PaymentPlanFactory(program_cycle=cls.program_two.cycles.first()) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=delivery_date, delivered_quantity_usd=100, household=household1, currency="PLN", ) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=delivery_date, delivered_quantity_usd=100, household=household2, currency="PLN", ) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=delivery_date, delivered_quantity_usd=100, household=household4, diff --git a/tests/unit/apps/household/test_detecting_paid_hhs_loaded_via_sf.py b/tests/unit/apps/household/test_detecting_paid_hhs_loaded_via_sf.py index dd5d67ea91..c056e48838 100644 --- a/tests/unit/apps/household/test_detecting_paid_hhs_loaded_via_sf.py +++ b/tests/unit/apps/household/test_detecting_paid_hhs_loaded_via_sf.py @@ -10,7 +10,7 @@ from hct_mis_api.apps.household.management.commands.detect_paid_households import ( find_paid_households, ) -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory class TestDetectingAlreadyPaidHouseholds(TestCase): @@ -31,7 +31,7 @@ def setUpTestData(cls) -> None: has_data_sharing_agreement=True, ) - cls.cash_plan = CashPlanFactory(business_area=cls.business_area) + cls.payment_plan = PaymentPlanFactory(business_area=cls.business_area) cls.document_type = DocumentTypeFactory(key="tax_id") ## @@ -50,11 +50,11 @@ def setUpTestData(cls) -> None: ) cls.household_2.storage_obj = None cls.household_2.save() - PaymentRecordFactory( + PaymentFactory( household=cls.household_2, full_name=cls.individuals_2[0].full_name, business_area=cls.business_area, - parent=cls.cash_plan, + parent=cls.payment_plan, currency="PLN", ) cls.individuals_2[0].documents.add( diff --git a/tests/unit/apps/household/test_household_admin.py b/tests/unit/apps/household/test_household_admin.py index 53612c2549..542261280b 100644 --- a/tests/unit/apps/household/test_household_admin.py +++ b/tests/unit/apps/household/test_household_admin.py @@ -122,7 +122,7 @@ def mock_message_user(*args: Any, **kwargs: Any) -> None: ) self.assertIsNotNone(self.household.withdrawn_date) self.assertEqual( - self.household.user_fields["withdrawn_tag"], + self.household.internal_data["withdrawn_tag"], tag, ) self.assertEqual( diff --git a/tests/unit/apps/household/test_household_delivered_quantities_query.py b/tests/unit/apps/household/test_household_delivered_quantities_query.py index 1aa78e2a4a..3fea97c437 100644 --- a/tests/unit/apps/household/test_household_delivered_quantities_query.py +++ b/tests/unit/apps/household/test_household_delivered_quantities_query.py @@ -10,12 +10,7 @@ from hct_mis_api.apps.core.fixtures import create_afghanistan from hct_mis_api.apps.geo import models as geo_models from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentFactory, - PaymentPlanFactory, - PaymentRecordFactory, -) +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.payment.models import PaymentRecord from hct_mis_api.apps.program.fixtures import ProgramFactory @@ -54,8 +49,8 @@ def setUpTestData(cls) -> None: household.program = program household.save() - PaymentRecordFactory( - parent=CashPlanFactory(program=program), + PaymentFactory( + parent=PaymentPlanFactory(program_cycle=program.cycles.first()), currency="AFG", delivered_quantity_usd=50, delivered_quantity=100, @@ -64,7 +59,7 @@ def setUpTestData(cls) -> None: ) PaymentFactory( - parent=PaymentPlanFactory(program=program), + parent=PaymentPlanFactory(program_cycle=program.cycles.first()), currency="AFG", delivered_quantity_usd=33, delivered_quantity=133, diff --git a/tests/unit/apps/household/test_household_status_endpoint.py b/tests/unit/apps/household/test_household_status_endpoint.py index 6b59193b44..a1247c8087 100644 --- a/tests/unit/apps/household/test_household_status_endpoint.py +++ b/tests/unit/apps/household/test_household_status_endpoint.py @@ -21,7 +21,7 @@ ROLE_NO_ROLE, PendingIndividualRoleInHousehold, ) -from hct_mis_api.apps.payment.fixtures import PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory from hct_mis_api.apps.registration_data.fixtures import RegistrationDataImportFactory from hct_mis_api.apps.targeting.fixtures import TargetPopulationFactory from hct_mis_api.apps.targeting.models import HouseholdSelection, TargetPopulation @@ -185,7 +185,7 @@ def test_getting_individual_with_status_paid(self) -> None: document_type = DocumentTypeFactory(key=IDENTIFICATION_TYPE_TO_KEY_MAPPING[IDENTIFICATION_TYPE_TAX_ID]) document = PendingDocumentFactory(individual=individual, type=document_type) tax_id = document.document_number - payment_record = PaymentRecordFactory(household=household, currency="PLN") + payment = PaymentFactory(household=household, currency="PLN") response = self.api_client.get(f"/api/hh-status?tax_id={tax_id}") self.assertEqual(response.status_code, 200) @@ -193,7 +193,7 @@ def test_getting_individual_with_status_paid(self) -> None: self.assertIsNotNone(data["info"]) info = data["info"] self.assertEqual(info["status"], "paid") - self.assertEqual(info["date"], _time(payment_record.updated_at)) + self.assertEqual(info["date"], _time(payment.updated_at)) def test_getting_non_existent_household(self) -> None: response = self.api_client.get("/api/hh-status?registration_id=non-existent") diff --git a/tests/unit/apps/payment/services/test_dashboard_service.py b/tests/unit/apps/payment/services/test_dashboard_service.py index 686cbd9095..295cf562b6 100644 --- a/tests/unit/apps/payment/services/test_dashboard_service.py +++ b/tests/unit/apps/payment/services/test_dashboard_service.py @@ -10,11 +10,9 @@ from hct_mis_api.apps.household.fixtures import create_household from hct_mis_api.apps.household.models import Household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, FinancialServiceProviderFactory, PaymentFactory, PaymentPlanFactory, - PaymentRecordFactory, generate_delivery_mechanisms, ) from hct_mis_api.apps.payment.models import DeliveryMechanism, GenericPayment @@ -81,9 +79,9 @@ def setUp(self) -> None: household_args={"size": 2, "business_area": business_area, "admin_area": admin_area3, "program": program}, ) - cash_plan = CashPlanFactory(program=program, business_area=business_area) - PaymentRecordFactory( - parent=cash_plan, + payment_plan1 = PaymentPlanFactory(program_cycle=program.cycles.first(), business_area=business_area) + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), household=household1, delivery_type=self.dm_cash, @@ -93,8 +91,8 @@ def setUp(self) -> None: business_area=business_area, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan, + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), household=household2, delivery_type=self.dm_voucher, @@ -104,8 +102,8 @@ def setUp(self) -> None: business_area=business_area, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan, + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 11, 10, tzinfo=utc), household=household3, delivery_type=self.dm_cash, @@ -116,9 +114,9 @@ def setUp(self) -> None: currency="PLN", ) - payment_plan = PaymentPlanFactory(program=program, business_area=business_area) + payment_plan2 = PaymentPlanFactory(program_cycle=program.cycles.first(), business_area=business_area) PaymentFactory( - parent=payment_plan, + parent=payment_plan2, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), delivery_type=self.dm_cash, delivered_quantity=10 + num, @@ -130,7 +128,7 @@ def setUp(self) -> None: financial_service_provider=fsp, ) PaymentFactory( - parent=payment_plan, + parent=payment_plan2, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), delivery_type=self.dm_voucher, delivered_quantity=20 + num, @@ -142,7 +140,7 @@ def setUp(self) -> None: financial_service_provider=fsp, ) PaymentFactory( - parent=payment_plan, + parent=payment_plan2, delivery_date=timezone.datetime(2021, 11, 10, tzinfo=utc), delivery_type=self.dm_cash, delivered_quantity=30 + num, diff --git a/tests/unit/apps/payment/test_action_payment_plan_mutation.py b/tests/unit/apps/payment/test_action_payment_plan_mutation.py index 1313472b56..a4c9290de9 100644 --- a/tests/unit/apps/payment/test_action_payment_plan_mutation.py +++ b/tests/unit/apps/payment/test_action_payment_plan_mutation.py @@ -22,7 +22,6 @@ FinancialServiceProviderFactory, PaymentFactory, PaymentPlanFactory, - RealProgramFactory, generate_delivery_mechanisms, ) from hct_mis_api.apps.payment.models import ( @@ -30,6 +29,7 @@ DeliveryMechanism, PaymentPlan, ) +from hct_mis_api.apps.program.fixtures import ProgramCycleFactory from hct_mis_api.apps.registration_data.fixtures import RegistrationDataImportFactory @@ -96,7 +96,9 @@ def setUpTestData(cls) -> None: ) cls.business_area = BusinessArea.objects.get(slug="afghanistan") - cls.payment_plan = PaymentPlanFactory.create(business_area=cls.business_area, program=RealProgramFactory()) + cls.payment_plan = PaymentPlanFactory.create( + business_area=cls.business_area, program_cycle=ProgramCycleFactory() + ) cls.registration_data_import = RegistrationDataImportFactory(business_area=cls.business_area) household, individuals = create_household_and_individuals( household_data={ diff --git a/tests/unit/apps/payment/test_all_payment_plan_queries.py b/tests/unit/apps/payment/test_all_payment_plan_queries.py index a680775e29..f9274d3b5b 100644 --- a/tests/unit/apps/payment/test_all_payment_plan_queries.py +++ b/tests/unit/apps/payment/test_all_payment_plan_queries.py @@ -35,24 +35,20 @@ def create_child_payment_plans(pp: PaymentPlan) -> None: fpp1 = PaymentPlanFactory( id="56aca38c-dc16-48a9-ace4-70d88b41d462", - dispersion_start_date=datetime(2020, 8, 10), - dispersion_end_date=datetime(2020, 12, 10), is_follow_up=True, source_payment_plan=pp, - program__cycle__start_date=timezone.datetime(2020, 9, 10, tzinfo=utc).date(), - program__cycle__end_date=timezone.datetime(2020, 11, 10, tzinfo=utc).date(), + dispersion_start_date=datetime(2020, 8, 10), + dispersion_end_date=datetime(2020, 12, 10), ) fpp1.unicef_id = "PP-0060-20-00000003" fpp1.save() fpp2 = PaymentPlanFactory( id="5b04f7c3-579a-48dd-a232-424daaefffe7", - dispersion_start_date=datetime(2020, 8, 10), - dispersion_end_date=datetime(2020, 12, 10), is_follow_up=True, source_payment_plan=pp, - program__cycle__start_date=timezone.datetime(2020, 9, 10, tzinfo=utc).date(), - program__cycle__end_date=timezone.datetime(2020, 11, 10, tzinfo=utc).date(), + dispersion_start_date=datetime(2020, 8, 10), + dispersion_end_date=datetime(2020, 12, 10), ) fpp2.unicef_id = "PP-0060-20-00000004" fpp2.save() @@ -236,7 +232,6 @@ def setUpTestData(cls) -> None: ) program_cycle = program.cycles.first() cls.pp = PaymentPlanFactory( - program=program, program_cycle=program_cycle, dispersion_start_date=datetime(2020, 8, 10), dispersion_end_date=datetime(2020, 12, 10), @@ -276,7 +271,6 @@ def setUpTestData(cls) -> None: # create hard conflicted payment cls.pp_conflicted = PaymentPlanFactory( - program=program, program_cycle=program_cycle, status=PaymentPlan.Status.LOCKED, dispersion_start_date=cls.pp.dispersion_start_date + relativedelta(months=2), @@ -468,7 +462,6 @@ def test_payment_node_with_legacy_data(self) -> None: cycle__end_date=timezone.datetime(2023, 11, 10, tzinfo=utc).date(), ) new_pp = PaymentPlanFactory( - program=program, program_cycle=program.cycles.first(), dispersion_start_date=datetime(2023, 8, 10), dispersion_end_date=datetime(2023, 12, 10), diff --git a/tests/unit/apps/payment/test_all_payment_records.py b/tests/unit/apps/payment/test_all_payment_records.py index f06f4d9628..3bfec0be5a 100644 --- a/tests/unit/apps/payment/test_all_payment_records.py +++ b/tests/unit/apps/payment/test_all_payment_records.py @@ -7,7 +7,7 @@ from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.core.utils import encode_id_base64 from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory class TestAllPaymentRecords(APITestCase): @@ -29,35 +29,35 @@ def setUpTestData(cls) -> None: (cls.household2, _) = create_household(household_args={"size": 1}) (cls.household3, _) = create_household(household_args={"size": 1}) business_area = BusinessArea.objects.get(slug="afghanistan") - cls.cash_plan1 = CashPlanFactory(funds_commitment="123456", exchange_rate=None) - cls.cash_plan2 = CashPlanFactory(funds_commitment="123456", exchange_rate=None) - cls.cash_plan3 = CashPlanFactory(funds_commitment="123456", exchange_rate=None) - PaymentRecordFactory.create_batch( + cls.payment_plan1 = PaymentPlanFactory(funds_commitment="123456", exchange_rate=None) + cls.payment_plan2 = PaymentPlanFactory(funds_commitment="123456", exchange_rate=None) + cls.payment_plan3 = PaymentPlanFactory(funds_commitment="123456", exchange_rate=None) + PaymentFactory.create_batch( 2, business_area=business_area, household=cls.household1, - parent=cls.cash_plan1, + parent=cls.payment_plan1, currency="PLN", ) - PaymentRecordFactory.create_batch( + PaymentFactory.create_batch( 1, business_area=business_area, household=cls.household1, - parent=cls.cash_plan2, + parent=cls.payment_plan2, currency="PLN", ) - PaymentRecordFactory.create_batch( + PaymentFactory.create_batch( 2, business_area=business_area, household=cls.household2, - parent=cls.cash_plan1, + parent=cls.payment_plan1, currency="PLN", ) - PaymentRecordFactory.create_batch( + PaymentFactory.create_batch( 2, business_area=business_area, household=cls.household2, - parent=cls.cash_plan3, + parent=cls.payment_plan3, currency="PLN", ) cls.create_user_role_with_permissions( @@ -76,12 +76,12 @@ def test_fetch_payment_records_filter_by_household(self) -> None: ) def test_fetch_payment_records_filter_by_cash_plan(self) -> None: - for cash_plan in [self.cash_plan1, self.cash_plan2, self.cash_plan3]: + for payment_plan in [self.payment_plan1, self.payment_plan2, self.payment_plan3]: self.snapshot_graphql_request( request_string=self.ALL_PAYMENT_RECORDS_QUERY, context={"user": self.user}, variables={ - "cashPlan": encode_id_base64(cash_plan.pk, "CashPlan"), + "cashPlan": encode_id_base64(payment_plan.pk, "PaymentPlan"), "businessArea": "afghanistan", }, ) diff --git a/tests/unit/apps/payment/test_build_snapshot.py b/tests/unit/apps/payment/test_build_snapshot.py index 70fb24e049..f03ab177fd 100644 --- a/tests/unit/apps/payment/test_build_snapshot.py +++ b/tests/unit/apps/payment/test_build_snapshot.py @@ -34,10 +34,7 @@ def setUpTestData(cls) -> None: program = RealProgramFactory() program_cycle = program.cycles.first() cls.pp = PaymentPlanFactory( - program=program, program_cycle=program_cycle, - dispersion_start_date=datetime(2020, 8, 10), - dispersion_end_date=datetime(2020, 12, 10), is_follow_up=False, ) cls.pp.unicef_id = "PP-01" @@ -114,7 +111,6 @@ def test_batching(self) -> None: program = RealProgramFactory() program_cycle = program.cycles.first() pp = PaymentPlanFactory( - program=program, program_cycle=program_cycle, dispersion_start_date=datetime(2020, 8, 10), dispersion_end_date=datetime(2020, 12, 10), diff --git a/tests/unit/apps/payment/test_build_summary.py b/tests/unit/apps/payment/test_build_summary.py index 572cc14557..efb6ae2d6a 100644 --- a/tests/unit/apps/payment/test_build_summary.py +++ b/tests/unit/apps/payment/test_build_summary.py @@ -4,7 +4,8 @@ from hct_mis_api.apps.core.fixtures import create_afghanistan from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, + PaymentPlanFactory, + PaymentVerificationSummaryFactory, create_payment_verification_plan_with_status, ) from hct_mis_api.apps.payment.models import ( @@ -33,51 +34,52 @@ def setUpTestData(cls) -> None: targeting_criteria=TargetingCriteriaFactory(), business_area=cls.business_area, ) - cls.cash_plan = CashPlanFactory( + cls.payment_plan = PaymentPlanFactory( name="TEST", - program=cls.program, + program_cycle=cls.program.cycles.first(), business_area=cls.business_area, ) + PaymentVerificationSummaryFactory(payment_plan=cls.payment_plan) def test_status_pending_when_zero_verifications(self) -> None: - build_summary(self.cash_plan) + build_summary(self.payment_plan) - summary = self.cash_plan.get_payment_verification_summary + summary = self.payment_plan.payment_verification_summary self.assertEqual(summary.status, PaymentVerificationSummary.STATUS_PENDING) def test_status_active_when_at_least_one_active_verification(self) -> None: self._create_verification_with_status(PaymentVerificationPlan.STATUS_ACTIVE) - build_summary(self.cash_plan) + build_summary(self.payment_plan) - summary = self.cash_plan.get_payment_verification_summary + summary = self.payment_plan.payment_verification_summary self.assertEqual(summary.status, PaymentVerificationSummary.STATUS_ACTIVE) def test_status_finished_when_all_verifications_finished(self) -> None: self._create_verification_with_status(PaymentVerificationPlan.STATUS_FINISHED) - build_summary(self.cash_plan) + build_summary(self.payment_plan) - summary = self.cash_plan.get_payment_verification_summary + summary = self.payment_plan.payment_verification_summary self.assertEqual(summary.status, PaymentVerificationSummary.STATUS_FINISHED) def test_status_pending_when_add_and_removed_verification(self) -> None: payment_verification_plan = self._create_verification_with_status(PaymentVerificationPlan.STATUS_PENDING) payment_verification_plan.delete() - build_summary(self.cash_plan) + build_summary(self.payment_plan) - summary = self.cash_plan.get_payment_verification_summary + summary = self.payment_plan.payment_verification_summary self.assertEqual(summary.status, PaymentVerificationSummary.STATUS_PENDING) def test_query_number(self) -> None: - with self.assertNumQueries(3): - build_summary(self.cash_plan) + with self.assertNumQueries(2): + build_summary(self.payment_plan) def _create_verification_with_status(self, status: str) -> PaymentVerificationPlan: return create_payment_verification_plan_with_status( - self.cash_plan, + self.payment_plan, self.user, self.business_area, self.program, diff --git a/tests/unit/apps/payment/test_chart_total_transferred_cash_by_country.py b/tests/unit/apps/payment/test_chart_total_transferred_cash_by_country.py index eeac008b95..5092b03177 100644 --- a/tests/unit/apps/payment/test_chart_total_transferred_cash_by_country.py +++ b/tests/unit/apps/payment/test_chart_total_transferred_cash_by_country.py @@ -12,8 +12,8 @@ from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.household.fixtures import create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, generate_delivery_mechanisms, ) from hct_mis_api.apps.payment.models import DeliveryMechanism @@ -42,12 +42,12 @@ def setUpTestData(cls) -> None: cls.partner = PartnerFactory(name="Test1") cls.user = UserFactory(partner=cls.partner) (household, _) = create_household(household_args={"size": 1}) - cash_plan = CashPlanFactory(funds_commitment="123456", exchange_rate=None) + cash_plan = PaymentPlanFactory(funds_commitment="123456", exchange_rate=None) chosen_business_areas = ("afghanistan", "botswana", "angola") delivery_date = timezone.datetime(2021, 10, 10, tzinfo=utc) for business_area_slug in chosen_business_areas: business_area = BusinessArea.objects.get(slug=business_area_slug) - PaymentRecordFactory.create_batch( + PaymentFactory.create_batch( 3, delivery_date=delivery_date, business_area=business_area, @@ -57,7 +57,7 @@ def setUpTestData(cls) -> None: household=household, currency="PLN", ) - PaymentRecordFactory.create_batch( + PaymentFactory.create_batch( 3, delivery_date=delivery_date, business_area=business_area, diff --git a/tests/unit/apps/payment/test_create_payment_verification_mutation.py b/tests/unit/apps/payment/test_create_payment_verification_mutation.py index 53ff998044..e27eed3d3e 100644 --- a/tests/unit/apps/payment/test_create_payment_verification_mutation.py +++ b/tests/unit/apps/payment/test_create_payment_verification_mutation.py @@ -8,8 +8,8 @@ from hct_mis_api.apps.core.fixtures import create_afghanistan from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory -from hct_mis_api.apps.payment.models import PaymentRecord +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory +from hct_mis_api.apps.payment.models import Payment, PaymentRecord from hct_mis_api.apps.program.fixtures import ProgramFactory from hct_mis_api.apps.program.models import Program @@ -35,7 +35,7 @@ def setUpTestData(cls) -> None: cls.active_program = ProgramFactory(status=Program.ACTIVE) cls.finished_program = ProgramFactory(status=Program.FINISHED) - cls.cash_plan = CashPlanFactory.create( + cls.payment_plan = PaymentPlanFactory.create( id="0e2927af-c84d-4852-bb0b-773efe059e05", business_area=cls.business_area, ) @@ -49,8 +49,8 @@ def setUpTestData(cls) -> None: def test_create_cash_plan_payment_verification(self, _: Any, permissions: List[Permissions]) -> None: self.create_user_role_with_permissions(self.user, permissions, self.business_area) (household, _) = create_household(household_args={"size": 1}) - PaymentRecordFactory.create( - parent=self.cash_plan, + PaymentFactory.create( + parent=self.payment_plan, business_area=self.cash_plan.business_area, delivered_quantity=1000, delivered_quantity_usd=None, @@ -61,8 +61,8 @@ def test_create_cash_plan_payment_verification(self, _: Any, permissions: List[P # after .create(...), newly created PaymentRecord does not have `head_of_household` set # logic needs it to check record.head_of_household.phone_no # hence the below - assert PaymentRecord.objects.count() == 1 - PaymentRecord.objects.all().update(head_of_household=household.head_of_household) + assert Payment.objects.count() == 1 + Payment.objects.all().update(collector=household.head_of_household) self.snapshot_graphql_request( request_string=self.MUTATION, @@ -74,7 +74,7 @@ def test_create_cash_plan_payment_verification(self, _: Any, permissions: List[P }, variables={ "input": { - "cashOrPaymentPlanId": self.id_to_base64(self.cash_plan.id, "CashPlanNode"), + "cashOrPaymentPlanId": self.id_to_base64(self.payment_plan.id, "PaymentPlanNode"), "sampling": "FULL_LIST", "fullListArguments": {"excludedAdminAreas": []}, "verificationChannel": "MANUAL", @@ -89,7 +89,7 @@ def test_create_cash_plan_payment_verification_when_invalid_arguments(self) -> N self.create_user_role_with_permissions(self.user, [Permissions.PAYMENT_VERIFICATION_CREATE], self.business_area) defaults = { - "cashOrPaymentPlanId": self.id_to_base64(self.cash_plan.id, "CashPlanNode"), + "cashOrPaymentPlanId": self.id_to_base64(self.payment_plan.id, "PaymentPlanNode"), "businessAreaSlug": "afghanistan", } @@ -172,7 +172,7 @@ def test_can_t_create_cash_plan_payment_verification_when_there_are_not_availabl }, variables={ "input": { - "cashOrPaymentPlanId": self.id_to_base64(self.cash_plan.id, "CashPlanNode"), + "cashOrPaymentPlanId": self.id_to_base64(self.payment_plan.id, "PaymentPlanNode"), "sampling": "FULL_LIST", "fullListArguments": {"excludedAdminAreas": []}, "verificationChannel": "MANUAL", @@ -196,7 +196,7 @@ def test_create_cash_plan_payment_verification_when_program_is_finished(self) -> }, variables={ "input": { - "cashOrPaymentPlanId": self.id_to_base64(self.cash_plan.id, "CashPlanNode"), + "cashOrPaymentPlanId": self.id_to_base64(self.payment_plan.id, "PaymentPlanNode"), "sampling": "FULL_LIST", "fullListArguments": {"excludedAdminAreas": []}, "verificationChannel": "MANUAL", diff --git a/tests/unit/apps/payment/test_dashboard_queries.py b/tests/unit/apps/payment/test_dashboard_queries.py index d6f7434514..0a2982e42c 100644 --- a/tests/unit/apps/payment/test_dashboard_queries.py +++ b/tests/unit/apps/payment/test_dashboard_queries.py @@ -17,11 +17,9 @@ from hct_mis_api.apps.geo.fixtures import AreaFactory, AreaTypeFactory from hct_mis_api.apps.household.fixtures import create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, FinancialServiceProviderFactory, PaymentFactory, PaymentPlanFactory, - PaymentRecordFactory, generate_delivery_mechanisms, ) from hct_mis_api.apps.payment.models import ( @@ -243,9 +241,9 @@ def setUpTestData(cls) -> None: "program": program1, }, ) - cash_plan1 = CashPlanFactory(program=program1, business_area=business_area) - PaymentRecordFactory( - parent=cash_plan1, + payment_plan1 = PaymentPlanFactory(program_cycle=program1.cycles.first(), business_area=business_area) + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), household=household1_admin1, delivery_type=cls.dm_cash, @@ -255,8 +253,8 @@ def setUpTestData(cls) -> None: business_area=business_area, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), household=household1_admin2, delivery_type=cls.dm_voucher, @@ -266,8 +264,8 @@ def setUpTestData(cls) -> None: business_area=business_area, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), household=household3_admin2, delivery_type=cls.dm_voucher, @@ -277,8 +275,8 @@ def setUpTestData(cls) -> None: business_area=business_area, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 11, 10, tzinfo=utc), household=household1_admin3, delivery_type=cls.dm_cash, @@ -288,8 +286,8 @@ def setUpTestData(cls) -> None: business_area=business_area, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), household=household3_admin3, delivery_type=cls.dm_voucher, @@ -299,8 +297,8 @@ def setUpTestData(cls) -> None: business_area=business_area, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), household=household4_admin3, delivery_type=cls.dm_voucher, @@ -311,9 +309,9 @@ def setUpTestData(cls) -> None: currency="PLN", ) - payment_plan1 = PaymentPlanFactory(program=program1, business_area=business_area) + payment_plan2 = PaymentPlanFactory(program_cycle=program1.cycles.first(), business_area=business_area) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), delivery_type=cls.dm_cash, delivered_quantity=10 + num, @@ -325,7 +323,7 @@ def setUpTestData(cls) -> None: financial_service_provider=fsp, ) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), delivery_type=cls.dm_voucher, delivered_quantity=20 + num, @@ -337,7 +335,7 @@ def setUpTestData(cls) -> None: financial_service_provider=fsp, ) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=timezone.datetime(2021, 11, 10, tzinfo=utc), delivery_type=cls.dm_cash, delivered_quantity=30 + num, diff --git a/tests/unit/apps/payment/test_delete_verification_mutation.py b/tests/unit/apps/payment/test_delete_verification_mutation.py index bc6b1f1ee5..58483ddc67 100644 --- a/tests/unit/apps/payment/test_delete_verification_mutation.py +++ b/tests/unit/apps/payment/test_delete_verification_mutation.py @@ -9,7 +9,8 @@ from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, + PaymentPlanFactory, + PaymentVerificationSummaryFactory, create_payment_verification_plan_with_status, ) from hct_mis_api.apps.payment.models import PaymentVerificationPlan @@ -52,12 +53,13 @@ def setUpTestData(cls) -> None: targeting_criteria=(TargetingCriteriaFactory()), business_area=cls.business_area, ) - cls.cash_plan = CashPlanFactory( + cls.payment_plan = PaymentPlanFactory( name="TEST", - program=cls.program, + program_cycle=cls.program.cycles.first(), business_area=cls.business_area, ) - cls.verification = cls.cash_plan.payment_verification_plan.first() + PaymentVerificationSummaryFactory(payment_plan=cls.payment_plan) + cls.verification = cls.payment_plan.payment_verification_plan.first() @parameterized.expand( [ @@ -103,7 +105,7 @@ def test_delete_active_verification_plan(self, _: Any, permissions: List[Permiss def create_pending_payment_verification_plan(self) -> PaymentVerificationPlan: return create_payment_verification_plan_with_status( - self.cash_plan, + self.payment_plan, self.user, self.business_area, self.program, @@ -113,7 +115,7 @@ def create_pending_payment_verification_plan(self) -> PaymentVerificationPlan: def create_active_payment_verification_plan(self) -> PaymentVerificationPlan: return create_payment_verification_plan_with_status( - self.cash_plan, + self.payment_plan, self.user, self.business_area, self.program, diff --git a/tests/unit/apps/payment/test_discard_verification_mutation.py b/tests/unit/apps/payment/test_discard_verification_mutation.py index 5433f490e0..0ea360680b 100644 --- a/tests/unit/apps/payment/test_discard_verification_mutation.py +++ b/tests/unit/apps/payment/test_discard_verification_mutation.py @@ -10,10 +10,11 @@ from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.household.fixtures import EntitlementCardFactory, create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentVerification, PaymentVerificationPlan from hct_mis_api.apps.program.fixtures import ProgramFactory @@ -66,13 +67,14 @@ def setUpTestData(cls) -> None: targeting_criteria=targeting_criteria, business_area=cls.business_area, ) - cash_plan = CashPlanFactory( + payment_plan = PaymentPlanFactory( name="TEST", - program=program, + program_cycle=program.cycles.first(), business_area=cls.business_area, ) + PaymentVerificationSummaryFactory(payment_plan=payment_plan) payment_verification_plan = PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL + payment_plan_obj=payment_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL ) payment_verification_plan.status = PaymentVerificationPlan.STATUS_ACTIVE payment_verification_plan.save() @@ -90,20 +92,20 @@ def setUpTestData(cls) -> None: household.programs.add(program) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, target_population=target_population, currency="PLN", ) PaymentVerificationFactory( payment_verification_plan=payment_verification_plan, - payment_obj=payment_record, + payment=payment, status=PaymentVerification.STATUS_PENDING, ) EntitlementCardFactory(household=household) - cls.cash_plan = cash_plan - cls.verification = cash_plan.payment_verification_plan.first() + cls.payment_plan = payment_plan + cls.verification = payment_plan.payment_verification_plans.first() @parameterized.expand( [ diff --git a/tests/unit/apps/payment/test_exclude_households.py b/tests/unit/apps/payment/test_exclude_households.py index 53787f2caf..6b4fbbcc95 100644 --- a/tests/unit/apps/payment/test_exclude_households.py +++ b/tests/unit/apps/payment/test_exclude_households.py @@ -199,7 +199,6 @@ def test_exclude_all_households(self) -> None: def test_exclude_payment_error_when_payment_has_hard_conflicts(self) -> None: finished_payment_plan = PaymentPlanFactory( status=PaymentPlan.Status.FINISHED, - program=self.program, is_follow_up=False, program_cycle=self.program_cycle, ) @@ -259,8 +258,8 @@ def test_exclude_individuals_people_program(self, get_exchange_rate_mock: Any) - self.program.data_collecting_type = people_dct self.program.save(update_fields=["data_collecting_type"]) self.payment_plan.background_action_status = PaymentPlan.BackgroundActionStatus.EXCLUDE_BENEFICIARIES - self.payment_plan.program = self.program - self.payment_plan.save(update_fields=["background_action_status", "program"]) + self.payment_plan.program_cycle = self.program.cycles.first() + self.payment_plan.save(update_fields=["background_action_status", "program_cycle"]) ind_unicef_id_1 = Individual.objects.get(id=self.individual_1.id).unicef_id ind_unicef_id_2 = Individual.objects.get(id=self.individual_2.id).unicef_id diff --git a/tests/unit/apps/payment/test_export_xlsx_verification_mutation.py b/tests/unit/apps/payment/test_export_xlsx_verification_mutation.py index 13723bcad2..644faedc82 100644 --- a/tests/unit/apps/payment/test_export_xlsx_verification_mutation.py +++ b/tests/unit/apps/payment/test_export_xlsx_verification_mutation.py @@ -9,8 +9,9 @@ from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, + PaymentPlanFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentVerificationPlan from hct_mis_api.apps.program.fixtures import ProgramFactory @@ -48,10 +49,10 @@ def setUpTestData(cls) -> None: program = ProgramFactory(business_area=cls.business_area) program.admin_areas.set(Area.objects.order_by("?")[:3]) - cash_plan = CashPlanFactory(program=program, business_area=cls.business_area) - cash_plan.save() + payment_plan = PaymentPlanFactory(program_cycle=program.cycles.first(), business_area=cls.business_area) + PaymentVerificationSummaryFactory(payment_plan=payment_plan) cls.payment_verification_plan = PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan, + payment_plan=payment_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_XLSX, status=PaymentVerificationPlan.STATUS_ACTIVE, ) diff --git a/tests/unit/apps/payment/test_finish_verification_plan.py b/tests/unit/apps/payment/test_finish_verification_plan.py index 7c11643f96..639ce1308f 100644 --- a/tests/unit/apps/payment/test_finish_verification_plan.py +++ b/tests/unit/apps/payment/test_finish_verification_plan.py @@ -13,10 +13,11 @@ from hct_mis_api.apps.household.fixtures import EntitlementCardFactory, create_household from hct_mis_api.apps.household.models import Household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentVerification, PaymentVerificationPlan from hct_mis_api.apps.payment.services.verification_plan_status_change_services import ( @@ -54,15 +55,15 @@ def setUpTestData(cls) -> None: business_area=business_area, program=cls.program, ) - cash_plan = CashPlanFactory( - program=cls.program, + payment_plan = PaymentPlanFactory( + program_cycle=cls.program.cycles.first(), business_area=business_area, ) - cash_plan.save() - cash_plan_payment_verification = PaymentVerificationPlanFactory( + PaymentVerificationSummaryFactory(payment_plan=payment_plan) + payment_plan_payment_verification = PaymentVerificationPlanFactory( status=PaymentVerificationPlan.STATUS_PENDING, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_RAPIDPRO, - payment_plan_obj=cash_plan, + payment_plan=payment_plan, ) for i in range(payment_record_amount): registration_data_import = RegistrationDataImportFactory( @@ -83,8 +84,8 @@ def setUpTestData(cls) -> None: household.program = cls.program household.refresh_from_db() - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, head_of_household=household.head_of_household, target_population=target_population, @@ -93,12 +94,12 @@ def setUpTestData(cls) -> None: ) PaymentVerificationFactory( - payment_verification_plan=cash_plan_payment_verification, - payment_obj=payment_record, + payment_verification_plan=payment_plan_payment_verification, + payment=payment, status=PaymentVerification.STATUS_RECEIVED_WITH_ISSUES, ) EntitlementCardFactory(household=household) - cls.verification = cash_plan.get_payment_verification_plans.first() + cls.verification = payment_plan.payment_verification_plans.first() @mock.patch("hct_mis_api.apps.utils.mailjet.requests.post") @override_settings(EMAIL_SUBJECT_PREFIX="test") diff --git a/tests/unit/apps/payment/test_fixtures.py b/tests/unit/apps/payment/test_fixtures.py index 409d44a2b6..61f7dd01da 100644 --- a/tests/unit/apps/payment/test_fixtures.py +++ b/tests/unit/apps/payment/test_fixtures.py @@ -7,7 +7,6 @@ from hct_mis_api.apps.payment.fixtures import ( generate_delivery_mechanisms, generate_payment_plan, - generate_real_cash_plans, generate_reconciled_payment_plan, update_fsps, ) @@ -29,6 +28,5 @@ def test_fixtures_functions(self) -> None: HouseholdFactory() generate_delivery_mechanisms() generate_payment_plan() - generate_real_cash_plans() generate_reconciled_payment_plan() update_fsps() diff --git a/tests/unit/apps/payment/test_fsp_in_payment_plan.py b/tests/unit/apps/payment/test_fsp_in_payment_plan.py index 1bc23261b2..b7255b85c7 100644 --- a/tests/unit/apps/payment/test_fsp_in_payment_plan.py +++ b/tests/unit/apps/payment/test_fsp_in_payment_plan.py @@ -119,7 +119,7 @@ def payment_plan_setup(cls: Any) -> None: total_households_count=4, target_population=target_population, status=PaymentPlan.Status.LOCKED, - program=cls.program, + program_cycle=cls.program.cycles.first(), ) cls.encoded_payment_plan_id = encode_id_base64(cls.payment_plan.id, "PaymentPlan") @@ -251,7 +251,7 @@ def setUpTestData(cls) -> None: def test_choosing_delivery_mechanism_order(self) -> None: payment_plan = PaymentPlanFactory( - total_households_count=1, status=PaymentPlan.Status.LOCKED, program=self.program + total_households_count=1, status=PaymentPlan.Status.LOCKED, program_cycle=self.program.cycles.first() ) encoded_payment_plan_id = encode_id_base64(payment_plan.id, "PaymentPlan") choose_dms_mutation_variables_mutation_variables_without_delivery_mechanisms = dict( @@ -320,7 +320,7 @@ def test_error_when_choosing_delivery_mechanism_with_usdc_currency(self) -> None payment_plan = PaymentPlanFactory( total_households_count=1, status=PaymentPlan.Status.LOCKED, - program=self.program, + program_cycle=self.program.cycles.first(), currency=USDC, ) assert payment_plan.currency == USDC @@ -365,7 +365,7 @@ def test_being_able_to_get_possible_delivery_mechanisms(self) -> None: def test_providing_non_unique_delivery_mechanisms(self) -> None: payment_plan = PaymentPlanFactory( - total_households_count=1, status=PaymentPlan.Status.LOCKED, program=self.program + total_households_count=1, status=PaymentPlan.Status.LOCKED, program_cycle=self.program.cycles.first() ) encoded_payment_plan_id = encode_id_base64(payment_plan.id, "PaymentPlan") choose_dms_mutation_variables_mutation_variables = dict( @@ -1116,7 +1116,9 @@ def test_fsp_cannot_accept_any_volume(self) -> None: # FSP with limit is used in other conflicting PP self.bank_of_america_fsp.distribution_limit = 1000 self.bank_of_america_fsp.save() - new_payment_plan = PaymentPlanFactory(status=PaymentPlan.Status.LOCKED_FSP, program=self.program) + new_payment_plan = PaymentPlanFactory( + status=PaymentPlan.Status.LOCKED_FSP, program_cycle=self.program.cycles.first() + ) DeliveryMechanismPerPaymentPlanFactory( payment_plan=new_payment_plan, delivery_mechanism=self.dm_voucher, diff --git a/tests/unit/apps/payment/test_fsp_xlsx_template_get_column_value.py b/tests/unit/apps/payment/test_fsp_xlsx_template_get_column_value.py index 2ad2a44c70..c5ad868861 100644 --- a/tests/unit/apps/payment/test_fsp_xlsx_template_get_column_value.py +++ b/tests/unit/apps/payment/test_fsp_xlsx_template_get_column_value.py @@ -34,7 +34,9 @@ def test_get_column_value_registration_token_empty(self) -> None: household, individuals = create_household(household_args={"size": 1, "business_area": self.business_area}) individual = individuals[0] payment_plan = PaymentPlanFactory( - program=self.program, status=PaymentPlan.Status.ACCEPTED, business_area=self.business_area + program_cycle=self.program.cycles.first(), + status=PaymentPlan.Status.ACCEPTED, + business_area=self.business_area, ) payment = PaymentFactory(parent=payment_plan, household=household, collector=individual, currency="PLN") create_payment_plan_snapshot_data(payment_plan) @@ -62,7 +64,9 @@ def test_get_column_value_from_payment(self, _: Any, field_name: str) -> None: individual = individuals[0] payment_plan = PaymentPlanFactory( - program=self.program, status=PaymentPlan.Status.ACCEPTED, business_area=self.business_area + program_cycle=self.program.cycles.first(), + status=PaymentPlan.Status.ACCEPTED, + business_area=self.business_area, ) payment = PaymentFactory(parent=payment_plan, household=household, collector=individual, currency="PLN") primary = IndividualRoleInHousehold.objects.filter(role=ROLE_PRIMARY).first().individual diff --git a/tests/unit/apps/payment/test_import_export_payment_plan_payment_list.py b/tests/unit/apps/payment/test_import_export_payment_plan_payment_list.py index 79beaa3754..f455d9899d 100644 --- a/tests/unit/apps/payment/test_import_export_payment_plan_payment_list.py +++ b/tests/unit/apps/payment/test_import_export_payment_plan_payment_list.py @@ -45,7 +45,6 @@ PaymentFactory, PaymentPlanFactory, RealProgramFactory, - ServiceProviderFactory, generate_delivery_mechanisms, ) from hct_mis_api.apps.payment.models import ( @@ -102,12 +101,12 @@ def setUpTestData(cls) -> None: ) if ServiceProvider.objects.count() < 3: - ServiceProviderFactory.create_batch(3) + FinancialServiceProviderFactory.create_batch(3) program = RealProgramFactory() cls.dm_cash = DeliveryMechanism.objects.get(code="cash") cls.dm_transfer = DeliveryMechanism.objects.get(code="transfer") cls.dm_atm_card = DeliveryMechanism.objects.get(code="atm_card") - cls.payment_plan = PaymentPlanFactory(program=program, business_area=cls.business_area) + cls.payment_plan = PaymentPlanFactory(program_cycle=program.cycles.first(), business_area=cls.business_area) cls.fsp_1 = FinancialServiceProviderFactory( name="Test FSP 1", communication_channel=FinancialServiceProvider.COMMUNICATION_CHANNEL_XLSX, @@ -501,7 +500,7 @@ def test_export_payment_plan_per_fsp_with_people_program(self) -> None: # create Program for People export program_sw = ProgramFactory(data_collecting_type__type=DataCollectingType.Type.SOCIAL) - self.payment_plan.program = program_sw + self.payment_plan.program_cycle = program_sw.cycles.first() self.payment_plan.save() export_service = XlsxPaymentPlanExportPerFspService(self.payment_plan) diff --git a/tests/unit/apps/payment/test_import_verifications.py b/tests/unit/apps/payment/test_import_verifications.py index 720d69a057..ee3a155335 100644 --- a/tests/unit/apps/payment/test_import_verifications.py +++ b/tests/unit/apps/payment/test_import_verifications.py @@ -23,10 +23,11 @@ create_household, ) from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentVerification from hct_mis_api.apps.payment.xlsx.xlsx_verification_export_service import ( @@ -47,7 +48,7 @@ class TestXlsxVerificationImport(APITestCase): def setUp(self) -> None: super().setUp() create_afghanistan() - payment_record_amount = 10 + payments_amount = 10 self.business_area = BusinessArea.objects.get(slug="afghanistan") self.user = UserFactory() @@ -59,10 +60,10 @@ def setUp(self) -> None: target_population = TargetPopulationFactory( created_by=self.user, targeting_criteria=targeting_criteria, business_area=self.business_area ) - cash_plan = CashPlanFactory(program=program, business_area=self.business_area) - cash_plan.save() - payment_verification_plan = PaymentVerificationPlanFactory(payment_plan_obj=cash_plan) - for _ in range(payment_record_amount): + payment_plan = PaymentPlanFactory(program_cycle=program.cycles.first(), business_area=self.business_area) + PaymentVerificationSummaryFactory(payment_plan=payment_plan) + payment_verification_plan = PaymentVerificationPlanFactory(payment_plan=payment_plan) + for _ in range(payments_amount): registration_data_import = RegistrationDataImportFactory( imported_by=self.user, business_area=BusinessArea.objects.first() ) @@ -76,8 +77,8 @@ def setUp(self) -> None: household.programs.add(program) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, head_of_household=household.head_of_household, target_population=target_population, @@ -85,13 +86,13 @@ def setUp(self) -> None: ) PaymentVerificationFactory( - payment_obj=payment_record, + payment=payment, payment_verification_plan=payment_verification_plan, status=PaymentVerification.STATUS_PENDING, ) EntitlementCardFactory(household=household) - self.cash_plan = cash_plan - self.verification = cash_plan.payment_verification_plan.first() + self.payment_plan = payment_plan + self.verification = payment_plan.payment_verification_plans.first() @parameterized.expand( [ @@ -123,7 +124,7 @@ def test_validation_valid_not_changed_file(self) -> None: self.assertEqual(import_service.errors, []) def test_validation_valid_status_changed_for_people(self) -> None: - dct = self.verification.payment_plan_obj.program.data_collecting_type + dct = self.verification.payment_plan.program_cycle.program.data_collecting_type dct.type = DataCollectingType.Type.SOCIAL dct.save() export_service = XlsxVerificationExportService(self.verification) @@ -368,13 +369,13 @@ def test_validation_of_unordered_columns(self, file_name: str, error_list: List, 3rd scenario - like above + one null header """ - cash_plan = CashPlanFactory() + payment_plan = PaymentPlanFactory() hoh1 = IndividualFactory(household=None) household_1 = HouseholdFactory(head_of_household=hoh1) - payment_1 = PaymentRecordFactory( + payment_1 = PaymentFactory( id="0329a41f-affd-4669-9e38-38ec2d6699b3", - parent=cash_plan, + parent=payment_plan, household=household_1, entitlement_quantity=120, delivered_quantity=150, @@ -383,24 +384,24 @@ def test_validation_of_unordered_columns(self, file_name: str, error_list: List, hoh2 = IndividualFactory(household=None) household_2 = HouseholdFactory(head_of_household=hoh2) - payment_2 = PaymentRecordFactory( + payment_2 = PaymentFactory( id="299811ef-b123-427d-b77d-9fd5d1bc8946", - parent=cash_plan, + parent=payment_plan, household=household_2, entitlement_quantity=120, delivered_quantity=150, currency="PLN", ) - - payment_verification_plan = PaymentVerificationPlanFactory(payment_plan_obj=cash_plan) + PaymentVerificationSummaryFactory(payment_plan=payment_plan) + payment_verification_plan = PaymentVerificationPlanFactory(payment_plan=payment_plan) PaymentVerificationFactory( - payment_obj=payment_1, + payment=payment_1, payment_verification_plan=payment_verification_plan, status=PaymentVerification.STATUS_PENDING, ) PaymentVerificationFactory( - payment_obj=payment_2, + payment=payment_2, payment_verification_plan=payment_verification_plan, status=PaymentVerification.STATUS_PENDING, ) diff --git a/tests/unit/apps/payment/test_invalid_xlsx_verification_mutation.py b/tests/unit/apps/payment/test_invalid_xlsx_verification_mutation.py index fe80113c58..1ae35dea74 100644 --- a/tests/unit/apps/payment/test_invalid_xlsx_verification_mutation.py +++ b/tests/unit/apps/payment/test_invalid_xlsx_verification_mutation.py @@ -15,8 +15,9 @@ from hct_mis_api.apps.core.models import BusinessArea, FileTemp from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, + PaymentPlanFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentVerificationPlan from hct_mis_api.apps.program.fixtures import ProgramFactory @@ -53,10 +54,12 @@ def setUpTestData(cls) -> None: program = ProgramFactory(business_area=cls.business_area) program.admin_areas.set(Area.objects.order_by("?")[:3]) - cash_plan = CashPlanFactory(program=program, business_area=cls.business_area) - cash_plan.save() + payment_plan = PaymentPlanFactory(program=program, business_area=cls.business_area) + PaymentVerificationSummaryFactory( + payment_plan=payment_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_XLSX + ) cls.payment_verification_plan = PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan, + payment_plan=payment_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_XLSX, status=PaymentVerificationPlan.STATUS_ACTIVE, ) diff --git a/tests/unit/apps/payment/test_models.py b/tests/unit/apps/payment/test_models.py index d96f9e5466..0c1697d50a 100644 --- a/tests/unit/apps/payment/test_models.py +++ b/tests/unit/apps/payment/test_models.py @@ -228,13 +228,12 @@ def test_can_be_locked(self) -> None: program = RealProgramFactory() program_cycle = program.cycles.first() - pp1 = PaymentPlanFactory(program=program, program_cycle=program_cycle) + pp1 = PaymentPlanFactory(program_cycle=program_cycle) self.assertEqual(pp1.can_be_locked, False) # create hard conflicted payment pp1_conflicted = PaymentPlanFactory( status=PaymentPlan.Status.LOCKED, - program=program, program_cycle=program_cycle, ) p1 = PaymentFactory(parent=pp1, conflicted=False, currency="PLN") @@ -311,23 +310,20 @@ def test_manager_annotations_pp_conflicts(self) -> None: program = RealProgramFactory() program_cycle = program.cycles.first() - pp1 = PaymentPlanFactory(program=program, program_cycle=program_cycle) + pp1 = PaymentPlanFactory(program_cycle=program_cycle) # create hard conflicted payment pp2 = PaymentPlanFactory( status=PaymentPlan.Status.LOCKED, - program=program, program_cycle=program_cycle, ) # create soft conflicted payments pp3 = PaymentPlanFactory( status=PaymentPlan.Status.OPEN, - program=program, program_cycle=program_cycle, ) pp4 = PaymentPlanFactory( status=PaymentPlan.Status.OPEN, - program=program, program_cycle=program_cycle, ) p1 = PaymentFactory(parent=pp1, conflicted=False, currency="PLN") diff --git a/tests/unit/apps/payment/test_payment_gateway_service.py b/tests/unit/apps/payment/test_payment_gateway_service.py index 6274e3d798..539dd957c9 100644 --- a/tests/unit/apps/payment/test_payment_gateway_service.py +++ b/tests/unit/apps/payment/test_payment_gateway_service.py @@ -3,10 +3,7 @@ from typing import Any from unittest import mock -from django.utils import timezone - import pytest -from pytz import utc from hct_mis_api.apps.account.fixtures import UserFactory from hct_mis_api.apps.core.base_test_case import APITestCase @@ -73,8 +70,6 @@ def setUpTestData(cls) -> None: cls.user = UserFactory.create() cls.pp = PaymentPlanFactory( - program__cycle__start_date=timezone.datetime(2021, 6, 10, tzinfo=utc).date(), - program__cycle__end_date=timezone.datetime(2021, 7, 10, tzinfo=utc).date(), status=PaymentPlan.Status.ACCEPTED, ) cls.pg_fsp = FinancialServiceProviderFactory( diff --git a/tests/unit/apps/payment/test_payment_notification.py b/tests/unit/apps/payment/test_payment_notification.py index 3b78154964..5bebd751f7 100644 --- a/tests/unit/apps/payment/test_payment_notification.py +++ b/tests/unit/apps/payment/test_payment_notification.py @@ -33,7 +33,9 @@ def setUpTestData(cls) -> None: cls.program = ProgramFactory.create(business_area=cls.business_area) cls.program2 = ProgramFactory.create(business_area=cls.business_area) cls.payment_plan = PaymentPlanFactory.create( - business_area=cls.business_area, created_by=cls.user_payment_plan_creator, program=cls.program + business_area=cls.business_area, + created_by=cls.user_payment_plan_creator, + program_cycle=cls.program.cycles.first(), ) cls.approval_process = ApprovalProcessFactory.create( diff --git a/tests/unit/apps/payment/test_payment_plan_pdf_export_service.py b/tests/unit/apps/payment/test_payment_plan_pdf_export_service.py index b8881c9c79..881d230370 100644 --- a/tests/unit/apps/payment/test_payment_plan_pdf_export_service.py +++ b/tests/unit/apps/payment/test_payment_plan_pdf_export_service.py @@ -25,8 +25,9 @@ def setUp(self) -> None: generate_delivery_mechanisms() create_afghanistan() self.dm_cash = DeliveryMechanism.objects.get(code="cash") + program = ProgramFactory(data_collecting_type__type=DataCollectingType.Type.STANDARD) self.payment_plan = PaymentPlanFactory( - program=ProgramFactory(data_collecting_type__type=DataCollectingType.Type.STANDARD) + program_cycle=program.cycles.first(), ) self.payment_plan.unicef_id = "PP-0060-24-00000007" self.payment_plan.save() diff --git a/tests/unit/apps/payment/test_payment_plan_reconciliation.py b/tests/unit/apps/payment/test_payment_plan_reconciliation.py index 0857112950..f4d2eb6e6d 100644 --- a/tests/unit/apps/payment/test_payment_plan_reconciliation.py +++ b/tests/unit/apps/payment/test_payment_plan_reconciliation.py @@ -893,9 +893,11 @@ def test_receiving_payment_reconciliations_status( def test_xlsx_payment_plan_import_per_fsp_service_import_row(self) -> None: pp = PaymentPlanFactory(status=PaymentPlan.Status.FINISHED) pp.refresh_from_db() - PaymentVerificationSummaryFactory(payment_plan_obj=pp) + pvs = PaymentVerificationSummaryFactory() + pvs.payment_plan = pp + pvs.save() pvp = PaymentVerificationPlanFactory( - payment_plan_obj=pp, + payment_plan=pp, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL, status=PaymentVerificationPlan.STATUS_ACTIVE, ) @@ -941,19 +943,19 @@ def test_xlsx_payment_plan_import_per_fsp_service_import_row(self) -> None: ) verification_1 = PaymentVerificationFactory( payment_verification_plan=pvp, - payment_obj=payment_1, + payment=payment_1, status=PaymentVerification.STATUS_RECEIVED_WITH_ISSUES, received_amount=999, ) verification_2 = PaymentVerificationFactory( payment_verification_plan=pvp, - payment_obj=payment_2, + payment=payment_2, status=PaymentVerification.STATUS_RECEIVED, received_amount=500, ) verification_3 = PaymentVerificationFactory( payment_verification_plan=pvp, - payment_obj=payment_3, + payment=payment_3, status=PaymentVerification.STATUS_PENDING, received_amount=None, ) diff --git a/tests/unit/apps/payment/test_payment_plan_services.py b/tests/unit/apps/payment/test_payment_plan_services.py index 88c8fe2e10..657d045333 100644 --- a/tests/unit/apps/payment/test_payment_plan_services.py +++ b/tests/unit/apps/payment/test_payment_plan_services.py @@ -62,7 +62,8 @@ def setUpTestData(cls) -> None: cls.dm_transfer_to_account = DeliveryMechanism.objects.get(code="transfer_to_account") def test_delete_open(self) -> None: - pp: PaymentPlan = PaymentPlanFactory(status=PaymentPlan.Status.OPEN, program__status=Program.ACTIVE) + program = ProgramFactory(status=Program.ACTIVE) + pp: PaymentPlan = PaymentPlanFactory(status=PaymentPlan.Status.OPEN, program_cycle=program.cycles.first()) self.assertEqual(pp.target_population.status, TargetPopulation.STATUS_OPEN) pp = PaymentPlanService(payment_plan=pp).delete() @@ -77,7 +78,8 @@ def test_delete_locked(self) -> None: PaymentPlanService(payment_plan=pp).delete() def test_delete_when_its_one_pp_in_cycle(self) -> None: - pp = PaymentPlanFactory(status=PaymentPlan.Status.OPEN, program__status=Program.ACTIVE) + program = ProgramFactory(status=Program.ACTIVE) + pp: PaymentPlan = PaymentPlanFactory(status=PaymentPlan.Status.OPEN, program_cycle=program.cycles.first()) program_cycle = ProgramCycleFactory(status=ProgramCycle.ACTIVE, program=pp.program) pp.program_cycle = program_cycle pp.save() @@ -91,14 +93,10 @@ def test_delete_when_its_one_pp_in_cycle(self) -> None: self.assertEqual(program_cycle.status, ProgramCycle.DRAFT) def test_delete_when_its_two_pp_in_cycle(self) -> None: - pp_1 = PaymentPlanFactory(status=PaymentPlan.Status.OPEN, program__status=Program.ACTIVE) - pp_2 = PaymentPlanFactory(status=PaymentPlan.Status.OPEN, program=pp_1.program) - program_cycle = ProgramCycleFactory(status=ProgramCycle.ACTIVE, program=pp_1.program) - pp_1.program_cycle = program_cycle - pp_1.save() - pp_1.refresh_from_db() - pp_2.program_cycle = program_cycle - pp_2.save() + program = ProgramFactory(status=Program.ACTIVE) + program_cycle = ProgramCycleFactory(status=ProgramCycle.ACTIVE, program=program) + pp_1: PaymentPlan = PaymentPlanFactory(status=PaymentPlan.Status.OPEN, program_cycle=program_cycle) + PaymentPlanFactory(status=PaymentPlan.Status.OPEN, program_cycle=program_cycle) self.assertEqual(pp_1.program_cycle.status, ProgramCycle.ACTIVE) @@ -195,7 +193,7 @@ def test_create(self, get_exchange_rate_mock: Any) -> None: self.assertEqual(pp.total_households_count, 0) self.assertEqual(pp.total_individuals_count, 0) self.assertEqual(pp.payment_items.count(), 0) - with self.assertNumQueries(68): + with self.assertNumQueries(69): prepare_payment_plan_task.delay(pp.id) pp.refresh_from_db() self.assertEqual(pp.status, PaymentPlan.Status.OPEN) @@ -293,8 +291,6 @@ def test_update(self, get_exchange_rate_mock: Any) -> None: def test_create_follow_up_pp(self, get_exchange_rate_mock: Any) -> None: pp = PaymentPlanFactory( total_households_count=1, - program__cycle__start_date=timezone.datetime(2021, 6, 10, tzinfo=utc).date(), - program__cycle__end_date=timezone.datetime(2021, 7, 10, tzinfo=utc).date(), ) new_targeting = TargetPopulationFactory( status=TargetPopulation.STATUS_READY_FOR_PAYMENT_MODULE, @@ -398,7 +394,7 @@ def test_create_follow_up_pp(self, get_exchange_rate_mock: Any) -> None: self.assertEqual(pp.follow_ups.count(), 2) - with self.assertNumQueries(48): + with self.assertNumQueries(49): prepare_follow_up_payment_plan_task(follow_up_pp_2.id) self.assertEqual(follow_up_pp_2.payment_items.count(), 1) @@ -414,10 +410,7 @@ def test_create_follow_up_pp(self, get_exchange_rate_mock: Any) -> None: def test_split(self, min_no_of_payments_in_chunk_mock: Any, get_exchange_rate_mock: Any) -> None: min_no_of_payments_in_chunk_mock.__get__ = mock.Mock(return_value=2) - pp = PaymentPlanFactory( - program__cycle__start_date=timezone.datetime(2021, 6, 10, tzinfo=utc).date(), - program__cycle__end_date=timezone.datetime(2021, 7, 10, tzinfo=utc).date(), - ) + pp = PaymentPlanFactory() with self.assertRaisesMessage(GraphQLError, "No payments to split"): PaymentPlanService(pp).split(PaymentPlanSplit.SplitType.BY_COLLECTOR) @@ -523,8 +516,6 @@ def test_split(self, min_no_of_payments_in_chunk_mock: Any, get_exchange_rate_mo @mock.patch("hct_mis_api.apps.payment.models.PaymentPlan.get_exchange_rate", return_value=2.0) def test_send_to_payment_gateway(self, get_exchange_rate_mock: Any) -> None: pp = PaymentPlanFactory( - program__cycle__start_date=timezone.datetime(2021, 6, 10, tzinfo=utc).date(), - program__cycle__end_date=timezone.datetime(2021, 7, 10, tzinfo=utc).date(), status=PaymentPlan.Status.ACCEPTED, ) pp.background_action_status_send_to_payment_gateway() diff --git a/tests/unit/apps/payment/test_payment_plan_views.py b/tests/unit/apps/payment/test_payment_plan_views.py index 65764804fa..0f1da2c540 100644 --- a/tests/unit/apps/payment/test_payment_plan_views.py +++ b/tests/unit/apps/payment/test_payment_plan_views.py @@ -38,17 +38,17 @@ def set_up(self, api_client: Callable, afghanistan: BusinessAreaFactory, id_to_b self.program1 = ProgramFactory(business_area=self.afghanistan) self.program2 = ProgramFactory(business_area=self.afghanistan) self.payment_plan1 = PaymentPlanFactory( - program=self.program1, + program_cycle=self.program1.cycles.first(), business_area=self.afghanistan, status=PaymentPlan.Status.IN_APPROVAL, ) self.payment_plan2 = PaymentPlanFactory( - program=self.program2, + program_cycle=self.program2.cycles.first(), business_area=self.afghanistan, status=PaymentPlan.Status.IN_APPROVAL, ) self.payment_plan3 = PaymentPlanFactory( - program=self.program2, + program_cycle=self.program2.cycles.first(), business_area=self.afghanistan, status=PaymentPlan.Status.OPEN, ) @@ -133,7 +133,7 @@ def _test_list() -> Any: etag = response.headers["etag"] assert json.loads(cache.get(etag)[0].decode("utf8")) == response.json() - assert len(ctx.captured_queries) == 26 + assert len(ctx.captured_queries) == 28 # Test that reoccurring request use cached data with CaptureQueriesContext(connection) as ctx: diff --git a/tests/unit/apps/payment/test_payment_token_and_order_numbers.py b/tests/unit/apps/payment/test_payment_token_and_order_numbers.py index 0176c54cfe..040ff8f76e 100644 --- a/tests/unit/apps/payment/test_payment_token_and_order_numbers.py +++ b/tests/unit/apps/payment/test_payment_token_and_order_numbers.py @@ -30,7 +30,7 @@ def setUpTestData(cls) -> None: program = ProgramFactory(business_area=business_area) cls.payment_plan = PaymentPlanFactory( - program=program, status=PaymentPlan.Status.ACCEPTED, business_area=business_area + program_cycle=program.cycles.first(), status=PaymentPlan.Status.ACCEPTED, business_area=business_area ) program.households.set(Household.objects.all().values_list("id", flat=True)) for household in program.households.all(): diff --git a/tests/unit/apps/payment/test_payment_verification_mutations.py b/tests/unit/apps/payment/test_payment_verification_mutations.py index a7b61fceef..df2ea6353f 100644 --- a/tests/unit/apps/payment/test_payment_verification_mutations.py +++ b/tests/unit/apps/payment/test_payment_verification_mutations.py @@ -18,10 +18,8 @@ from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.household.fixtures import EntitlementCardFactory, create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, PaymentFactory, PaymentPlanFactory, - PaymentRecordFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, PaymentVerificationSummaryFactory, @@ -72,10 +70,9 @@ def setUpTestData(cls) -> None: target_population = TargetPopulationFactory( created_by=cls.user, targeting_criteria=targeting_criteria, business_area=cls.business_area ) - cash_plan = CashPlanFactory(program=program, business_area=cls.business_area) - cash_plan.save() + payment_plan = PaymentPlanFactory(program_cycle=program.cycles.first(), business_area=cls.business_area) payment_verification_plan = PaymentVerificationPlanFactory( - payment_plan_obj=cash_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL + payment_plan=payment_plan, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_MANUAL ) registration_data_import = RegistrationDataImportFactory( imported_by=cls.user, business_area=BusinessArea.objects.first() @@ -90,8 +87,8 @@ def setUpTestData(cls) -> None: household.programs.add(program) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, head_of_household=household.head_of_household, target_population=target_population, @@ -101,13 +98,13 @@ def setUpTestData(cls) -> None: ) PaymentVerificationFactory( - payment_obj=payment_record, + payment=payment, payment_verification_plan=payment_verification_plan, status=PaymentVerification.STATUS_PENDING, ) EntitlementCardFactory(household=household) - cls.cash_plan = cash_plan - cls.verification = cash_plan.payment_verification_plan.first() + cls.payment_plan = payment_plan + cls.verification = payment_plan.payment_verification_plans.first() VerificationPlanStatusChangeServices(payment_verification_plan).activate() info = ResolveInfo(None, None, None, None, None, None, None, None, None, None) request = RequestFactory().get("/api/graphql") @@ -230,10 +227,10 @@ def test_permissions(self) -> None: def test_edit_payment_verification_plan_mutation(self) -> None: payment_plan = PaymentPlanFactory(status=PaymentPlan.Status.FINISHED, business_area=self.business_area) - PaymentVerificationSummaryFactory(payment_plan_obj=payment_plan) + PaymentVerificationSummaryFactory(payment_plan=payment_plan) PaymentFactory(parent=payment_plan, currency="PLN", status=GenericPayment.STATUS_SUCCESS) payment_verification_plan = PaymentVerificationPlanFactory( - payment_plan_obj=payment_plan, + payment_plan=payment_plan, status=PaymentVerificationPlan.STATUS_PENDING, ) input_dict = { diff --git a/tests/unit/apps/payment/test_rapid_pro_verification_task.py b/tests/unit/apps/payment/test_rapid_pro_verification_task.py index e4a9520459..00ba39f555 100644 --- a/tests/unit/apps/payment/test_rapid_pro_verification_task.py +++ b/tests/unit/apps/payment/test_rapid_pro_verification_task.py @@ -12,10 +12,11 @@ from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.household.fixtures import EntitlementCardFactory, create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentVerification, PaymentVerificationPlan from hct_mis_api.apps.payment.tasks.CheckRapidProVerificationTask import ( @@ -93,15 +94,15 @@ def setUpTestData(cls) -> None: targeting_criteria=targeting_criteria, business_area=BusinessArea.objects.first(), ) - cash_plan = CashPlanFactory( - program=program, + payment_plan = PaymentPlanFactory( + program_cycle=program.cycles.first(), business_area=BusinessArea.objects.first(), ) - cash_plan.save() + PaymentVerificationSummaryFactory(payment_plan=payment_plan) payment_verification_plan = PaymentVerificationPlanFactory( status=PaymentVerificationPlan.STATUS_ACTIVE, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_RAPIDPRO, - payment_plan_obj=cash_plan, + payment_plan=payment_plan, ) cls.individuals = [] for _ in range(payment_record_amount): @@ -119,8 +120,8 @@ def setUpTestData(cls) -> None: household.programs.add(program) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, head_of_household=household.head_of_household, target_population=target_population, @@ -130,12 +131,12 @@ def setUpTestData(cls) -> None: PaymentVerificationFactory( payment_verification_plan=payment_verification_plan, - payment_obj=payment_record, + payment=payment, status=PaymentVerification.STATUS_PENDING, ) EntitlementCardFactory(household=household) - cls.cash_plan = cash_plan - cls.verification = cash_plan.get_payment_verification_plans.first() + cls.payment_plan = payment_plan + cls.verification = payment_plan.payment_verification_plans.first() @patch("hct_mis_api.apps.core.services.rapid_pro.api.RapidProAPI.__init__") def test_filtering_by_start_id(self, mock_parent_init: Any) -> None: @@ -143,7 +144,7 @@ def test_filtering_by_start_id(self, mock_parent_init: Any) -> None: payment_record_verification_obj = TestRapidProVerificationTask.verification.payment_record_verifications.first() TestRapidProVerificationTask.ORIGINAL_RAPIDPRO_RUNS_RESPONSE[0]["contact"][ "urn" - ] = f"tel:{payment_record_verification_obj.payment_obj.head_of_household.phone_no}" + ] = f"tel:{payment_record_verification_obj.payment.head_of_household.phone_no}" mock = MagicMock(return_value=TestRapidProVerificationTask.ORIGINAL_RAPIDPRO_RUNS_RESPONSE) with patch("hct_mis_api.apps.core.services.rapid_pro.api.RapidProAPI.get_flow_runs", mock): api = RapidProAPI("afghanistan", RapidProAPI.MODE_VERIFICATION) @@ -159,7 +160,7 @@ def test_mapping(self, mock_parent_init: Any) -> None: payment_record_verification_obj = TestRapidProVerificationTask.verification.payment_record_verifications.first() TestRapidProVerificationTask.ORIGINAL_RAPIDPRO_RUNS_RESPONSE[0]["contact"][ "urn" - ] = f"tel:{payment_record_verification_obj.payment_obj.head_of_household.phone_no}" + ] = f"tel:{payment_record_verification_obj.payment.head_of_household.phone_no}" mock = MagicMock(return_value=TestRapidProVerificationTask.ORIGINAL_RAPIDPRO_RUNS_RESPONSE) with patch("hct_mis_api.apps.core.services.rapid_pro.api.RapidProAPI.get_flow_runs", mock): api = RapidProAPI("afghanistan", RapidProAPI.MODE_VERIFICATION) @@ -168,7 +169,7 @@ def test_mapping(self, mock_parent_init: Any) -> None: mapped_dict, [ { - "phone_number": str(payment_record_verification_obj.payment_obj.head_of_household.phone_no), + "phone_number": str(payment_record_verification_obj.payment.head_of_household.phone_no), "received": True, "received_amount": Decimal("200"), } @@ -188,13 +189,13 @@ def test_not_received(self, mock_parent_init: Any) -> None: fake_data_to_return_from_rapid_pro_api = [ { - "phone_number": str(payment_record_verification.payment_obj.head_of_household.phone_no), + "phone_number": str(payment_record_verification.payment.head_of_household.phone_no), "received": False, } ] assert is_valid_phone_number( - payment_record_verification.payment_obj.head_of_household.phone_no - ), payment_record_verification.payment_obj.head_of_household.phone_no + payment_record_verification.payment.head_of_household.phone_no + ), payment_record_verification.payment.head_of_household.phone_no mock = MagicMock(return_value=fake_data_to_return_from_rapid_pro_api) with patch("hct_mis_api.apps.core.services.rapid_pro.api.RapidProAPI.get_mapped_flow_runs", mock): task = CheckRapidProVerificationTask() @@ -217,13 +218,13 @@ def test_received_with_issues(self, mock_parent_init: Any) -> None: PaymentVerification.STATUS_PENDING, ) assert is_valid_phone_number( - payment_record_verification.payment_obj.head_of_household.phone_no - ), payment_record_verification.payment_obj.head_of_household.phone_no + payment_record_verification.payment.head_of_household.phone_no + ), payment_record_verification.payment.head_of_household.phone_no fake_data_to_return_from_rapid_pro_api = [ { - "phone_number": str(payment_record_verification.payment_obj.head_of_household.phone_no), + "phone_number": str(payment_record_verification.payment.head_of_household.phone_no), "received": True, - "received_amount": payment_record_verification.payment_obj.delivered_quantity - 1, + "received_amount": payment_record_verification.payment.delivered_quantity - 1, } ] mock = MagicMock(return_value=fake_data_to_return_from_rapid_pro_api) @@ -238,7 +239,7 @@ def test_received_with_issues(self, mock_parent_init: Any) -> None: ) self.assertEqual( payment_record_verification.received_amount, - payment_record_verification.payment_obj.delivered_quantity - 1, + payment_record_verification.payment.delivered_quantity - 1, ) @patch("hct_mis_api.apps.core.services.rapid_pro.api.RapidProAPI.__init__") @@ -253,14 +254,14 @@ def test_received(self, mock_parent_init: Any) -> None: ) fake_data_to_return_from_rapid_pro_api = [ { - "phone_number": str(payment_record_verification.payment_obj.head_of_household.phone_no), + "phone_number": str(payment_record_verification.payment.head_of_household.phone_no), "received": True, - "received_amount": payment_record_verification.payment_obj.delivered_quantity, + "received_amount": payment_record_verification.payment.delivered_quantity, } ] assert is_valid_phone_number( - payment_record_verification.payment_obj.head_of_household.phone_no - ), payment_record_verification.payment_obj.head_of_household.phone_no + payment_record_verification.payment.head_of_household.phone_no + ), payment_record_verification.payment.head_of_household.phone_no mock = MagicMock(return_value=fake_data_to_return_from_rapid_pro_api) with patch("hct_mis_api.apps.core.services.rapid_pro.api.RapidProAPI.get_mapped_flow_runs", mock): task = CheckRapidProVerificationTask() @@ -273,7 +274,7 @@ def test_received(self, mock_parent_init: Any) -> None: ) self.assertEqual( payment_record_verification.received_amount, - payment_record_verification.payment_obj.delivered_quantity, + payment_record_verification.payment.delivered_quantity, ) @patch("hct_mis_api.apps.core.services.rapid_pro.api.RapidProAPI.__init__") @@ -290,7 +291,7 @@ def test_wrong_phone_number(self, mock_parent_init: Any) -> None: { "phone_number": "123-not-really-a-phone-number", "received": True, - "received_amount": payment_record_verification.payment_obj.delivered_quantity, + "received_amount": payment_record_verification.payment.delivered_quantity, } ] mock = MagicMock(return_value=fake_data_to_return_from_rapid_pro_api) diff --git a/tests/unit/apps/payment/test_sample_size.py b/tests/unit/apps/payment/test_sample_size.py index 3ac4af2cca..222a46dc9f 100644 --- a/tests/unit/apps/payment/test_sample_size.py +++ b/tests/unit/apps/payment/test_sample_size.py @@ -6,14 +6,14 @@ from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.core.utils import encode_id_base64 from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import CashPlanFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.payment.models import PaymentRecord -def create_query_variables(cash_plan: CashPlanFactory, verification_channel: Any) -> Dict: +def create_query_variables(payment_plan: PaymentPlanFactory, verification_channel: Any) -> Dict: return { "input": { - "cashOrPaymentPlanId": encode_id_base64(cash_plan.pk, "CashPlan"), + "cashOrPaymentPlanId": encode_id_base64(payment_plan.pk, "PaymentPlan"), "sampling": "FULL_LIST", "fullListArguments": {"excludedAdminAreas": []}, "verificationChannel": verification_channel, @@ -43,7 +43,7 @@ def setUpTestData(cls) -> None: cls.business_area = BusinessArea.objects.get(slug="afghanistan") cls.household, cls.individuals = create_household(household_args={"size": 2}) - cls.cash_plan = CashPlanFactory() + cls.payment_plan = PaymentPlanFactory() cls.individuals[0].phone_no = "invalid-phone-no" cls.individuals[0].phone_no_alternative = "invalid-phone-no" @@ -54,8 +54,8 @@ def setUpTestData(cls) -> None: cls.individuals[1].save() def test_sample_size_in_manual_verification_plan(self) -> None: - PaymentRecordFactory( - parent=self.cash_plan, + PaymentFactory( + parent=self.payment_plan, business_area=self.business_area, household=self.household, head_of_household_id=self.individuals[0].id, @@ -79,9 +79,9 @@ def test_sample_size_in_manual_verification_plan(self) -> None: self.assertEqual(rapid_pro_response["data"]["sampleSize"]["paymentRecordCount"], 0) def test_number_of_queries(self) -> None: - PaymentRecordFactory.create_batch( + PaymentFactory.create_batch( 4, - parent=self.cash_plan, + parent=self.payment_plan, business_area=self.business_area, household=self.household, head_of_household_id=self.individuals[1].id, diff --git a/tests/unit/apps/payment/test_verification_plan_status_change_services.py b/tests/unit/apps/payment/test_verification_plan_status_change_services.py index d09375affb..e0da7a220e 100644 --- a/tests/unit/apps/payment/test_verification_plan_status_change_services.py +++ b/tests/unit/apps/payment/test_verification_plan_status_change_services.py @@ -12,10 +12,11 @@ from hct_mis_api.apps.geo.models import Area from hct_mis_api.apps.household.fixtures import EntitlementCardFactory, create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentRecordFactory, + PaymentFactory, + PaymentPlanFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, + PaymentVerificationSummaryFactory, ) from hct_mis_api.apps.payment.models import PaymentVerification, PaymentVerificationPlan from hct_mis_api.apps.payment.services.verification_plan_status_change_services import ( @@ -48,15 +49,15 @@ def setUpTestData(cls) -> None: targeting_criteria=targeting_criteria, business_area=BusinessArea.objects.first(), ) - cash_plan = CashPlanFactory( - program=program, + payment_plan = PaymentPlanFactory( + program_cycle=program.cycles.first(), business_area=BusinessArea.objects.first(), ) - cash_plan.save() + PaymentVerificationSummaryFactory(payment_plan=payment_plan) cash_plan_payment_verification = PaymentVerificationPlanFactory( status=PaymentVerificationPlan.STATUS_PENDING, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_RAPIDPRO, - payment_plan_obj=cash_plan, + payment_plan=payment_plan, ) cls.individuals = [] for i in range(cls.payment_record_amount): @@ -78,8 +79,8 @@ def setUpTestData(cls) -> None: household.programs.add(program) - payment_record = PaymentRecordFactory( - parent=cash_plan, + payment = PaymentFactory( + parent=payment_plan, household=household, head_of_household=household.head_of_household, target_population=target_population, @@ -89,12 +90,12 @@ def setUpTestData(cls) -> None: PaymentVerificationFactory( payment_verification_plan=cash_plan_payment_verification, - payment_obj=payment_record, + payment=payment, status=PaymentVerification.STATUS_PENDING, ) EntitlementCardFactory(household=household) - cls.cash_plan = cash_plan - cls.verification = cash_plan.get_payment_verification_plans.first() + cls.payment_plan = payment_plan + cls.verification = payment_plan.payment_verification_plans.first() ### @@ -107,15 +108,14 @@ def setUpTestData(cls) -> None: targeting_criteria=other_targeting_criteria, business_area=BusinessArea.objects.first(), ) - other_cash_plan = CashPlanFactory( - program=other_program, + other_payment_plan = PaymentPlanFactory( + program_cycle=other_program.cycles.first(), business_area=BusinessArea.objects.first(), ) - other_cash_plan.save() - other_cash_plan_payment_verification = PaymentVerificationPlanFactory( + other_payment_plan_payment_verification = PaymentVerificationPlanFactory( status=PaymentVerificationPlan.STATUS_PENDING, verification_channel=PaymentVerificationPlan.VERIFICATION_CHANNEL_RAPIDPRO, - payment_plan_obj=other_cash_plan, + payment_plan=other_payment_plan, ) cls.other_individuals = [] for _ in range(cls.payment_record_amount): @@ -134,8 +134,8 @@ def setUpTestData(cls) -> None: other_household.programs.add(program) - other_payment_record = PaymentRecordFactory( - parent=other_cash_plan, + other_payment_record = PaymentFactory( + parent=other_payment_plan, household=other_household, head_of_household=other_household.head_of_household, target_population=other_target_population, @@ -144,13 +144,13 @@ def setUpTestData(cls) -> None: ) PaymentVerificationFactory( - payment_verification_plan=other_cash_plan_payment_verification, + payment_verification_plan=other_payment_plan_payment_verification, payment_obj=other_payment_record, status=PaymentVerification.STATUS_PENDING, ) EntitlementCardFactory(household=other_household) - cls.other_cash_plan = other_cash_plan - cls.other_verification = other_cash_plan.get_payment_verification_plans.first() + cls.other_payment_plan = other_payment_plan + cls.other_verification = other_payment_plan.get_payment_verification_plans.first() def test_failing_rapid_pro_during_cash_plan_payment_verification(self) -> None: self.assertEqual(self.verification.status, PaymentVerification.STATUS_PENDING) diff --git a/tests/unit/apps/program/test_all_programs_query.py b/tests/unit/apps/program/test_all_programs_query.py index 5b5ce7f041..864c75359e 100644 --- a/tests/unit/apps/program/test_all_programs_query.py +++ b/tests/unit/apps/program/test_all_programs_query.py @@ -224,7 +224,7 @@ def test_all_programs_with_cycles_filter(self) -> None: program = Program.objects.get(name="Program with all partners access") cycle = ProgramCycleFactory(program=program, title="Second CYCLE with total_delivered_quantity_usd") - PaymentPlanFactory(program=program, program_cycle=cycle, total_delivered_quantity_usd=999) + PaymentPlanFactory(program_cycle=cycle, total_delivered_quantity_usd=999) self.snapshot_graphql_request( request_string=self.ALL_PROGRAMS_QUERY_WITH_PROGRAM_CYCLE_FILTERS, diff --git a/tests/unit/apps/program/test_cash_plan_queries.py b/tests/unit/apps/program/test_cash_plan_queries.py index e5707db832..cee4410577 100644 --- a/tests/unit/apps/program/test_cash_plan_queries.py +++ b/tests/unit/apps/program/test_cash_plan_queries.py @@ -8,7 +8,7 @@ from hct_mis_api.apps.core.fixtures import create_afghanistan from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.payment.delivery_mechanisms import DeliveryMechanismChoices -from hct_mis_api.apps.payment.fixtures import CashPlanFactory +from hct_mis_api.apps.payment.fixtures import PaymentPlanFactory from hct_mis_api.apps.program.fixtures import ProgramFactory QUERY_SINGLE_CASH_PLAN = """ @@ -67,7 +67,7 @@ def setUpTestData(cls) -> None: cls.user = UserFactory(partner=cls.partner) cls.business_area = BusinessArea.objects.get(slug="afghanistan") program = ProgramFactory.create(business_area=cls.business_area) - cls.CASH_PLANS_TO_CREATE = [ + cls.PAYMENTS_PLANS_TO_CREATE = [ { "business_area": cls.business_area, "id": "c7e768f1-5626-413e-a032-5fb18789f985", @@ -105,10 +105,10 @@ def setUpTestData(cls) -> None: }, ] - for cash_plan in cls.CASH_PLANS_TO_CREATE: - CashPlanFactory.create( + for payment_plan in cls.PAYMENT_PLANS_TO_CREATE: + PaymentPlanFactory.create( program=program, - **cash_plan, + **payment_plan, ) @parameterized.expand( @@ -123,7 +123,7 @@ def test_cash_plans(self, name: str, permissions: List[Permissions], query: str) self.create_user_role_with_permissions(self.user, permissions, self.business_area) variables = {} if "single" in name: - variables["id"] = self.id_to_base64("c7e768f1-5626-413e-a032-5fb18789f985", "CashPlanNode") + variables["id"] = self.id_to_base64("c7e768f1-5626-413e-a032-5fb18789f985", "PaymentPlanNode") self.snapshot_graphql_request( request_string=query, diff --git a/tests/unit/apps/program/test_dashboard_queries.py b/tests/unit/apps/program/test_dashboard_queries.py index 603b01aa59..5664db1757 100644 --- a/tests/unit/apps/program/test_dashboard_queries.py +++ b/tests/unit/apps/program/test_dashboard_queries.py @@ -9,10 +9,8 @@ from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.household.fixtures import create_household from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, PaymentFactory, PaymentPlanFactory, - PaymentRecordFactory, generate_delivery_mechanisms, ) from hct_mis_api.apps.payment.models import DeliveryMechanism @@ -84,17 +82,17 @@ def test_chart_programmes_by_sector(self) -> None: program3 = ProgramFactory.create(cash_plus=False, sector=Program.NUTRITION) program4 = ProgramFactory.create(cash_plus=True, sector=Program.WASH) - cash_plan1 = CashPlanFactory(program=program1) - cash_plan2 = CashPlanFactory(program=program2) + payment_plan1 = PaymentPlanFactory(program_cycle=program1.cycles.first()) + payment_plan2 = PaymentPlanFactory(program_cycle=program2.cycles.first()) delivery_date = timezone.datetime(2021, 10, 10, tzinfo=utc) - PaymentRecordFactory(parent=cash_plan1, delivery_date=delivery_date, household=household, currency="PLN") - PaymentRecordFactory(parent=cash_plan2, delivery_date=delivery_date, household=household, currency="PLN") - - payment_plan1 = PaymentPlanFactory(program=program3) - payment_plan2 = PaymentPlanFactory(program=program4) PaymentFactory(parent=payment_plan1, delivery_date=delivery_date, household=household, currency="PLN") PaymentFactory(parent=payment_plan2, delivery_date=delivery_date, household=household, currency="PLN") + payment_plan3 = PaymentPlanFactory(program_cycle=program3.cycles.first()) + payment_plan4 = PaymentPlanFactory(program_cycle=program4.cycles.first()) + PaymentFactory(parent=payment_plan3, delivery_date=delivery_date, household=household, currency="PLN") + PaymentFactory(parent=payment_plan4, delivery_date=delivery_date, household=household, currency="PLN") + self.snapshot_graphql_request( request_string=QUERY_CHART_PROGRAMMES_BY_SECTOR, variables={"businessAreaSlug": "afghanistan", "year": 2021}, @@ -104,70 +102,63 @@ def test_chart_programmes_by_sector(self) -> None: def test_chart_total_transferred_by_month(self) -> None: dm_cash = DeliveryMechanism.objects.get(code="cash") dm_voucher = DeliveryMechanism.objects.get(code="voucher") - household, individuals = create_household( - household_args={"size": 2, "business_area": self.business_area}, - ) program1 = ProgramFactory.create(cash_plus=True, sector=Program.EDUCATION) - cash_plan1 = CashPlanFactory(program=program1) + payment_plan1 = PaymentPlanFactory(program_cycle=program1.cycles.first()) delivery_date1 = timezone.datetime(2021, 10, 10, tzinfo=utc) delivery_date2 = timezone.datetime(2021, 11, 10, tzinfo=utc) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=delivery_date1, - household=household, delivery_type=dm_cash, delivered_quantity_usd=133, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=delivery_date1, - household=household, delivery_type=dm_voucher, delivered_quantity_usd=25, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=delivery_date2, - household=household, delivery_type=dm_cash, delivered_quantity_usd=133, currency="PLN", ) - PaymentRecordFactory( - parent=cash_plan1, + PaymentFactory( + parent=payment_plan1, delivery_date=delivery_date2, - household=household, delivery_type=dm_voucher, delivered_quantity_usd=25, currency="PLN", ) - payment_plan1 = PaymentPlanFactory(program=program1) + payment_plan2 = PaymentPlanFactory(program_cycle=program1.cycles.first()) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=delivery_date1, delivery_type=dm_cash, delivered_quantity_usd=133, currency="PLN", ) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=delivery_date1, delivery_type=dm_voucher, delivered_quantity_usd=25, currency="PLN", ) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=delivery_date2, delivery_type=dm_cash, delivered_quantity_usd=133, currency="PLN", ) PaymentFactory( - parent=payment_plan1, + parent=payment_plan2, delivery_date=delivery_date2, delivery_type=dm_voucher, delivered_quantity_usd=25, diff --git a/tests/unit/apps/program/test_program_cycle.py b/tests/unit/apps/program/test_program_cycle.py index efd17a02b9..581328f325 100644 --- a/tests/unit/apps/program/test_program_cycle.py +++ b/tests/unit/apps/program/test_program_cycle.py @@ -111,19 +111,17 @@ def test_set_finish(self) -> None: def test_total_entitled_quantity_usd(self) -> None: self.assertEqual(self.cycle.total_entitled_quantity_usd, Decimal("0.0")) - PaymentPlanFactory(program=self.program, program_cycle=self.cycle, total_entitled_quantity_usd=Decimal(123.99)) + PaymentPlanFactory(program_cycle=self.cycle, total_entitled_quantity_usd=Decimal(123.99)) self.assertEqual(self.cycle.total_entitled_quantity_usd, Decimal("123.99")) def test_total_undelivered_quantity_usd(self) -> None: self.assertEqual(self.cycle.total_undelivered_quantity_usd, Decimal("0.0")) - PaymentPlanFactory( - program=self.program, program_cycle=self.cycle, total_undelivered_quantity_usd=Decimal(222.33) - ) + PaymentPlanFactory(program_cycle=self.cycle, total_undelivered_quantity_usd=Decimal(222.33)) self.assertEqual(self.cycle.total_undelivered_quantity_usd, Decimal("222.33")) def test_total_delivered_quantity_usd(self) -> None: self.assertEqual(self.cycle.total_delivered_quantity_usd, Decimal("0.0")) - PaymentPlanFactory(program=self.program, program_cycle=self.cycle, total_delivered_quantity_usd=Decimal(333.11)) + PaymentPlanFactory(program_cycle=self.cycle, total_delivered_quantity_usd=Decimal(333.11)) self.assertEqual(self.cycle.total_delivered_quantity_usd, Decimal("333.11")) def test_cycle_validation_start_date(self) -> None: diff --git a/tests/unit/apps/program/test_program_cycle_rest_api.py b/tests/unit/apps/program/test_program_cycle_rest_api.py index 84c0a4e52d..4a4197462b 100644 --- a/tests/unit/apps/program/test_program_cycle_rest_api.py +++ b/tests/unit/apps/program/test_program_cycle_rest_api.py @@ -177,7 +177,7 @@ def test_delete_program_cycle(self) -> None: ) # create TP and PP tp = TargetPopulationFactory(program_cycle=cycle3, program=self.program) - pp = PaymentPlanFactory(program_cycle=cycle3, target_population=tp, program=self.program) + pp = PaymentPlanFactory(program_cycle=cycle3, target_population=tp) self.assertEqual(TargetPopulation.objects.count(), 1) self.assertEqual(ProgramCycle.objects.count(), 4) self.client.force_authenticate(user=self.user) diff --git a/tests/unit/apps/program/test_update_program.py b/tests/unit/apps/program/test_update_program.py index 57cc5d7fde..9403f7cabc 100644 --- a/tests/unit/apps/program/test_update_program.py +++ b/tests/unit/apps/program/test_update_program.py @@ -974,6 +974,7 @@ def test_update_program_end_date_validation(self) -> None: self.assertEqual(self.program.status, Program.ACTIVE) self.assertIsNone(self.program.end_date) program_cycle = self.program.cycles.first() + program_cycle.start_date = self.program.start_date program_cycle.end_date = self.program.start_date + timedelta(days=5) program_cycle.save() diff --git a/tests/unit/apps/program/test_validators.py b/tests/unit/apps/program/test_validators.py index 4ff7a4610e..0deaf18f2e 100644 --- a/tests/unit/apps/program/test_validators.py +++ b/tests/unit/apps/program/test_validators.py @@ -38,7 +38,7 @@ def test_program_validator(self) -> None: data = {"program": self.program, "program_data": {"status": Program.FINISHED}} self.program.status = Program.ACTIVE self.program.save() - PaymentPlanFactory(program=self.program, program_cycle=self.program_cycle, status=PaymentPlan.Status.IN_REVIEW) + PaymentPlanFactory(program_cycle=self.program_cycle, status=PaymentPlan.Status.IN_REVIEW) with self.assertRaisesMessage( ValidationError, "All Payment Plans and Follow-Up Payment Plans have to be Reconciled." diff --git a/tests/unit/apps/reporting/test_report_service.py b/tests/unit/apps/reporting/test_report_service.py index f4797fa555..1784f20715 100644 --- a/tests/unit/apps/reporting/test_report_service.py +++ b/tests/unit/apps/reporting/test_report_service.py @@ -15,10 +15,8 @@ from hct_mis_api.apps.geo.fixtures import AreaFactory, AreaTypeFactory from hct_mis_api.apps.household.fixtures import create_household_and_individuals from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, PaymentFactory, PaymentPlanFactory, - PaymentRecordFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, ) @@ -85,81 +83,83 @@ def setUpTestData(self) -> None: else: household.programs.add(self.program_2) - self.cash_plan_1 = CashPlanFactory( + self.payment_plan_1 = PaymentPlanFactory( business_area=self.business_area, - program=self.program_1, + program_cycle=self.program_1.cycles.first(), # end_date=datetime.datetime.fromisoformat("2020-01-01 00:01:11+00:00"), ) - self.cash_plan_2 = CashPlanFactory( + self.payment_plan_2 = PaymentPlanFactory( business_area=self.business_area, # end_date=datetime.datetime.fromisoformat("2020-01-01 00:01:11+00:00") ) - self.payment_plan_1 = PaymentPlanFactory( + self.payment_plan_3 = PaymentPlanFactory( business_area=self.business_area, - program=self.program_1, + program_cycle=self.program_1.cycles.first(), # end_date=datetime.datetime.fromisoformat("2020-01-01 00:01:11+00:00"), ) - self.payment_plan_2 = PaymentPlanFactory( + self.payment_plan_4 = PaymentPlanFactory( business_area=self.business_area, # end_date=datetime.datetime.fromisoformat("2020-01-01 00:01:11+00:00") ) - PaymentVerificationSummary.objects.create(payment_plan_obj=self.payment_plan_1) - PaymentVerificationSummary.objects.create(payment_plan_obj=self.payment_plan_2) - self.cash_plan_verification_1 = PaymentVerificationPlanFactory( - payment_plan_obj=self.cash_plan_1, completion_date="2020-01-01T14:30+00:00" - ) - self.cash_plan_verification_2 = PaymentVerificationPlanFactory( - payment_plan_obj=self.cash_plan_2, completion_date="2020-01-01T14:30+00:00" - ) + PaymentVerificationSummary.objects.create(payment_plan=self.payment_plan_1) + PaymentVerificationSummary.objects.create(payment_plan=self.payment_plan_2) + PaymentVerificationSummary.objects.create(payment_plan=self.payment_plan_3) + PaymentVerificationSummary.objects.create(payment_plan=self.payment_plan_4) self.payment_plan_verification_1 = PaymentVerificationPlanFactory( payment_plan_obj=self.payment_plan_1, completion_date="2020-01-01T14:30+00:00" ) self.payment_plan_verification_2 = PaymentVerificationPlanFactory( payment_plan_obj=self.payment_plan_2, completion_date="2020-01-01T14:30+00:00" ) - record_1 = PaymentRecordFactory( + self.payment_plan_verification_3 = PaymentVerificationPlanFactory( + payment_plan=self.payment_plan_3, completion_date="2020-01-01T14:30+00:00" + ) + self.payment_plan_verification_4 = PaymentVerificationPlanFactory( + payment_plan=self.payment_plan_4, completion_date="2020-01-01T14:30+00:00" + ) + payment_1 = PaymentFactory( household=self.households[0], business_area=self.business_area, delivery_date="2020-01-01T00:00+00:00", - parent=self.cash_plan_1, + parent=self.payment_plan_1, currency="PLN", ) - record_2 = PaymentRecordFactory( + payment_2 = PaymentFactory( household=self.households[1], business_area=self.business_area, delivery_date="2020-01-01T00:00+00:00", - parent=self.cash_plan_2, + parent=self.payment_plan_2, currency="PLN", ) - payment_1 = PaymentFactory( + payment_3 = PaymentFactory( household=self.households[0], business_area=self.business_area, delivery_date="2020-01-01T14:30+00:00", - parent=self.payment_plan_1, + parent=self.payment_plan_3, currency="PLN", ) - payment_2 = PaymentFactory( + payment_4 = PaymentFactory( household=self.households[1], business_area=self.business_area, delivery_date="2020-01-01T14:30+00:00", - parent=self.payment_plan_2, + parent=self.payment_plan_4, currency="PLN", ) PaymentVerificationFactory( payment_verification_plan=self.cash_plan_verification_1, - payment_obj=record_1, + payment_obj=payment_1, ) PaymentVerificationFactory( payment_verification_plan=self.cash_plan_verification_2, - payment_obj=record_2, + payment_obj=payment_2, ) PaymentVerificationFactory( payment_verification_plan=self.payment_plan_verification_1, - payment_obj=payment_1, + payment=payment_3, ) PaymentVerificationFactory( payment_verification_plan=self.payment_plan_verification_2, - payment_obj=payment_2, + payment=payment_4, ) @parameterized.expand( diff --git a/tests/unit/apps/reporting/test_reporting_choices.py b/tests/unit/apps/reporting/test_reporting_choices.py index d859ad1736..9aba96e653 100644 --- a/tests/unit/apps/reporting/test_reporting_choices.py +++ b/tests/unit/apps/reporting/test_reporting_choices.py @@ -10,7 +10,7 @@ from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.grievance.models import GrievanceTicket from hct_mis_api.apps.household.fixtures import create_household -from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentRecordFactory +from hct_mis_api.apps.payment.fixtures import PaymentFactory from hct_mis_api.apps.payment.models import Payment, PaymentRecord @@ -81,7 +81,7 @@ def test_dashboard_years_choices(self) -> None: household, individuals = create_household( household_args={"size": 2, "business_area": business_area}, ) - PaymentRecordFactory( + PaymentFactory( delivery_date=timezone.datetime(2021, 10, 10, tzinfo=utc), business_area=business_area, household=household, diff --git a/tests/unit/one_time_scripts/test_create_payment_snapshot.py b/tests/unit/one_time_scripts/test_create_payment_snapshot.py index 9a4c0d92e7..64bee5146b 100644 --- a/tests/unit/one_time_scripts/test_create_payment_snapshot.py +++ b/tests/unit/one_time_scripts/test_create_payment_snapshot.py @@ -1,5 +1,3 @@ -from datetime import datetime - from django.test import TestCase from freezegun import freeze_time @@ -31,10 +29,7 @@ def setUpTestData(cls) -> None: program = RealProgramFactory() program_cycle = program.cycles.first() cls.pp = PaymentPlanFactory( - program=program, program_cycle=program_cycle, - dispersion_start_date=datetime(2020, 8, 10), - dispersion_end_date=datetime(2020, 12, 10), is_follow_up=False, ) cls.hoh1 = IndividualFactory(household=None) diff --git a/tests/unit/one_time_scripts/test_mass_withdraw_sudan_hhs.py b/tests/unit/one_time_scripts/test_mass_withdraw_sudan_hhs.py index 0898de1f1f..bd873f8102 100644 --- a/tests/unit/one_time_scripts/test_mass_withdraw_sudan_hhs.py +++ b/tests/unit/one_time_scripts/test_mass_withdraw_sudan_hhs.py @@ -60,7 +60,7 @@ def test_mass_withdraw_sudan_hhs(self) -> None: True, ) self.assertEqual( - self.household.user_fields["withdrawn_tag"], + self.household.internal_data["withdrawn_tag"], "Received Full entitlements", ) self.assertEqual( diff --git a/tests/unit/one_time_scripts/test_migrate_data_to_representations.py b/tests/unit/one_time_scripts/test_migrate_data_to_representations.py index ae91833bc6..a0bbd4a4a2 100644 --- a/tests/unit/one_time_scripts/test_migrate_data_to_representations.py +++ b/tests/unit/one_time_scripts/test_migrate_data_to_representations.py @@ -34,14 +34,8 @@ IndividualIdentity, IndividualRoleInHousehold, ) -from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, - PaymentFactory, - PaymentPlanFactory, - PaymentRecordFactory, - ServiceProviderFactory, -) -from hct_mis_api.apps.payment.models import Payment, PaymentRecord, ServiceProvider +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory +from hct_mis_api.apps.payment.models import Payment from hct_mis_api.apps.program.fixtures import ProgramFactory from hct_mis_api.apps.program.models import Program from hct_mis_api.apps.registration_data.fixtures import RegistrationDataImportFactory @@ -49,7 +43,6 @@ from hct_mis_api.apps.targeting.fixtures import TargetPopulationFactory from hct_mis_api.apps.targeting.models import HouseholdSelection, TargetPopulation from hct_mis_api.one_time_scripts.migrate_data_to_representations import ( - adjust_payment_records, adjust_payments, copy_household_representation_for_programs_fast, migrate_data_to_representations, @@ -193,7 +186,7 @@ def setUp(self) -> None: # Payments 1 payment_plan1 = PaymentPlanFactory( target_population=self.target_population1, - program=self.program_active, + program_cycle=self.program_active.cycles.first(), ) self.payment1 = PaymentFactory( @@ -205,18 +198,6 @@ def setUp(self) -> None: entitlement_quantity=103, currency="PLN", ) - cash_plan = CashPlanFactory( - program=self.program_active, - ) - - self.payment_record1 = PaymentRecordFactory( - target_population=self.target_population1, - household=self.household1, - head_of_household=self.individual1_1, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - parent=cash_plan, - currency="PLN", - ) # Household2 and its data (no RDI, in 2 programs) self.individual2_1 = IndividualFactory( @@ -262,7 +243,7 @@ def setUp(self) -> None: # Payments 2 payment_plan2 = PaymentPlanFactory( target_population=self.target_population_paid, - program=self.program_active, + program_cycle=self.program_active.cycles.first(), ) self.payment2 = PaymentFactory( parent=payment_plan2, @@ -273,15 +254,6 @@ def setUp(self) -> None: currency="PLN", ) - self.payment_record2 = PaymentRecordFactory( - target_population=self.target_population_paid, - household=self.household2, - head_of_household=self.collector2_1, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - parent=cash_plan, - currency="PLN", - ) - # Household3 and its data # Additional helper individual that will already be enrolled into a different program # and is representative in the household3 @@ -425,7 +397,7 @@ def setUp(self) -> None: # Payments 5 payment_plan5 = PaymentPlanFactory( target_population=self.target_population_paid, - program=self.program_finished1, + program_cycle=self.program_finished1.cycles.first(), ) self.payment5 = PaymentFactory( parent=payment_plan5, @@ -436,17 +408,10 @@ def setUp(self) -> None: currency="PLN", ) - self.payment_record5 = PaymentRecordFactory( - target_population=self.target_population_paid, - household=self.household5, - head_of_household=self.individual5_1, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - parent=cash_plan, - ) # Payments 7 payment_plan7 = PaymentPlanFactory( target_population=self.target_population3, - program=self.program_finished2, + program_cycle=self.program_finished2.cycles.first(), ) self.payment7 = PaymentFactory( parent=payment_plan7, @@ -456,15 +421,6 @@ def setUp(self) -> None: program=self.program_finished2, currency="PLN", ) - - self.payment_record7 = PaymentRecordFactory( - target_population=self.target_population3, - household=self.household7, - head_of_household=self.individual7_1, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - parent=cash_plan, - ) - # Households from mixed rdi self.rdi_mixed = RegistrationDataImportFactory( business_area=self.business_area, @@ -670,9 +626,7 @@ def refresh_objects(self) -> None: self.individual4_1.refresh_from_db() self.collector2_1.refresh_from_db() self.payment1.refresh_from_db() - self.payment_record1.refresh_from_db() self.payment2.refresh_from_db() - self.payment_record2.refresh_from_db() self.household5.refresh_from_db() self.individual5_1.refresh_from_db() self.household6.refresh_from_db() @@ -682,9 +636,7 @@ def refresh_objects(self) -> None: self.collector5_1.refresh_from_db() self.collector5_2.refresh_from_db() self.payment5.refresh_from_db() - self.payment_record5.refresh_from_db() self.payment7.refresh_from_db() - self.payment_record7.refresh_from_db() self.rdi_with_3_hhs.refresh_from_db() self.individual_helper3.refresh_from_db() self.individual_mixed_closed_tp_paid.refresh_from_db() @@ -1806,42 +1758,31 @@ def test_migrate_data_to_representations_per_business_area(self) -> None: self.program_active, ) - def test_adjust_payments_and_payment_records(self) -> None: + def test_adjust_payments(self) -> None: payment_count = Payment.objects.filter(business_area=self.business_area).count() - payment_record_count = PaymentRecord.objects.filter(business_area=self.business_area).count() self.assertEqual(self.payment1.collector, self.individual1_2) self.assertEqual(self.payment1.head_of_household, self.individual1_1) self.assertEqual(self.payment1.household, self.household1) - self.assertEqual(self.payment_record1.head_of_household, self.individual1_1) - self.assertEqual(self.payment_record1.household, self.household1) self.assertEqual(self.payment2.collector, self.collector2_1) self.assertEqual(self.payment2.head_of_household, self.individual2_1) self.assertEqual(self.payment2.household, self.household2) - self.assertEqual(self.payment_record2.head_of_household, self.collector2_1) - self.assertEqual(self.payment_record2.household, self.household2) self.assertEqual(self.payment5.collector, self.collector5_1) self.assertEqual(self.payment5.head_of_household, self.individual5_1) self.assertEqual(self.payment5.household, self.household5) - self.assertEqual(self.payment_record5.head_of_household, self.individual5_1) - self.assertEqual(self.payment_record5.household, self.household5) self.assertEqual(self.payment7.collector, self.collector5_1) self.assertEqual(self.payment7.head_of_household, self.individual7_1) self.assertEqual(self.payment7.household, self.household7) - self.assertEqual(self.payment_record7.head_of_household, self.individual7_1) - self.assertEqual(self.payment_record7.household, self.household7) migrate_data_to_representations_per_business_area(business_area=self.business_area) adjust_payments(business_area=self.business_area) - adjust_payment_records(business_area=self.business_area) self.refresh_objects() self.assertEqual(Payment.objects.filter(business_area=self.business_area).count(), payment_count) - self.assertEqual(PaymentRecord.objects.filter(business_area=self.business_area).count(), payment_record_count) # payment1 individual1_1_representation1 = Individual.original_and_repr_objects.filter( @@ -1856,8 +1797,6 @@ def test_adjust_payments_and_payment_records(self) -> None: self.assertEqual(self.payment1.collector, individual1_2_representation1) self.assertEqual(self.payment1.head_of_household, individual1_1_representation1) self.assertEqual(self.payment1.household, household1_representation1) - self.assertEqual(self.payment_record1.head_of_household, individual1_1_representation1) - self.assertEqual(self.payment_record1.household, household1_representation1) # payment2 individual2_1_representation2 = Individual.original_and_repr_objects.filter( @@ -1872,8 +1811,6 @@ def test_adjust_payments_and_payment_records(self) -> None: self.assertEqual(self.payment2.collector, collector2_1_representation2) self.assertEqual(self.payment2.head_of_household, individual2_1_representation2) self.assertEqual(self.payment2.household, household2_representation2) - self.assertEqual(self.payment_record2.head_of_household, collector2_1_representation2) - self.assertEqual(self.payment_record2.household, household2_representation2) # payment5 collector5_1_representation2 = Individual.original_and_repr_objects.filter( @@ -1888,8 +1825,6 @@ def test_adjust_payments_and_payment_records(self) -> None: self.assertEqual(self.payment5.collector, collector5_1_representation2) self.assertEqual(self.payment5.head_of_household, individual5_1_representation2) self.assertEqual(self.payment5.household, household5_representation2) - self.assertEqual(self.payment_record5.head_of_household, individual5_1_representation2) - self.assertEqual(self.payment_record5.household, household5_representation2) # payment7 collector5_1_representation3 = Individual.original_and_repr_objects.filter( @@ -1904,8 +1839,6 @@ def test_adjust_payments_and_payment_records(self) -> None: self.assertEqual(self.payment7.collector, collector5_1_representation3) self.assertEqual(self.payment7.head_of_household, individual7_1_representation3) self.assertEqual(self.payment7.household, household7_representation3) - self.assertEqual(self.payment_record7.head_of_household, individual7_1_representation3) - self.assertEqual(self.payment_record7.household, household7_representation3) class TestCountrySpecificRules(TestCase): diff --git a/tests/unit/one_time_scripts/test_migrate_data_to_representations_performance.py b/tests/unit/one_time_scripts/test_migrate_data_to_representations_performance.py index 99e2610e69..3128c8b496 100644 --- a/tests/unit/one_time_scripts/test_migrate_data_to_representations_performance.py +++ b/tests/unit/one_time_scripts/test_migrate_data_to_representations_performance.py @@ -29,13 +29,11 @@ Individual, ) from hct_mis_api.apps.payment.fixtures import ( - CashPlanFactory, + FinancialServiceProviderFactory, PaymentFactory, PaymentPlanFactory, - PaymentRecordFactory, - ServiceProviderFactory, ) -from hct_mis_api.apps.payment.models import ServiceProvider +from hct_mis_api.apps.payment.models import FinancialServiceProvider from hct_mis_api.apps.program.fixtures import ProgramFactory from hct_mis_api.apps.program.models import Program from hct_mis_api.apps.registration_data.fixtures import RegistrationDataImportFactory @@ -204,7 +202,7 @@ def setUp(self) -> None: # Payments 1 payment_plan1 = PaymentPlanFactory( target_population=self.target_population1, - program=self.program_active, + program_cycle=self.program_active.cycles.first(), ) self.payment1 = PaymentFactory( @@ -216,16 +214,16 @@ def setUp(self) -> None: entitlement_quantity=103, currency="PLN", ) - cash_plan = CashPlanFactory( + payment_plan2 = PaymentPlanFactory( program=self.program_active, ) - self.payment_record1 = PaymentRecordFactory( + self.payment2 = PaymentFactory( target_population=self.target_population1, household=self.household1, head_of_household=self.individual1_1, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - parent=cash_plan, + service_provider=FinancialServiceProvider.objects.first() or FinancialServiceProviderFactory(), + parent=payment_plan2, currency="PLN", ) @@ -265,12 +263,12 @@ def setUp(self) -> None: ) # Payments 2 - payment_plan2 = PaymentPlanFactory( + payment_plan3 = PaymentPlanFactory( target_population=self.target_population_paid, program=self.program_active, ) - self.payment2 = PaymentFactory( - parent=payment_plan2, + self.payment3 = PaymentFactory( + parent=payment_plan3, collector=self.collector2_1, household=self.household2, head_of_household=self.individual2_1, @@ -278,12 +276,12 @@ def setUp(self) -> None: currency="PLN", ) - self.payment_record2 = PaymentRecordFactory( + self.payment4 = PaymentFactory( target_population=self.target_population_paid, household=self.household2, head_of_household=self.collector2_1, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - parent=cash_plan, + service_provider=FinancialServiceProvider.objects.first() or FinancialServiceProviderFactory(), + parent=payment_plan2, currency="PLN", ) @@ -423,7 +421,7 @@ def setUp(self) -> None: # Payments 5 payment_plan5 = PaymentPlanFactory( target_population=self.target_population_paid, - program=self.program_finished1, + program_cycle=self.program_finished1.cycles.first(), ) self.payment5 = PaymentFactory( parent=payment_plan5, @@ -434,17 +432,17 @@ def setUp(self) -> None: currency="PLN", ) - self.payment_record5 = PaymentRecordFactory( + self.payment6 = PaymentFactory( target_population=self.target_population_paid, household=self.household5, head_of_household=self.individual5_1, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - parent=cash_plan, + service_provider=FinancialServiceProvider.objects.first() or FinancialServiceProviderFactory(), + parent=payment_plan2, ) # Payments 7 payment_plan7 = PaymentPlanFactory( target_population=self.target_population3, - program=self.program_finished2, + program_cycle=self.program_finished2.cycles.first(), ) self.payment7 = PaymentFactory( parent=payment_plan7, @@ -455,12 +453,12 @@ def setUp(self) -> None: currency="PLN", ) - self.payment_record7 = PaymentRecordFactory( + self.payment8 = PaymentFactory( target_population=self.target_population3, household=self.household7, head_of_household=self.individual7_1, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - parent=cash_plan, + service_provider=FinancialServiceProvider.objects.first() or FinancialServiceProviderFactory(), + parent=payment_plan2, ) # Households from mixed rdi diff --git a/tests/unit/one_time_scripts/test_migrate_data_to_representations_unit.py b/tests/unit/one_time_scripts/test_migrate_data_to_representations_unit.py index 03ca6f03a1..c6d4b2d624 100644 --- a/tests/unit/one_time_scripts/test_migrate_data_to_representations_unit.py +++ b/tests/unit/one_time_scripts/test_migrate_data_to_representations_unit.py @@ -31,13 +31,7 @@ IndividualIdentity, IndividualRoleInHousehold, ) -from hct_mis_api.apps.payment.fixtures import ( - PaymentFactory, - PaymentPlanFactory, - PaymentRecordFactory, - ServiceProviderFactory, -) -from hct_mis_api.apps.payment.models import ServiceProvider +from hct_mis_api.apps.payment.fixtures import PaymentFactory, PaymentPlanFactory from hct_mis_api.apps.program.fixtures import ProgramFactory from hct_mis_api.apps.program.models import Program from hct_mis_api.apps.registration_data.fixtures import RegistrationDataImportFactory @@ -48,7 +42,6 @@ ) from hct_mis_api.apps.targeting.models import HouseholdSelection from hct_mis_api.one_time_scripts.migrate_data_to_representations import ( - adjust_payment_records, adjust_payments, copy_bank_account_info_per_individual, copy_document_per_individual, @@ -508,57 +501,6 @@ def test_adjust_payments(self) -> None: self.assertEqual(self.payment1.household, household_this_program) -class TestAdjustPaymentRecords(TestCase): - def setUp(self) -> None: - self.business_area = BusinessAreaFactory() - self.other_program = ProgramFactory(status=Program.ACTIVE, business_area=self.business_area) - self.target_population1 = TargetPopulationFactory(program=self.other_program, business_area=self.business_area) - ( - self.household_original, - self.individual_original, - ) = create_origin_household_with_individual( - business_area=self.business_area, - ) - self.payment_record1 = PaymentRecordFactory( - target_population=self.target_population1, - household=self.household_original, - head_of_household=self.individual_original, - service_provider=ServiceProvider.objects.first() or ServiceProviderFactory(), - business_area=self.business_area, - ) - - def test_adjust_payment_records(self) -> None: - this_program = ProgramFactory(status=Program.ACTIVE, business_area=self.business_area) - - individual_representation_this_program = IndividualFactory( - program_id=this_program.id, - business_area=self.business_area, - copied_from=self.individual_original, - origin_unicef_id=self.individual_original.unicef_id, - household=None, - is_original=False, - ) - - household_this_program = HouseholdFactory( - program_id=this_program.id, - business_area=self.business_area, - copied_from=self.household_original, - origin_unicef_id=self.household_original.unicef_id, - head_of_household=individual_representation_this_program, - is_original=False, - ) - - self.target_population1.program = this_program - self.target_population1.save() - - adjust_payment_records(self.business_area) - - self.payment_record1.refresh_from_db() - - self.assertEqual(self.payment_record1.head_of_household, individual_representation_this_program) - self.assertEqual(self.payment_record1.household, household_this_program) - - @skip(reason="Skip this test for GPF") class TestCopyHouseholdSelections(TestCase): def setUp(self) -> None: diff --git a/tests/unit/one_time_scripts/test_migrate_grievance_to_representations.py b/tests/unit/one_time_scripts/test_migrate_grievance_to_representations.py index 8439630e64..f7e202d005 100644 --- a/tests/unit/one_time_scripts/test_migrate_grievance_to_representations.py +++ b/tests/unit/one_time_scripts/test_migrate_grievance_to_representations.py @@ -55,7 +55,6 @@ from hct_mis_api.apps.payment.fixtures import ( PaymentFactory, PaymentPlanFactory, - PaymentRecordFactory, PaymentVerificationFactory, PaymentVerificationPlanFactory, ) @@ -308,14 +307,14 @@ def create_complaint_tickets(self) -> None: [self.program2, self.program3] ) target_population2 = TargetPopulationFactory(program=self.program2) - payment_record = PaymentRecordFactory( + payment = PaymentFactory( target_population=target_population2, household=self.household_complaint_ticket_with_payment_record, currency="PLN", ) self.complaint_ticket_with_payment_record = GrievanceComplaintTicketWithoutExtrasFactory( - household=self.household_complaint_ticket_with_payment_record, individual=None, payment_obj=payment_record + household=self.household_complaint_ticket_with_payment_record, individual=None, payment=payment ) # ComplaintTicketDetails without payment_obj @@ -323,7 +322,7 @@ def create_complaint_tickets(self) -> None: self.complaint_ticket_no_payment_no_hh_no_ind_closed_gt = GrievanceComplaintTicketWithoutExtrasFactory( household=None, individual=None, - payment_obj=None, + payment=None, ) self.complaint_ticket_no_payment_no_hh_no_ind_closed_gt.ticket.status = GrievanceTicket.STATUS_CLOSED self.complaint_ticket_no_payment_no_hh_no_ind_closed_gt.ticket.save() @@ -338,7 +337,7 @@ def create_complaint_tickets(self) -> None: self.complaint_ticket_no_payment_closed_gt = GrievanceComplaintTicketWithoutExtrasFactory( household=self.household_complaint_ticket_no_payment_closed_gt, individual=self.individual_complaint_ticket_no_payment_closed_gt, - payment_obj=None, + payment=None, ) self.complaint_ticket_no_payment_closed_gt.ticket.status = GrievanceTicket.STATUS_CLOSED self.complaint_ticket_no_payment_closed_gt.ticket.save() @@ -350,7 +349,7 @@ def create_complaint_tickets(self) -> None: self.complaint_ticket_no_payment_closed_gt_only_hh = GrievanceComplaintTicketWithoutExtrasFactory( household=self.household_complaint_ticket_no_payment_closed_gt_only_hh, individual=None, - payment_obj=None, + payment=None, ) self.complaint_ticket_no_payment_closed_gt_only_hh.ticket.status = GrievanceTicket.STATUS_CLOSED self.complaint_ticket_no_payment_closed_gt_only_hh.ticket.save() @@ -362,7 +361,7 @@ def create_complaint_tickets(self) -> None: self.complaint_ticket_no_payment_only_hh = GrievanceComplaintTicketWithoutExtrasFactory( household=self.household_complaint_ticket_no_payment_only_hh, individual=None, - payment_obj=None, + payment=None, ) self.complaint_ticket_no_payment_only_hh.ticket.status = GrievanceTicket.STATUS_IN_PROGRESS self.complaint_ticket_no_payment_only_hh.ticket.save() @@ -378,7 +377,7 @@ def create_complaint_tickets(self) -> None: self.complaint_ticket_no_payment_not_closed_gt = GrievanceComplaintTicketWithoutExtrasFactory( household=self.household_complaint_ticket_no_payment_not_closed_gt, individual=self.individual_complaint_ticket_no_payment_not_closed_gt, - payment_obj=None, + payment=None, ) grievance_ticket = self.complaint_ticket_no_payment_not_closed_gt.ticket grievance_ticket.status = GrievanceTicket.STATUS_IN_PROGRESS @@ -392,7 +391,7 @@ def create_complaint_tickets(self) -> None: self.complaint_ticket_no_payment_not_closed_gt_no_hh_no_ind = GrievanceComplaintTicketWithoutExtrasFactory( household=None, individual=None, - payment_obj=None, + payment=None, ) grievance_ticket = self.complaint_ticket_no_payment_not_closed_gt_no_hh_no_ind.ticket grievance_ticket.status = GrievanceTicket.STATUS_IN_PROGRESS @@ -412,7 +411,7 @@ def create_sensitive_tickets(self) -> None: self.sensitive_ticket_with_payment = SensitiveGrievanceTicketWithoutExtrasFactory( household=None, individual=self.individual_sensitive_ticket_with_payment, - payment_obj=payment, + payment=payment, ) # TicketSensitiveDetails without payment_obj @@ -421,7 +420,7 @@ def create_sensitive_tickets(self) -> None: self.sensitive_ticket_no_payment_closed_gt = SensitiveGrievanceTicketWithoutExtrasFactory( household=None, individual=individual_pr1, - payment_obj=None, + payment=None, ) self.sensitive_ticket_no_payment_closed_gt.ticket.status = GrievanceTicket.STATUS_CLOSED self.sensitive_ticket_no_payment_closed_gt.ticket.save() @@ -434,7 +433,7 @@ def create_sensitive_tickets(self) -> None: self.sensitive_ticket_no_payment_not_closed_gt = SensitiveGrievanceTicketWithoutExtrasFactory( household=None, individual=self.individual_sensitive_ticket_no_payment_not_closed_gt, - payment_obj=None, + payment=None, ) grievance_ticket = self.sensitive_ticket_no_payment_not_closed_gt.ticket grievance_ticket.status = GrievanceTicket.STATUS_IN_PROGRESS @@ -453,7 +452,7 @@ def create_sensitive_tickets(self) -> None: [self.program2, self.program3], ) target_population2 = TargetPopulationFactory(program=self.program2) - payment_record = PaymentRecordFactory( + payment = PaymentFactory( target_population=target_population2, household=self.household_sensitive_ticket_with_payment_record, currency="PLN", @@ -461,7 +460,7 @@ def create_sensitive_tickets(self) -> None: self.sensitive_ticket_with_payment_record = SensitiveGrievanceTicketWithoutExtrasFactory( household=self.household_sensitive_ticket_with_payment_record, individual=self.individual_sensitive_ticket_with_payment_record, - payment_obj=payment_record, + payment=payment, ) # TicketSensitiveDetails with no payment, GT not Closed, HH in pr1, pr2, pr3, IND in pr2, pr3 @@ -474,7 +473,7 @@ def create_sensitive_tickets(self) -> None: self.sensitive_ticket_no_payment_not_closed_3hh_2ind = SensitiveGrievanceTicketWithoutExtrasFactory( household=self.household_sensitive_ticket_no_payment_not_closed_3hh_2ind, individual=self.individual_sensitive_ticket_no_payment_not_closed_3hh_2ind, - payment_obj=None, + payment=None, ) grievance_ticket = self.sensitive_ticket_no_payment_not_closed_3hh_2ind.ticket grievance_ticket.status = GrievanceTicket.STATUS_IN_PROGRESS @@ -492,12 +491,12 @@ def create_payment_verification_tickets(self) -> None: [self.program1] ) target_population1 = TargetPopulationFactory(program=self.program1) - payment_record = PaymentRecordFactory( + payment = PaymentFactory( target_population=target_population1, household=self.household_payment_verification_ticket_with_payment_record, ) payment_verification1 = PaymentVerificationFactory( - payment_obj=payment_record, + payment=payment, payment_verification_plan=payment_verification_plan, ) self.payment_verification_ticket_with_payment_record = TicketPaymentVerificationDetailsFactory( @@ -512,7 +511,7 @@ def create_payment_verification_tickets(self) -> None: payment_plan = PaymentPlanFactory(target_population=target_population2) payment = PaymentFactory(parent=payment_plan) payment_verification2 = PaymentVerificationFactory( - payment_obj=payment, + paymenttest_export_xlsx_verification_mutation=payment, ) self.payment_verification_ticket_with_payment = TicketPaymentVerificationDetailsFactory( payment_verification=payment_verification2,