diff --git a/src/hct_mis_api/apps/household/models.py b/src/hct_mis_api/apps/household/models.py index 1802857333..ca48ab5733 100644 --- a/src/hct_mis_api/apps/household/models.py +++ b/src/hct_mis_api/apps/household/models.py @@ -699,6 +699,16 @@ class Meta: def __str__(self) -> str: return f"{self.label}" + @classmethod + def get_all_doc_types_choices(cls) -> List[Tuple[str, str]]: + """return list of Document Types choices""" + return [(obj.key, obj.label) for obj in cls.objects.all()] + + @classmethod + def get_all_doc_types(cls) -> List[str]: + """return list of Document Types keys""" + return list(cls.objects.all().only("key").values_list("key", flat=True)) + class Document(AbstractSyncable, SoftDeletableRepresentationMergeStatusModel, TimeStampedUUIDModel): STATUS_PENDING = "PENDING" diff --git a/src/hct_mis_api/apps/payment/admin.py b/src/hct_mis_api/apps/payment/admin.py index efd4bfc814..ab82df38ba 100644 --- a/src/hct_mis_api/apps/payment/admin.py +++ b/src/hct_mis_api/apps/payment/admin.py @@ -279,7 +279,7 @@ class FinancialServiceProviderXlsxTemplateAdmin(HOPEModelAdminBase): ) list_filter = (("created_by", AutoCompleteFilter),) search_fields = ("name",) - fields = ("name", "columns", "core_fields", "flex_fields") + fields = ("name", "columns", "core_fields", "flex_fields", "document_types") def total_selected_columns(self, obj: Any) -> str: return f"{len(obj.columns)} of {len(FinancialServiceProviderXlsxTemplate.COLUMNS_CHOICES)}" diff --git a/src/hct_mis_api/apps/payment/migrations/0007_migration.py b/src/hct_mis_api/apps/payment/migrations/0007_migration.py new file mode 100644 index 0000000000..4bd14071ad --- /dev/null +++ b/src/hct_mis_api/apps/payment/migrations/0007_migration.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.25 on 2024-12-06 13:32 + +from django.db import migrations, models +import hct_mis_api.apps.payment.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('payment', '0006_migration'), + ] + + operations = [ + migrations.AddField( + model_name='financialserviceproviderxlsxtemplate', + name='document_types', + field=hct_mis_api.apps.payment.fields.DynamicChoiceArrayField(base_field=models.CharField(blank=True, max_length=255), blank=True, default=list, size=None), + ), + ] diff --git a/src/hct_mis_api/apps/payment/models/payment.py b/src/hct_mis_api/apps/payment/models/payment.py index fee7acd602..1b6e4874ae 100644 --- a/src/hct_mis_api/apps/payment/models/payment.py +++ b/src/hct_mis_api/apps/payment/models/payment.py @@ -51,7 +51,7 @@ from hct_mis_api.apps.core.mixins import LimitBusinessAreaModelMixin from hct_mis_api.apps.core.models import FileTemp, FlexibleAttribute from hct_mis_api.apps.geo.models import Area, Country -from hct_mis_api.apps.household.models import FEMALE, MALE, Individual +from hct_mis_api.apps.household.models import FEMALE, MALE, DocumentType, Individual from hct_mis_api.apps.payment.fields import DynamicChoiceArrayField from hct_mis_api.apps.payment.managers import PaymentManager from hct_mis_api.apps.payment.validators import payment_token_and_order_number_validator @@ -974,19 +974,23 @@ class FinancialServiceProviderXlsxTemplate(TimeStampedUUIDModel): verbose_name=_("Columns"), help_text=_("Select the columns to include in the report"), ) - core_fields = DynamicChoiceArrayField( models.CharField(max_length=255, blank=True), choices_callable=FieldFactory.get_all_core_fields_choices, default=list, blank=True, ) - flex_fields = FlexFieldArrayField( models.CharField(max_length=255, blank=True), default=list, blank=True, ) + document_types = DynamicChoiceArrayField( + models.CharField(max_length=255, blank=True), + choices_callable=DocumentType.get_all_doc_types_choices, + default=list, + blank=True, + ) @staticmethod def get_data_from_payment_snapshot( @@ -1124,11 +1128,12 @@ def get_column_value_from_payment(cls, payment: "Payment", column_name: str) -> ), } additional_columns = { - "registration_token": cls.get_registration_token_doc_number, - "national_id": cls.get_national_id_doc_number, "admin_level_2": cls.get_admin_level_2, "alternate_collector_document_numbers": cls.get_alternate_collector_doc_numbers, } + if column_name in DocumentType.get_all_doc_types(): + return cls.get_document_number_by_doc_type_key(snapshot_data, column_name) + if column_name in additional_columns: method = additional_columns[column_name] return method(snapshot_data) @@ -1148,22 +1153,13 @@ def get_column_value_from_payment(cls, payment: "Payment", column_name: str) -> return getattr(obj, nested_field, None) or "" @staticmethod - def get_registration_token_doc_number(snapshot_data: Dict[str, Any]) -> str: - collector_data = ( - snapshot_data.get("primary_collector", {}) or snapshot_data.get("alternate_collector", {}) or dict() - ) - documents_list = collector_data.get("documents", []) - documents_dict = {doc.get("type"): doc for doc in documents_list} - return documents_dict.get("registration_token", {}).get("document_number", "") - - @staticmethod - def get_national_id_doc_number(snapshot_data: Dict[str, Any]) -> str: + def get_document_number_by_doc_type_key(snapshot_data: Dict[str, Any], document_type_key: str) -> str: collector_data = ( snapshot_data.get("primary_collector", {}) or snapshot_data.get("alternate_collector", {}) or dict() ) documents_list = collector_data.get("documents", []) documents_dict = {doc.get("type"): doc for doc in documents_list} - return documents_dict.get("national_id", {}).get("document_number", "") + return documents_dict.get(document_type_key, {}).get("document_number", "") @staticmethod def get_alternate_collector_doc_numbers(snapshot_data: Dict[str, Any]) -> str: 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 be749f0086..bba83cb8f5 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 @@ -123,6 +123,8 @@ def prepare_headers(self, fsp_xlsx_template: "FinancialServiceProviderXlsxTempla column_list.append(core_field) for flex_field in fsp_xlsx_template.flex_fields: column_list.append(flex_field) + for document_field in fsp_xlsx_template.document_types: + column_list.append(document_field) column_list = self._remove_column_for_people(column_list) column_list = self._remove_core_fields_for_people(column_list) @@ -144,6 +146,7 @@ def add_rows( def get_payment_row(self, payment: Payment, fsp_xlsx_template: "FinancialServiceProviderXlsxTemplate") -> List[str]: fsp_template_columns = self._remove_column_for_people(fsp_xlsx_template.columns) fsp_template_core_fields = self._remove_core_fields_for_people(fsp_xlsx_template.core_fields) + fsp_template_document_fields = fsp_xlsx_template.document_types if self.payment_generate_token_and_order_numbers: payment = generate_token_and_order_numbers(payment) @@ -165,6 +168,13 @@ def get_payment_row(self, payment: Payment, fsp_xlsx_template: "FinancialService self._get_flex_field_by_name(column_name, payment) for column_name in fsp_xlsx_template.flex_fields ] payment_row.extend(flex_field_row) + # get document number by document type key + documents_row = [ + FinancialServiceProviderXlsxTemplate.get_column_value_from_payment(payment, doc_type_key) + for doc_type_key in fsp_template_document_fields + ] + payment_row.extend(documents_row) + return list(map(self.right_format_for_xlsx, payment_row)) def _get_flex_field_by_name(self, name: str, payment: Payment) -> str: diff --git a/src/hct_mis_api/migrations_script/main.py b/src/hct_mis_api/migrations_script/main.py index 31b6ff89b1..f6968d622e 100644 --- a/src/hct_mis_api/migrations_script/main.py +++ b/src/hct_mis_api/migrations_script/main.py @@ -55,6 +55,7 @@ def apply_migrations(): ("payment", "0004_migration"), ("payment", "0005_migration"), ("payment", "0006_migration"), + ("payment", "0007_migration"), ("aurora", "0003_migration"), ] fake_migrations(excluded_migrations) 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 c5ad868861..81ee3acc62 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 @@ -2,9 +2,9 @@ from parameterized import parameterized +from hct_mis_api.apps.account.fixtures import UserFactory from hct_mis_api.apps.core.base_test_case import APITestCase 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 ( DocumentFactory, DocumentTypeFactory, @@ -26,9 +26,9 @@ class FinancialServiceProviderXlsxTemplateTest(APITestCase): @classmethod def setUpTestData(cls) -> None: super().setUpTestData() - create_afghanistan() - cls.business_area = BusinessArea.objects.get(slug="afghanistan") + cls.business_area = create_afghanistan() cls.program = ProgramFactory(business_area=cls.business_area) + cls.user = UserFactory() def test_get_column_value_registration_token_empty(self) -> None: household, individuals = create_household(household_args={"size": 1, "business_area": self.business_area}) @@ -37,7 +37,9 @@ def test_get_column_value_registration_token_empty(self) -> None: program_cycle=self.program.cycles.first(), status=PaymentPlan.Status.ACCEPTED, business_area=self.business_area, + created_by=self.user, ) + DocumentTypeFactory(key="registration_token") payment = PaymentFactory(parent=payment_plan, household=household, collector=individual, currency="PLN") create_payment_plan_snapshot_data(payment_plan)