diff --git a/backend/.coveragerc b/backend/.coveragerc index 4d67696f1d..d98484e597 100644 --- a/backend/.coveragerc +++ b/backend/.coveragerc @@ -1,7 +1,7 @@ [run] branch = True source = hct_mis_api -concurrency=multiprocessing +concurrency=multiprocessing,thread omit = */selenium_tests/** diff --git a/backend/hct_mis_api/apps/core/attributes_qet_queries.py b/backend/hct_mis_api/apps/core/attributes_qet_queries.py index 31d1b4b4ae..08ef733ce3 100644 --- a/backend/hct_mis_api/apps/core/attributes_qet_queries.py +++ b/backend/hct_mis_api/apps/core/attributes_qet_queries.py @@ -23,17 +23,20 @@ logger = logging.getLogger(__name__) -def age_to_birth_date_range_query(field_name: str, age_min: Optional[int], age_max: Optional[int]) -> Q: +def age_to_birth_date_range_query( + field_name: str, age_min: Optional[int], age_max: Optional[int], is_social_worker_query: bool = False +) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" query_dict = {} current_date = dt.date.today() if age_min is not None: - query_dict[f"{field_name}__lte"] = current_date - relativedelta(years=+age_min) + query_dict[f"{lookup_prefix}{field_name}__lte"] = current_date - relativedelta(years=+age_min) if age_max is not None: - query_dict[f"{field_name}__gt"] = current_date - relativedelta(years=+age_max + 1) + query_dict[f"{lookup_prefix}{field_name}__gt"] = current_date - relativedelta(years=+age_max + 1) return Q(**query_dict) -def age_to_birth_date_query(comparison_method: str, args: Any) -> Q: +def age_to_birth_date_query(comparison_method: str, args: Any, is_social_worker_query: bool = False) -> Q: field_name = "birth_date" comparison_method_args_count = { "RANGE": 2, @@ -51,132 +54,196 @@ def age_to_birth_date_query(comparison_method: str, args: Any) -> Q: logger.error(f"Age {comparison_method} filter query expect {args_count} arguments") raise ValidationError(f"Age {comparison_method} filter query expect {args_count} arguments") if comparison_method == "RANGE": - return age_to_birth_date_range_query(field_name, *args) + return age_to_birth_date_range_query(field_name, *args, is_social_worker_query=is_social_worker_query) if comparison_method == "NOT_IN_RANGE": - return ~(age_to_birth_date_range_query(field_name, *args)) + return ~(age_to_birth_date_range_query(field_name, *args, is_social_worker_query=is_social_worker_query)) if comparison_method == "EQUALS": - return age_to_birth_date_range_query(field_name, args[0], args[0]) + return age_to_birth_date_range_query( + field_name, args[0], args[0], is_social_worker_query=is_social_worker_query + ) if comparison_method == "NOT_EQUALS": - return ~(age_to_birth_date_range_query(field_name, args[0], args[0])) + return ~( + age_to_birth_date_range_query(field_name, args[0], args[0], is_social_worker_query=is_social_worker_query) + ) if comparison_method == "GREATER_THAN": - return age_to_birth_date_range_query(field_name, args[0], None) + return age_to_birth_date_range_query(field_name, args[0], None, is_social_worker_query=is_social_worker_query) if comparison_method == "LESS_THAN": - return age_to_birth_date_range_query(field_name, None, args[0]) - logger.error(f"Age filter query don't supports {comparison_method} type") - raise ValidationError(f"Age filter query don't supports {comparison_method} type") + return age_to_birth_date_range_query(field_name, None, args[0], is_social_worker_query=is_social_worker_query) + logger.error(f"Age filter query don't supports {comparison_method} type") # pragma: no cover + raise ValidationError(f"Age filter query don't supports {comparison_method} type") # pragma: no cover -def get_birth_certificate_document_number_query(_: Any, args: Any) -> Q: - return get_documents_number_query(IDENTIFICATION_TYPE_BIRTH_CERTIFICATE, args[0]) +def get_birth_certificate_document_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_number_query( + IDENTIFICATION_TYPE_BIRTH_CERTIFICATE, args[0], is_social_worker_query=is_social_worker_query + ) -def get_tax_id_document_number_query(_: Any, args: Any) -> Q: - return get_documents_number_query(IDENTIFICATION_TYPE_TAX_ID, args[0]) +def get_tax_id_document_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_number_query( + IDENTIFICATION_TYPE_TAX_ID, args[0], is_social_worker_query=is_social_worker_query + ) -def get_drivers_license_document_number_query(_: Any, args: Any) -> Q: - return get_documents_number_query(IDENTIFICATION_TYPE_DRIVERS_LICENSE, args[0]) +def get_drivers_license_document_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_number_query( + IDENTIFICATION_TYPE_DRIVERS_LICENSE, args[0], is_social_worker_query=is_social_worker_query + ) -def get_national_id_document_number_query(_: Any, args: Any) -> Q: - return get_documents_number_query(IDENTIFICATION_TYPE_NATIONAL_ID, args[0]) +def get_national_id_document_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_number_query( + IDENTIFICATION_TYPE_NATIONAL_ID, args[0], is_social_worker_query=is_social_worker_query + ) -def get_national_passport_document_number_query(_: Any, args: Any) -> Q: - return get_documents_number_query(IDENTIFICATION_TYPE_NATIONAL_PASSPORT, args[0]) +def get_national_passport_document_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_number_query( + IDENTIFICATION_TYPE_NATIONAL_PASSPORT, args[0], is_social_worker_query=is_social_worker_query + ) -def get_electoral_card_document_number_query(_: Any, args: Any) -> Q: - return get_documents_number_query(IDENTIFICATION_TYPE_ELECTORAL_CARD, args[0]) +def get_electoral_card_document_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_number_query( + IDENTIFICATION_TYPE_ELECTORAL_CARD, args[0], is_social_worker_query=is_social_worker_query + ) -def get_other_document_number_query(_: Any, args: Any) -> Q: - return get_documents_number_query(IDENTIFICATION_TYPE_OTHER, args[0]) +def get_other_document_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_number_query(IDENTIFICATION_TYPE_OTHER, args[0], is_social_worker_query=is_social_worker_query) -def get_documents_number_query(document_type: str, number: str) -> Q: - return Q(documents__type__key=document_type.lower(), documents__document_number=number) +def get_documents_number_query(document_type: str, number: str, is_social_worker_query: bool = False) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" + return Q( + **{ + f"{lookup_prefix}documents__type__key": document_type.lower(), + f"{lookup_prefix}documents__document_number": number, + } + ) -def get_birth_certificate_issuer_query(_: Any, args: Any) -> Q: - return get_documents_issuer_query(IDENTIFICATION_TYPE_BIRTH_CERTIFICATE, args[0]) +def get_birth_certificate_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_issuer_query( + IDENTIFICATION_TYPE_BIRTH_CERTIFICATE, args[0], is_social_worker_query=is_social_worker_query + ) -def get_tax_id_issuer_query(_: Any, args: Any) -> Q: - return get_documents_issuer_query(IDENTIFICATION_TYPE_TAX_ID, args[0]) +def get_tax_id_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_issuer_query( + IDENTIFICATION_TYPE_TAX_ID, args[0], is_social_worker_query=is_social_worker_query + ) -def get_drivers_licensee_issuer_query(_: Any, args: Any) -> Q: - return get_documents_issuer_query(IDENTIFICATION_TYPE_DRIVERS_LICENSE, args[0]) +def get_drivers_licensee_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_issuer_query( + IDENTIFICATION_TYPE_DRIVERS_LICENSE, args[0], is_social_worker_query=is_social_worker_query + ) -def get_national_id_issuer_query(_: Any, args: Any) -> Q: - return get_documents_issuer_query(IDENTIFICATION_TYPE_NATIONAL_ID, args[0]) +def get_national_id_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_issuer_query( + IDENTIFICATION_TYPE_NATIONAL_ID, args[0], is_social_worker_query=is_social_worker_query + ) -def get_national_passport_issuer_query(_: Any, args: Any) -> Q: - return get_documents_issuer_query(IDENTIFICATION_TYPE_NATIONAL_PASSPORT, args[0]) +def get_national_passport_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_issuer_query( + IDENTIFICATION_TYPE_NATIONAL_PASSPORT, args[0], is_social_worker_query=is_social_worker_query + ) -def get_electoral_card_issuer_query(_: Any, args: Any) -> Q: - return get_documents_issuer_query(IDENTIFICATION_TYPE_ELECTORAL_CARD, args[0]) +def get_electoral_card_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_issuer_query( + IDENTIFICATION_TYPE_ELECTORAL_CARD, args[0], is_social_worker_query=is_social_worker_query + ) -def get_other_issuer_query(_: Any, args: Any) -> Q: - return get_documents_issuer_query(IDENTIFICATION_TYPE_OTHER, args[0]) +def get_other_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_issuer_query(IDENTIFICATION_TYPE_OTHER, args[0], is_social_worker_query=is_social_worker_query) -def get_documents_issuer_query(document_type: str, country_alpha3: str) -> Q: - return Q(documents__type__type=document_type, documents__type__country__iso_code3=country_alpha3) +def get_documents_issuer_query(document_type: str, country_alpha3: str, is_social_worker_query: bool = False) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" + return Q( + **{ + f"{lookup_prefix}documents__type__type": document_type, + f"{lookup_prefix}documents__type__country__iso_code3": country_alpha3, + } + ) -def get_role_query(_: Any, args: Any) -> Q: - return Q(households_and_roles__role=args[0]) +def get_role_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" + return Q(**{f"{lookup_prefix}households_and_roles__role": args[0]}) -def get_scope_id_number_query(_: Any, args: Any) -> Q: - return Q(identities__partner__name=WFP, identities__number=args[0]) +def get_scope_id_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" + return Q(**{f"{lookup_prefix}identities__partner__name": WFP, f"{lookup_prefix}identities__number": args[0]}) -def get_scope_id_issuer_query(_: Any, args: Any) -> Q: - return Q(identities__partner__name=WFP, identities__country__iso_code3=args[0]) +def get_scope_id_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" + return Q( + **{f"{lookup_prefix}identities__partner__name": WFP, f"{lookup_prefix}identities__country__iso_code3": args[0]} + ) -def get_unhcr_id_number_query(_: Any, args: Any) -> Q: - return Q(identities__partner__name=UNHCR, identities__number=args[0]) +def get_unhcr_id_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" + return Q(**{f"{lookup_prefix}identities__partner__name": UNHCR, f"{lookup_prefix}identities__number": args[0]}) -def get_unhcr_id_issuer_query(_: Any, args: Any) -> Q: - return Q(identities__partner__name=UNHCR, identities__country__iso_code3=args[0]) +def get_unhcr_id_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" + return Q( + **{ + f"{lookup_prefix}identities__partner__name": UNHCR, + f"{lookup_prefix}identities__country__iso_code3": args[0], + } + ) -def get_receiver_poi_number_query(_: Any, args: Any) -> Q: - return get_documents_number_query("receiver_poi", args[0]) +def get_receiver_poi_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_number_query("receiver_poi", args[0], is_social_worker_query=is_social_worker_query) -def get_receiver_poi_issuer_query(_: Any, args: Any) -> Q: - return get_documents_issuer_query("receiver_poi", args[0]) +def get_receiver_poi_issuer_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: + return get_documents_issuer_query("receiver_poi", args[0], is_social_worker_query=is_social_worker_query) -def get_has_phone_number_query(_: Any, args: Any) -> Q: +def get_has_phone_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: has_phone_no = args[0] in [True, "True"] - return ~Q(phone_no="") if has_phone_no else Q(phone_no="") + lookup_prefix = "individuals__" if is_social_worker_query else "" + return ~Q(**{f"{lookup_prefix}phone_no": ""}) if has_phone_no else Q(**{f"{lookup_prefix}phone_no": ""}) -def get_has_bank_account_number_query(_: Any, args: Any) -> Q: +def get_has_bank_account_number_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: has_bank_account_number = args[0] in [True, "True"] + lookup_prefix = "individuals__" if is_social_worker_query else "" if has_bank_account_number: # Individual can have related object bank_account, but empty number - return Q(bank_account_info__isnull=False) & ~Q(bank_account_info__bank_account_number="") - return Q(bank_account_info__isnull=True) | Q(bank_account_info__bank_account_number="") + return Q(**{f"{lookup_prefix}bank_account_info__isnull": False}) & ~Q( + **{f"{lookup_prefix}bank_account_info__bank_account_number": ""} + ) + return Q(**{f"{lookup_prefix}bank_account_info__isnull": True}) | Q( + **{f"{lookup_prefix}bank_account_info__bank_account_number": ""} + ) -def get_has_tax_id_query(_: Any, args: Any) -> Q: +def get_has_tax_id_query(_: Any, args: Any, is_social_worker_query: bool = False) -> Q: has_tax_id = args[0] in [True, "True"] - return Q(documents__type__key__iexact="TAX_ID") if has_tax_id else ~Q(documents__type__key__iexact="TAX_ID") + lookup_prefix = "individuals__" if is_social_worker_query else "" + return ( + Q(**{f"{lookup_prefix}documents__type__key__iexact": "TAX_ID"}) + if has_tax_id + else ~Q(**{f"{lookup_prefix}documents__type__key__iexact": "TAX_ID"}) + ) -def country_generic_query(comparison_method: str, args: Any, lookup: Any) -> Q: - query = Q(**{lookup: Countries.get_country_value(args[0])}) +def country_generic_query(comparison_method: str, args: Any, lookup: Any, is_social_worker_query: bool = False) -> Q: + lookup_prefix = "individuals__" if is_social_worker_query else "" + query = Q(**{lookup_prefix + lookup: Countries.get_country_value(args[0])}) if comparison_method == "EQUALS": return query elif comparison_method == "NOT_EQUALS": @@ -185,15 +252,17 @@ def country_generic_query(comparison_method: str, args: Any, lookup: Any) -> Q: raise ValidationError(f"Country filter query does not support {comparison_method} type") -def country_query(comparison_method: str, args: Any) -> Q: - return country_generic_query(comparison_method, args, "country") +def country_query(comparison_method: str, args: Any, is_social_worker_query: bool = False) -> Q: + return country_generic_query(comparison_method, args, "country", is_social_worker_query=is_social_worker_query) -def country_origin_query(comparison_method: str, args: Any) -> Q: - return country_generic_query(comparison_method, args, "country_origin") +def country_origin_query(comparison_method: str, args: Any, is_social_worker_query: bool = False) -> Q: + return country_generic_query( + comparison_method, args, "country_origin", is_social_worker_query=is_social_worker_query + ) -def registration_data_import_query(comparison_method: str, args: Any) -> Q: +def registration_data_import_query(comparison_method: str, args: Any, is_social_worker_query: bool = False) -> Q: from django.db.models import Q return Q(registration_data_import__pk__in=args) diff --git a/backend/hct_mis_api/apps/core/field_attributes/core_fields_attributes.py b/backend/hct_mis_api/apps/core/field_attributes/core_fields_attributes.py index 0083f07b55..a962eea72b 100644 --- a/backend/hct_mis_api/apps/core/field_attributes/core_fields_attributes.py +++ b/backend/hct_mis_api/apps/core/field_attributes/core_fields_attributes.py @@ -1837,7 +1837,7 @@ def __init__( super().__init__(*args, **kwargs) self.scopes: Iterable = scopes or set() if fields: - self.extend(fields) + self.extend(copy.deepcopy(fields)) self.all_fields = copy.deepcopy(CORE_FIELDS_ATTRIBUTES) def extend(self, __iterable: Iterable[dict]) -> None: @@ -1865,11 +1865,22 @@ def _fill_label_template(self, field: dict, language: str = "English(EN)") -> Op def from_scopes(cls, scopes: list[Scope]) -> "FieldFactory": factory = cls() all_fields = copy.deepcopy(factory.all_fields) + factory.scopes.update(scopes) factory.extend(filter(lambda field: any(True for scope in scopes if scope in field["scope"]), all_fields)) if Scope.XLSX_PEOPLE in scopes: for field_attr in factory: field_attr["xlsx_field"] = "pp_" + field_attr["xlsx_field"].replace("_h_c", "_i_c") + return factory + + @classmethod + def from_only_scopes(cls, scopes: list[Scope]) -> "FieldFactory": + factory = cls() + all_fields = copy.deepcopy(factory.all_fields) factory.scopes.update(scopes) + factory.extend(filter(lambda field: all(scope in field["scope"] for scope in scopes), all_fields)) + if Scope.XLSX_PEOPLE in scopes: + for field_attr in factory: + field_attr["xlsx_field"] = "pp_" + field_attr["xlsx_field"].replace("_h_c", "_i_c") return factory @classmethod diff --git a/backend/hct_mis_api/apps/core/fixtures/data.json b/backend/hct_mis_api/apps/core/fixtures/data.json index 34ad4dd8fa..955bf89f87 100644 --- a/backend/hct_mis_api/apps/core/fixtures/data.json +++ b/backend/hct_mis_api/apps/core/fixtures/data.json @@ -6681,8 +6681,8 @@ "description": "Partial individuals collected (Social Worker)", "type": "SOCIAL", "active": true, - "individual_filters_available": false, - "household_filters_available": true, + "individual_filters_available": true, + "household_filters_available": false, "compatible_types": [2, 3], "limit_to": ["c259b1a0-ae3a-494e-b343-f7c8eb060c68", "3e269a73-123b-43e1-86af-ced1b30d8e80"] } diff --git a/backend/hct_mis_api/apps/core/schema.py b/backend/hct_mis_api/apps/core/schema.py index 19818984b2..4f16a34435 100644 --- a/backend/hct_mis_api/apps/core/schema.py +++ b/backend/hct_mis_api/apps/core/schema.py @@ -39,6 +39,7 @@ FlexibleAttributeGroup, ) from hct_mis_api.apps.core.utils import decode_id_string +from hct_mis_api.apps.program.models import Program if TYPE_CHECKING: from django.db.models.query import QuerySet @@ -268,9 +269,14 @@ def get_fields_attr_generators( if flex_field is not False: yield from FlexibleAttribute.objects.order_by("created_at") if flex_field is not True: - yield from FieldFactory.from_scope(Scope.TARGETING).filtered_by_types(FILTERABLE_TYPES).apply_business_area( - business_area_slug=business_area_slug, program_id=program_id - ) + if program_id and Program.objects.get(id=program_id).is_social_worker_program: + yield from FieldFactory.from_only_scopes([Scope.XLSX_PEOPLE, Scope.TARGETING]).filtered_by_types( + FILTERABLE_TYPES + ).apply_business_area(business_area_slug=business_area_slug, program_id=program_id) + else: + yield from FieldFactory.from_scope(Scope.TARGETING).filtered_by_types(FILTERABLE_TYPES).apply_business_area( + business_area_slug=business_area_slug, program_id=program_id + ) def resolve_asset(business_area_slug: str, uid: str) -> Dict: diff --git a/backend/hct_mis_api/apps/core/tests/test_attributes_get_queries.py b/backend/hct_mis_api/apps/core/tests/test_attributes_get_queries.py new file mode 100644 index 0000000000..61f6bd1eae --- /dev/null +++ b/backend/hct_mis_api/apps/core/tests/test_attributes_get_queries.py @@ -0,0 +1,334 @@ +import datetime as dt + +from django.core.exceptions import ValidationError +from django.db.models import Q + +from dateutil.relativedelta import relativedelta + +from hct_mis_api.apps.core.attributes_qet_queries import ( + age_to_birth_date_query, + age_to_birth_date_range_query, + country_origin_query, + country_query, + get_birth_certificate_document_number_query, + get_birth_certificate_issuer_query, + get_documents_issuer_query, + get_drivers_license_document_number_query, + get_drivers_licensee_issuer_query, + get_electoral_card_document_number_query, + get_electoral_card_issuer_query, + get_has_bank_account_number_query, + get_has_phone_number_query, + get_has_tax_id_query, + get_national_id_document_number_query, + get_national_id_issuer_query, + get_national_passport_document_number_query, + get_national_passport_issuer_query, + get_other_document_number_query, + get_other_issuer_query, + get_receiver_poi_issuer_query, + get_receiver_poi_number_query, + get_role_query, + get_scope_id_issuer_query, + get_scope_id_number_query, + get_tax_id_document_number_query, + get_tax_id_issuer_query, + get_unhcr_id_issuer_query, + get_unhcr_id_number_query, + registration_data_import_query, +) +from hct_mis_api.apps.core.base_test_case import APITestCase +from hct_mis_api.apps.core.countries import Countries +from hct_mis_api.apps.household.models import UNHCR, WFP + + +class TestAttributesGetQueries(APITestCase): + def setUp(self) -> None: + self.today = dt.date.today() + self.social_worker_prefix = "individuals__" + super().setUp() + + def test_age_to_birth_date_range_query_min_only(self) -> None: + q = age_to_birth_date_range_query("birth_date", 30, None) + expected_date = self.today - relativedelta(years=30) + self.assertEqual(q, Q(birth_date__lte=expected_date)) + + def test_age_to_birth_date_range_query_max_only(self) -> None: + q = age_to_birth_date_range_query("birth_date", None, 20) + expected_date = self.today - relativedelta(years=21) + self.assertEqual(q, Q(birth_date__gt=expected_date)) + + def test_age_to_birth_date_range_query_min_and_max(self) -> None: + q = age_to_birth_date_range_query("birth_date", 25, 35) + expected_min_date = self.today - relativedelta(years=25) + expected_max_date = self.today - relativedelta(years=36) + self.assertEqual(q, Q(birth_date__lte=expected_min_date, birth_date__gt=expected_max_date)) + + def test_age_to_birth_date_query_equals(self) -> None: + q = age_to_birth_date_query("EQUALS", [30]) + expected_date = self.today - relativedelta(years=30) + print("*" * 399) + print(q) + print(Q(birth_date__lte=expected_date, birth_date__gt=expected_date - relativedelta(years=1))) + self.assertEqual(q, Q(birth_date__lte=expected_date, birth_date__gt=expected_date - relativedelta(years=1))) + + def test_age_to_birth_date_query_not_equals(self) -> None: + q = age_to_birth_date_query("NOT_EQUALS", [30]) + expected_date = self.today - relativedelta(years=30) + self.assertEqual(q, ~(Q(birth_date__lte=expected_date, birth_date__gt=expected_date - relativedelta(years=1)))) + + def test_age_to_birth_date_query_range(self) -> None: + q = age_to_birth_date_query("RANGE", [20, 30]) + expected_min_date = self.today - relativedelta(years=20) + expected_max_date = self.today - relativedelta(years=31) + self.assertEqual(q, Q(birth_date__lte=expected_min_date, birth_date__gt=expected_max_date)) + + def test_age_to_birth_date_query_not_in_range(self) -> None: + q = age_to_birth_date_query("NOT_IN_RANGE", [20, 30]) + expected_min_date = self.today - relativedelta(years=20) + expected_max_date = self.today - relativedelta(years=31) + self.assertEqual(q, ~(Q(birth_date__lte=expected_min_date, birth_date__gt=expected_max_date))) + + def test_age_to_birth_date_query_greater_than(self) -> None: + q = age_to_birth_date_query("GREATER_THAN", [25]) + expected_min_date = self.today - relativedelta(years=25) + self.assertEqual(q, Q(birth_date__lte=expected_min_date)) + + def test_age_to_birth_date_query_less_than(self) -> None: + q = age_to_birth_date_query("LESS_THAN", [25]) + expected_max_date = self.today - relativedelta(years=26) + self.assertEqual(q, Q(birth_date__gt=expected_max_date)) + + def test_invalid_comparison_method(self) -> None: + with self.assertRaises(ValidationError): + age_to_birth_date_query("INVALID_METHOD", [25]) + + def test_incorrect_argument_count(self) -> None: + with self.assertRaises(ValidationError): + age_to_birth_date_query("EQUALS", []) + + def test_country_query_equals(self) -> None: + q = country_query("EQUALS", ["USA"]) + self.assertEqual(q, Q(country=Countries.get_country_value("USA"))) + + def test_country_query_not_equals(self) -> None: + q = country_query("NOT_EQUALS", ["USA"]) + self.assertEqual(q, ~Q(country=Countries.get_country_value("USA"))) + + def test_registration_data_import_query(self) -> None: + q = registration_data_import_query("EQUALS", [1, 2, 3]) + self.assertEqual(q, Q(registration_data_import__pk__in=[1, 2, 3])) + + def test_invalid_country_comparison_method(self) -> None: + with self.assertRaises(ValidationError): + country_query("INVALID_METHOD", ["USA"]) + + def test_get_has_phone_number_query_true(self) -> None: + q = get_has_phone_number_query(None, [True]) + self.assertEqual(q, ~Q(phone_no="")) + + def test_get_has_phone_number_query_false(self) -> None: + q = get_has_phone_number_query(None, [False]) + self.assertEqual(q, Q(phone_no="")) + + def test_get_birth_certificate_document_number_query(self) -> None: + q = get_birth_certificate_document_number_query(None, ["1234"]) + self.assertEqual(q, Q(documents__type__key="birth_certificate", documents__document_number="1234")) + + def test_get_tax_id_document_number_query(self) -> None: + q = get_tax_id_document_number_query(None, ["5678"]) + self.assertEqual(q, Q(documents__type__key="tax_id", documents__document_number="5678")) + + def test_get_drivers_license_document_number_query(self) -> None: + q = get_drivers_license_document_number_query(None, ["ABCD"]) + self.assertEqual(q, Q(documents__type__key="drivers_license", documents__document_number="ABCD")) + + def test_get_national_id_document_number_query(self) -> None: + q = get_national_id_document_number_query(None, ["EFGH"]) + self.assertEqual(q, Q(documents__type__key="national_id", documents__document_number="EFGH")) + + def test_get_national_passport_document_number_query(self) -> None: + q = get_national_passport_document_number_query(None, ["IJKL"]) + self.assertEqual(q, Q(documents__type__key="national_passport", documents__document_number="IJKL")) + + def test_get_electoral_card_document_number_query(self) -> None: + q = get_electoral_card_document_number_query(None, ["MNOP"]) + self.assertEqual(q, Q(documents__type__key="electoral_card", documents__document_number="MNOP")) + + def test_get_other_document_number_query(self) -> None: + q = get_other_document_number_query(None, ["QRST"]) + self.assertEqual(q, Q(documents__type__key="other", documents__document_number="QRST")) + + def test_get_has_bank_account_number_query_true(self) -> None: + # Test for individuals who have a bank account number + expected_query = Q(bank_account_info__isnull=False) & ~Q(bank_account_info__bank_account_number="") + result = get_has_bank_account_number_query(None, [True]) + self.assertEqual(result, expected_query) + + def test_get_has_bank_account_number_query_false(self) -> None: + # Test for individuals who do not have a bank account number + expected_query = Q(bank_account_info__isnull=True) | Q(bank_account_info__bank_account_number="") + result = get_has_bank_account_number_query(None, [False]) + self.assertEqual(result, expected_query) + + def test_get_has_bank_account_number_query_social_worker_true(self) -> None: + # Test with social worker prefix for individuals who have a bank account number + expected_query = Q(individuals__bank_account_info__isnull=False) & ~Q( + individuals__bank_account_info__bank_account_number="" + ) + result = get_has_bank_account_number_query(None, [True], is_social_worker_query=True) + self.assertEqual(result, expected_query) + + def test_get_has_bank_account_number_query_social_worker_false(self) -> None: + # Test with social worker prefix for individuals who do not have a bank account number + expected_query = Q(individuals__bank_account_info__isnull=True) | Q( + individuals__bank_account_info__bank_account_number="" + ) + result = get_has_bank_account_number_query(None, [False], is_social_worker_query=True) + self.assertEqual(result, expected_query) + + def test_get_has_tax_id_query_true(self) -> None: + # Test for individuals who have a tax ID + expected_query = Q(documents__type__key__iexact="TAX_ID") + result = get_has_tax_id_query(None, [True]) + self.assertEqual(result, expected_query) + + def test_get_has_tax_id_query_false(self) -> None: + # Test for individuals who do not have a tax ID + expected_query = ~Q(documents__type__key__iexact="TAX_ID") + result = get_has_tax_id_query(None, [False]) + self.assertEqual(result, expected_query) + + def test_get_has_tax_id_query_social_worker_true(self) -> None: + # Test with social worker prefix for individuals who have a tax ID + expected_query = Q(individuals__documents__type__key__iexact="TAX_ID") + result = get_has_tax_id_query(None, [True], is_social_worker_query=True) + self.assertEqual(result, expected_query) + + def test_get_has_tax_id_query_social_worker_false(self) -> None: + # Test with social worker prefix for individuals who do not have a tax ID + expected_query = ~Q(individuals__documents__type__key__iexact="TAX_ID") + result = get_has_tax_id_query(None, [False], is_social_worker_query=True) + self.assertEqual(result, expected_query) + + def test_get_role_query(self) -> None: + # Without social worker prefix + expected = Q(households_and_roles__role="manager") + result = get_role_query(None, ["manager"]) + self.assertEqual(result, expected) + + # With social worker prefix + expected = Q(individuals__households_and_roles__role="manager") + result = get_role_query(None, ["manager"], True) + self.assertEqual(result, expected) + + def test_get_scope_id_number_query(self) -> None: + # Without social worker prefix + expected = Q(identities__partner__name=WFP, identities__number="123456") + result = get_scope_id_number_query(None, ["123456"]) + self.assertEqual(result, expected) + + # With social worker prefix + expected = Q(individuals__identities__partner__name=WFP, individuals__identities__number="123456") + result = get_scope_id_number_query(None, ["123456"], True) + self.assertEqual(result, expected) + + def test_get_scope_id_issuer_query(self) -> None: + # Without social worker prefix + expected = Q(identities__partner__name=WFP, identities__country__iso_code3="KEN") + result = get_scope_id_issuer_query(None, ["KEN"]) + self.assertEqual(result, expected) + + # With social worker prefix + expected = Q(individuals__identities__partner__name=WFP, individuals__identities__country__iso_code3="KEN") + result = get_scope_id_issuer_query(None, ["KEN"], True) + self.assertEqual(result, expected) + + def test_get_unhcr_id_number_query(self) -> None: + # Without social worker prefix + expected = Q(identities__partner__name=UNHCR, identities__number="987654") + result = get_unhcr_id_number_query(None, ["987654"]) + self.assertEqual(result, expected) + + # With social worker prefix + expected = Q(individuals__identities__partner__name=UNHCR, individuals__identities__number="987654") + result = get_unhcr_id_number_query(None, ["987654"], True) + self.assertEqual(result, expected) + + def test_get_unhcr_id_issuer_query(self) -> None: + # Without social worker prefix + expected = Q(identities__partner__name=UNHCR, identities__country__iso_code3="UGA") + result = get_unhcr_id_issuer_query(None, ["UGA"]) + self.assertEqual(result, expected) + + expected = Q(individuals__identities__partner__name=UNHCR, individuals__identities__country__iso_code3="UGA") + result = get_unhcr_id_issuer_query(None, ["UGA"], True) + self.assertEqual(result, expected) + + def test_get_national_id_issuer_query(self) -> None: + expected = Q(documents__type__type="NATIONAL_ID", documents__type__country__iso_code3="USA") + result = get_national_id_issuer_query(None, ["USA"]) + self.assertEqual(result, expected) + + def test_get_national_passport_issuer_query(self) -> None: + expected = Q(documents__type__type="NATIONAL_PASSPORT", documents__type__country__iso_code3="GBR") + result = get_national_passport_issuer_query(None, ["GBR"]) + self.assertEqual(result, expected) + + def test_get_electoral_card_issuer_query(self) -> None: + expected = Q(documents__type__type="ELECTORAL_CARD", documents__type__country__iso_code3="IND") + result = get_electoral_card_issuer_query(None, ["IND"]) + self.assertEqual(result, expected) + + def test_get_documents_issuer_query(self) -> None: + expected = Q(documents__type__type="GENERIC_TYPE", documents__type__country__iso_code3="FRA") + result = get_documents_issuer_query("GENERIC_TYPE", "FRA") + self.assertEqual(result, expected) + + def test_get_receiver_poi_number_query(self) -> None: + expected = Q(documents__type__key="receiver_poi", documents__document_number="12345") + result = get_receiver_poi_number_query(None, ["12345"]) + self.assertEqual(result, expected) + + def test_get_receiver_poi_issuer_query(self) -> None: + expected = Q(documents__type__type="receiver_poi", documents__type__country__iso_code3="CAN") + result = get_receiver_poi_issuer_query(None, ["CAN"]) + self.assertEqual(result, expected) + + def test_country_origin_query_equals(self) -> None: + expected = Q(individuals__country_origin="CA") + result = country_origin_query("EQUALS", ["CAN"], is_social_worker_query=True) + self.assertEqual(result, expected) + + def test_country_origin_query_not_equals(self) -> None: + expected = ~Q(individuals__country_origin="CA") + result = country_origin_query("NOT_EQUALS", ["CAN"], is_social_worker_query=True) + self.assertEqual(result, expected) + + def test_invalid_country_origin_comparison(self) -> None: + with self.assertRaises(ValidationError): + country_origin_query("INVALID", ["CAN"], is_social_worker_query=True) + + def test_get_birth_certificate_issuer_query(self) -> None: + country_code = "USA" + result = get_birth_certificate_issuer_query(None, [country_code]) + expected = Q(documents__type__type="BIRTH_CERTIFICATE", documents__type__country__iso_code3=country_code) + self.assertEqual(result, expected) + + def test_get_tax_id_issuer_query(self) -> None: + country_code = "GBR" + result = get_tax_id_issuer_query(None, [country_code]) + expected = Q(documents__type__type="TAX_ID", documents__type__country__iso_code3=country_code) + self.assertEqual(result, expected) + + def test_get_drivers_licensee_issuer_query(self) -> None: + country_code = "CAN" + result = get_drivers_licensee_issuer_query(None, [country_code]) + expected = Q(documents__type__type="DRIVERS_LICENSE", documents__type__country__iso_code3=country_code) + self.assertEqual(result, expected) + + def test_get_other_issuer_query(self) -> None: + country_code = "AUS" + result = get_other_issuer_query(None, [country_code]) + expected = Q(documents__type__type="OTHER", documents__type__country__iso_code3=country_code) + self.assertEqual(result, expected) diff --git a/backend/hct_mis_api/apps/core/tests/test_core_fields.py b/backend/hct_mis_api/apps/core/tests/test_core_fields.py index 998490a239..5c12eac968 100644 --- a/backend/hct_mis_api/apps/core/tests/test_core_fields.py +++ b/backend/hct_mis_api/apps/core/tests/test_core_fields.py @@ -1,10 +1,89 @@ +from unittest.mock import patch + from hct_mis_api.apps.core.base_test_case import APITestCase from hct_mis_api.apps.core.field_attributes.core_fields_attributes import ( CORE_FIELDS_ATTRIBUTES, + FieldFactory, ) +from hct_mis_api.apps.core.field_attributes.fields_types import TYPE_STRING, Scope class TestCoreFields(APITestCase): + + def setUp(self) -> None: + self.scopes = [Scope.GLOBAL, Scope.XLSX_PEOPLE] + super().setUp() + def test_all_fields_have_lookup(self) -> None: for field in CORE_FIELDS_ATTRIBUTES: self.assertTrue(field.get("lookup"), f'{field.get("name")} does not have a lookup') + + @patch( + "hct_mis_api.apps.core.field_attributes.core_fields_attributes.CORE_FIELDS_ATTRIBUTES", + [ + { + "id": "b1f90314-b8b8-4bcb-9265-9d48d1fce5a4", + "type": TYPE_STRING, + "name": "given_name", + "lookup": "given_name", + "required": False, + "label": {"English(EN)": "Given name"}, + "hint": "", + "choices": [], + "associated_with": "individual", + "xlsx_field": "given_name_i_c", + "scope": [Scope.GLOBAL, Scope.TARGETING, Scope.KOBO_IMPORT, Scope.INDIVIDUAL_UPDATE, Scope.XLSX_PEOPLE], + }, + { + "id": "b1f90314-b8b8-4bcb-9265-9d48d1fce524", + "type": TYPE_STRING, + "name": "given_name1", + "lookup": "given_name1", + "required": False, + "label": {"English(EN)": "Given name1"}, + "hint": "", + "choices": [], + "associated_with": "individual", + "xlsx_field": "given_name1_i_c", + "scope": [Scope.GLOBAL, Scope.TARGETING, Scope.KOBO_IMPORT, Scope.INDIVIDUAL_UPDATE], + }, + { + "id": "36ab3421-6e7a-40d1-b816-ea5cbdcc0b6a", + "type": TYPE_STRING, + "name": "full_name", + "lookup": "full_name", + "required": True, + "label": {"English(EN)": "Full name"}, + "hint": "", + "choices": [], + "associated_with": "individual", + "xlsx_field": "full_name_i_c", + "scope": [Scope.GLOBAL, Scope.XLSX_PEOPLE], + }, + ], + ) + def test_xlsx_people_scope_filtering(self) -> None: + factory_result = FieldFactory.from_only_scopes(self.scopes) + self.assertEqual(len(factory_result), 2) + + @patch( + "hct_mis_api.apps.core.field_attributes.core_fields_attributes.CORE_FIELDS_ATTRIBUTES", + [ + { + "id": "b1f90314-b8b8-4bcb-9265-9d48d1fce5a4", + "type": TYPE_STRING, + "name": "given_name", + "lookup": "given_name", + "required": False, + "label": {"English(EN)": "Given name"}, + "hint": "", + "choices": [], + "associated_with": "individual", + "xlsx_field": "given_name_i_c", + "scope": [Scope.GLOBAL, Scope.TARGETING, Scope.KOBO_IMPORT, Scope.INDIVIDUAL_UPDATE, Scope.XLSX_PEOPLE], + } + ], + ) + def test_xlsx_people_scope_modification(self) -> None: + factory_result = FieldFactory.from_only_scopes(self.scopes) + self.assertEqual(factory_result[0]["xlsx_field"], "pp_given_name_i_c") diff --git a/backend/hct_mis_api/apps/household/fixtures.py b/backend/hct_mis_api/apps/household/fixtures.py index 48ef3dee00..dbcfee845f 100644 --- a/backend/hct_mis_api/apps/household/fixtures.py +++ b/backend/hct_mis_api/apps/household/fixtures.py @@ -180,7 +180,7 @@ class Meta: MARITAL_STATUS_CHOICE, getter=lambda c: c[0], ) - phone_no = factory.Sequence(lambda n: f"+48 609 456 {n%1000:03d}") + phone_no = factory.Sequence(lambda n: f"+48 609 456 {n % 1000:03d}") phone_no_valid = True phone_no_alternative = "" phone_no_alternative_valid = True @@ -363,6 +363,13 @@ def create_household_and_individuals( individuals_data = [] if household_data.get("size") is None: household_data["size"] = len(individuals_data) + if "program" not in household_data: + program = ProgramFactory() + else: + program = household_data["program"] + if "registration_data_import" not in household_data: + rdi = RegistrationDataImportFactory(program=program) + household_data["registration_data_import"] = rdi household: Household = HouseholdFactory.build(**household_data) household.program.save() household.household_collection.save() @@ -370,8 +377,16 @@ def create_household_and_individuals( household.registration_data_import.program.save() household.registration_data_import.save() household.program.save() + for individual_data in individuals_data: + if "program" not in individual_data: + individual_data["program"] = program + if "registration_data_import" not in individual_data: + individual_data["registration_data_import"] = household_data["registration_data_import"] individuals: List[Individual] = [ - IndividualFactory(household=household, program=household.program, **individual_data) + IndividualFactory( + household=household, + **individual_data, + ) for individual_data in individuals_data ] household.head_of_household = individuals[0] diff --git a/backend/hct_mis_api/apps/payment/celery_tasks.py b/backend/hct_mis_api/apps/payment/celery_tasks.py index dd1abd6a25..1cca926d6c 100644 --- a/backend/hct_mis_api/apps/payment/celery_tasks.py +++ b/backend/hct_mis_api/apps/payment/celery_tasks.py @@ -21,7 +21,7 @@ ) from hct_mis_api.apps.payment.models import PaymentPlan, PaymentVerificationPlan from hct_mis_api.apps.payment.pdf.payment_plan_export_pdf_service import ( - PaymentPlanPDFExportSevice, + PaymentPlanPDFExportService, ) from hct_mis_api.apps.payment.services.payment_household_snapshot_service import ( create_payment_plan_snapshot_data, @@ -565,7 +565,7 @@ def export_pdf_payment_plan_summary(self: Any, payment_plan_id: str, user_id: st payment_plan.export_pdf_file_summary.delete() payment_plan.export_pdf_file_summary = None - service = PaymentPlanPDFExportSevice(payment_plan) + service = PaymentPlanPDFExportService(payment_plan) pdf, filename = service.generate_pdf_summary() file_pdf_obj = FileTemp( diff --git a/backend/hct_mis_api/apps/payment/pdf/payment_plan_export_pdf_service.py b/backend/hct_mis_api/apps/payment/pdf/payment_plan_export_pdf_service.py index d65a570122..1efcc65134 100644 --- a/backend/hct_mis_api/apps/payment/pdf/payment_plan_export_pdf_service.py +++ b/backend/hct_mis_api/apps/payment/pdf/payment_plan_export_pdf_service.py @@ -16,7 +16,7 @@ logger = logging.getLogger(__name__) -class PaymentPlanPDFExportSevice: +class PaymentPlanPDFExportService: text_template = "payment/pdf_file_generated_email.txt" html_template = "payment/pdf_file_generated_email.html" @@ -24,6 +24,7 @@ def __init__(self, payment_plan: PaymentPlan): self.payment_plan = payment_plan self.download_link: str = "" self.payment_plan_link: str = "" + self.is_social_worker_program = payment_plan.program.is_social_worker_program @staticmethod def get_link(api_url: Optional[str] = None) -> str: @@ -58,7 +59,10 @@ def get_email_context(self, user: "User") -> Dict: def generate_pdf_summary(self) -> Any: self.generate_web_links() - template_name = "payment/payment_plan_summary_pdf_template.html" + if self.is_social_worker_program: + template_name = "payment/people_payment_plan_summary_pdf_template.html" + else: + template_name = "payment/payment_plan_summary_pdf_template.html" filename = f"PaymentPlanSummary-{self.payment_plan.unicef_id}.pdf" delivery_mechanism_per_payment_plan = self.payment_plan.delivery_mechanisms.select_related( "financial_service_provider" diff --git a/backend/hct_mis_api/apps/payment/templates/payment/payment_plan_summary_pdf_template.html b/backend/hct_mis_api/apps/payment/templates/payment/payment_plan_summary_pdf_template.html index 2efc61708d..02153c6b5b 100644 --- a/backend/hct_mis_api/apps/payment/templates/payment/payment_plan_summary_pdf_template.html +++ b/backend/hct_mis_api/apps/payment/templates/payment/payment_plan_summary_pdf_template.html @@ -9,7 +9,7 @@

LETTER OF AUTHORIZATION

- + @@ -96,9 +96,9 @@

PAYMENT PLAN ACCEPTANCE PROCESS

PAYMENT PLAN DETAILSPAYMENT PLAN DETAILS
Start Date
- - - + + + @@ -167,8 +167,8 @@

PAYMENT PLAN ACCEPTANCE PROCESS

-

Link to Payment Plan: {{ payment_plan_link }}

+

Link to Payment Plan: {{ payment_plan_link }}

Generated on {% now "N j, Y" %}

-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/backend/hct_mis_api/apps/payment/templates/payment/people_payment_plan_summary_pdf_template.html b/backend/hct_mis_api/apps/payment/templates/payment/people_payment_plan_summary_pdf_template.html new file mode 100644 index 0000000000..921ad2fce6 --- /dev/null +++ b/backend/hct_mis_api/apps/payment/templates/payment/people_payment_plan_summary_pdf_template.html @@ -0,0 +1,174 @@ +{% extends "export/pdf_base.html" %} + +{% block table %} + +
+

LETTER OF AUTHORIZATION

+
+ +
approvalauthorizationreleaseapprovalauthorizationrelease
Name of Approver
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PAYMENT PLAN DETAILS
Start Date{{ payment_plan.start_date|date:"j N Y" }}Programme Name{{ payment_plan.program_cycle.program.name }}
End Date{{ payment_plan.end_date|date:"j N Y" }}Delivery mechanism{{ delivery_mechanism_per_payment_plan }}
Dispersion Start Date{{ payment_plan.dispersion_start_date|date:"j N Y" }}FSP{{ fsp.name }}
Dispersion End Date{{ payment_plan.dispersion_end_date|date:"j N Y" }}Vision Vendor number{{ fsp.vision_vendor_number }}
Target Population{{ payment_plan.target_population.name }}
SUMMARY
Total number of people covered{{ payment_plan.total_individuals_count }}Total entitlement{{ payment_plan.total_entitled_quantity|default_if_none:"0" }}
Currency{{ payment_plan.currency }}
Total entitlement (USD){{ payment_plan.total_entitled_quantity_usd|default_if_none:"0" }}
+ + + + + + + + + + + + + + + + + + + + + + + +
RECONCILIATION SUMMARY
Total People redeemed{{reconciliation.reconciled|default_if_none:"0"}}Total amount redeemed ({{ payment_plan.currency }}){{reconciliation.reconciled_local|default_if_none:"0"}}Total amount redeemed (USD){{reconciliation.reconciled_usd|default_if_none:"0"}}
Total pending People{{reconciliation.pending|default_if_none:"0"}}Total amount unredeemed ({{ payment_plan.currency }}){{reconciliation.pending_local|default_if_none:"0"}}Total amount unredeemed (USD){{reconciliation.pending_usd|default_if_none:"0"}}
+ +
+

PAYMENT PLAN ACCEPTANCE PROCESS

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
approvalauthorizationrelease
Name of Approver{{ approval.created_by.get_full_name }}Name of authorizer{{ authorization.created_by.get_full_name }}Name of Releaser{{ release.created_by.get_full_name }}
Approval date{{ approval.created_at|date:"j N Y" }}Authorization date{{ authorization.created_at|date:"j N Y" }}Release date{{ release.created_at|date:"j N Y" }}
Comment{{ approval.comment }}Comment{{ authorization.comment }}Comment{{ release.comment }}
SignatureSignatureSignature
+ +
+ + + + + + + +
This part is reserved for FSP Authorized signatories
+ + + + + + + + +
FSP Authorized signatory 1
+ + + + + + + + +
FSP Authorized signatory 2
+ +
+ +

+

+

Link to Payment Plan: {{ payment_plan_link }}

+

+

Generated on {% now "N j, Y" %}

+ +{% endblock %} diff --git a/backend/hct_mis_api/apps/payment/tests/test_payment_plan_pdf_export_service.py b/backend/hct_mis_api/apps/payment/tests/test_payment_plan_pdf_export_service.py new file mode 100644 index 0000000000..f9dc686114 --- /dev/null +++ b/backend/hct_mis_api/apps/payment/tests/test_payment_plan_pdf_export_service.py @@ -0,0 +1,95 @@ +from typing import Any +from unittest.mock import MagicMock, patch + +from django.test import TestCase + +from hct_mis_api.apps.core.fixtures import create_afghanistan +from hct_mis_api.apps.core.models import DataCollectingType +from hct_mis_api.apps.payment.fixtures import ( + ApprovalFactory, + ApprovalProcessFactory, + DeliveryMechanismPerPaymentPlanFactory, + FinancialServiceProviderFactory, + PaymentPlanFactory, +) +from hct_mis_api.apps.payment.models import Approval, GenericPayment +from hct_mis_api.apps.payment.pdf.payment_plan_export_pdf_service import ( + PaymentPlanPDFExportService, +) +from hct_mis_api.apps.program.fixtures import ProgramFactory + + +class TestPaymentPlanPDFExportService(TestCase): + def setUp(self) -> None: + create_afghanistan() + self.payment_plan = PaymentPlanFactory( + program=ProgramFactory(data_collecting_type__type=DataCollectingType.Type.STANDARD) + ) + self.payment_plan.unicef_id = "PP-0060-24-00000007" + self.payment_plan.save() + self.pdf_export_service = PaymentPlanPDFExportService(self.payment_plan) + + financial_service_provider1 = FinancialServiceProviderFactory( + delivery_mechanisms=[GenericPayment.DELIVERY_TYPE_CASH] + ) + + DeliveryMechanismPerPaymentPlanFactory( + payment_plan=self.payment_plan, + delivery_mechanism=GenericPayment.DELIVERY_TYPE_CASH, + financial_service_provider=financial_service_provider1, + delivery_mechanism_order=1, + ) + approval_process = ApprovalProcessFactory( + payment_plan=self.payment_plan, + ) + ApprovalFactory(type=Approval.APPROVAL, approval_process=approval_process) + + @patch( + "hct_mis_api.apps.payment.pdf.payment_plan_export_pdf_service.PaymentPlanPDFExportService.get_link", + return_value="http://www_link/download-payment-plan-summary-pdf/111", + ) + def test_generate_web_links(self, get_link_mock: Any) -> None: + expected_download_link = "http://www_link/download-payment-plan-summary-pdf/111" + self.pdf_export_service.generate_web_links() + self.assertEqual(self.pdf_export_service.download_link, expected_download_link) + self.assertEqual(self.pdf_export_service.payment_plan_link, expected_download_link) + + @patch( + "hct_mis_api.apps.payment.pdf.payment_plan_export_pdf_service.PaymentPlanPDFExportService.get_link", + return_value="http://www_link/download-payment-plan-summary-pdf/111", + ) + def test_generate_pdf_summary(self, get_link_mock: Any) -> None: + pdf1, filename1 = self.pdf_export_service.generate_pdf_summary() + + self.assertEqual(self.payment_plan.program.data_collecting_type.type, DataCollectingType.Type.STANDARD) + + self.assertTrue(isinstance(pdf1, bytes)) + self.assertEqual(filename1, "PaymentPlanSummary-PP-0060-24-00000007.pdf") + + self.payment_plan.program.data_collecting_type.type = DataCollectingType.Type.SOCIAL + self.payment_plan.program.data_collecting_type.save() + self.payment_plan.program.data_collecting_type.refresh_from_db(fields=["type"]) + + self.assertEqual(self.payment_plan.program.data_collecting_type.type, DataCollectingType.Type.SOCIAL) + pdf2, filename2 = self.pdf_export_service.generate_pdf_summary() + self.assertTrue(isinstance(pdf2, bytes)) + self.assertEqual(filename2, "PaymentPlanSummary-PP-0060-24-00000007.pdf") + + def test_get_email_context(self) -> None: + user_mock = MagicMock() + user_mock.first_name = "First" + user_mock.last_name = "Last" + user_mock.email = "first.last@email_tivix.com" + expected_context = { + "first_name": "First", + "last_name": "Last", + "email": "first.last@email_tivix.com", + "message": "Payment Plan Summary PDF file(s) have been generated, " + "and below you will find the link to download the file(s).", + "link": "", + "title": "Payment Plan Payment List files generated", + } + + context = self.pdf_export_service.get_email_context(user_mock) + + self.assertDictEqual(context, expected_context) diff --git a/backend/hct_mis_api/apps/targeting/graphql_types.py b/backend/hct_mis_api/apps/targeting/graphql_types.py index f35e959bde..a1839d4b89 100644 --- a/backend/hct_mis_api/apps/targeting/graphql_types.py +++ b/backend/hct_mis_api/apps/targeting/graphql_types.py @@ -1,3 +1,4 @@ +import uuid from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type import graphene @@ -26,17 +27,20 @@ from graphene.types.structures import List as GrapheneList - from hct_mis_api.apps.core.models import BusinessArea from hct_mis_api.apps.targeting.models import TargetingIndividualBlockRuleFilter -def get_field_by_name(field_name: str, business_area: "BusinessArea") -> Dict: - factory = FieldFactory.from_scope(Scope.TARGETING) - factory.apply_business_area(business_area.slug) +def get_field_by_name(field_name: str, target_population: target_models.TargetPopulation) -> Dict: + scopes = [Scope.TARGETING] + if target_population.program.is_social_worker_program: + scopes.append(Scope.XLSX_PEOPLE) + factory = FieldFactory.from_only_scopes(scopes) + factory.apply_business_area(target_population.business_area.slug) field = factory.to_dict_by("name")[field_name] - choices = field.get("choices") + choices = field.get("choices") or field.get("_choices") if choices and callable(choices): field["choices"] = choices() + field["id"] = uuid.uuid4() return field @@ -61,9 +65,12 @@ def resolve_field_attribute(parent, info: Any) -> Optional[Dict]: return FlexibleAttribute.objects.get(name=parent.field_name) else: field_attribute = get_field_by_name( - parent.field_name, parent.targeting_criteria_rule.targeting_criteria.target_population.business_area + parent.field_name, parent.targeting_criteria_rule.targeting_criteria.target_population + ) + parent.targeting_criteria_rule + return filter_choices( + field_attribute, parent.arguments # type: ignore # can't convert graphene list to list ) - return filter_choices(field_attribute, parent.arguments) # type: ignore # can't convert graphene list to list class Meta: model = target_models.TargetingCriteriaRuleFilter @@ -82,7 +89,7 @@ def resolve_field_attribute(parent, info: Any) -> Any: field_attribute = get_field_by_name( parent.field_name, - parent.individuals_filters_block.targeting_criteria_rule.targeting_criteria.target_population.business_area, + parent.individuals_filters_block.targeting_criteria_rule.targeting_criteria.target_population, ) return filter_choices(field_attribute, parent.arguments) # type: ignore # can't convert graphene list to list diff --git a/backend/hct_mis_api/apps/targeting/models.py b/backend/hct_mis_api/apps/targeting/models.py index 07f3d23f16..1f1c0ea5b4 100644 --- a/backend/hct_mis_api/apps/targeting/models.py +++ b/backend/hct_mis_api/apps/targeting/models.py @@ -45,7 +45,6 @@ from django.db.models.query import QuerySet - logger = logging.getLogger(__name__) @@ -446,7 +445,19 @@ class TargetingCriteriaRuleFilter(TimeStampedUUIDModel, TargetingCriteriaFilterB :Residential Status != Refugee """ + @property + def is_social_worker_program(self) -> bool: + try: + return self.targeting_criteria_rule.targeting_criteria.target_population.program.is_social_worker_program + except ( + AttributeError, + TargetingCriteriaRuleFilter.targeting_criteria_rule.RelatedObjectDoesNotExist, + ): + return False + def get_core_fields(self) -> List: + if self.is_social_worker_program: + return FieldFactory.from_only_scopes([Scope.TARGETING, Scope.XLSX_PEOPLE]) return FieldFactory.from_scope(Scope.TARGETING).associated_with_household() comparison_method = models.CharField( @@ -475,6 +486,10 @@ class TargetingIndividualBlockRuleFilter(TimeStampedUUIDModel, TargetingCriteria :Residential Status != Refugee """ + @property + def is_social_worker_program(self) -> bool: + return False + def get_core_fields(self) -> List: return FieldFactory.from_scope(Scope.TARGETING).associated_with_individual() diff --git a/backend/hct_mis_api/apps/targeting/services/targeting_service.py b/backend/hct_mis_api/apps/targeting/services/targeting_service.py index 9c79493790..3c46288270 100644 --- a/backend/hct_mis_api/apps/targeting/services/targeting_service.py +++ b/backend/hct_mis_api/apps/targeting/services/targeting_service.py @@ -329,7 +329,9 @@ def get_query_for_core_field(self) -> Q: core_field_attr = core_field_attrs[0] get_query = core_field_attr.get("get_query") if get_query: - return get_query(self.comparison_method, self.arguments) + return get_query( + self.comparison_method, self.arguments, is_social_worker_query=self.is_social_worker_program + ) lookup = core_field_attr.get("lookup") if not lookup: logger.error( diff --git a/backend/selenium_tests/conftest.py b/backend/selenium_tests/conftest.py index 259b5300e3..f9b390e17c 100644 --- a/backend/selenium_tests/conftest.py +++ b/backend/selenium_tests/conftest.py @@ -25,6 +25,9 @@ from page_object.registration_data_import.registration_data_import import ( RegistrationDataImport, ) +from page_object.targeting.targeting import Targeting +from page_object.targeting.targeting_create import TargetingCreate +from page_object.targeting.targeting_details import TargetingDetails from pytest_django.live_server_helper import LiveServer from pytest_html_reporter import attach from requests import Session @@ -48,6 +51,9 @@ def pytest_addoption(parser) -> None: # type: ignore def pytest_configure() -> None: + # delete all old screenshots + for file in os.listdir("report/screenshot"): + os.remove(os.path.join("report/screenshot", file)) from django.conf import settings settings.DEBUG = True @@ -240,6 +246,21 @@ def pageIndividualsDetails(request: FixtureRequest, browser: Chrome) -> Individu yield IndividualsDetails(browser) +@pytest.fixture +def pageTargeting(request: FixtureRequest, browser: Chrome) -> Targeting: + yield Targeting(browser) + + +@pytest.fixture +def pageTargetingDetails(request: FixtureRequest, browser: Chrome) -> TargetingDetails: + yield TargetingDetails(browser) + + +@pytest.fixture +def pageTargetingCreate(request: FixtureRequest, browser: Chrome) -> TargetingCreate: + yield TargetingCreate(browser) + + @pytest.fixture def pageGrievanceDetailsPage(request: FixtureRequest, browser: Chrome) -> GrievanceDetailsPage: yield GrievanceDetailsPage(browser) diff --git a/backend/selenium_tests/girevance/grievance_tickets/test_grievance_tickets.py b/backend/selenium_tests/girevance/grievance_tickets/test_grievance_tickets.py index 7d072396c0..fa4442db23 100644 --- a/backend/selenium_tests/girevance/grievance_tickets/test_grievance_tickets.py +++ b/backend/selenium_tests/girevance/grievance_tickets/test_grievance_tickets.py @@ -37,6 +37,8 @@ def create_programs(django_db_setup: Generator[None, None, None], django_db_bloc @pytest.mark.usefixtures("login") class TestSmokeGrievanceTickets: + + @pytest.mark.skip(reason="Unstable test") def test_check_grievance_tickets_user_generated_page( self, create_programs: None, @@ -146,7 +148,6 @@ def test_check_grievance_tickets_details_page( @pytest.mark.usefixtures("login") class TestGrievanceTicketsHappyPath: - @pytest.mark.skip(reason="ToDo") def test_grievance_tickets_create_new_ticket( self, diff --git a/backend/selenium_tests/helpers/helper.py b/backend/selenium_tests/helpers/helper.py index 3503ec9906..4245ed6c1d 100644 --- a/backend/selenium_tests/helpers/helper.py +++ b/backend/selenium_tests/helpers/helper.py @@ -2,7 +2,7 @@ from time import sleep from typing import Literal, Union -from selenium.webdriver import Chrome +from selenium.webdriver import Chrome, Keys from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.remote.webelement import WebElement @@ -77,6 +77,19 @@ def select_option_by_name(self, optionName: str) -> None: self.wait_for(selectOption).click() self.wait_for_disappear(selectOption) + def select_multiple_option_by_name(self, *optionNames: [str]) -> None: + for optionName in optionNames: + selectOption = f'li[data-cy="select-option-{optionName}"]' + self.wait_for(selectOption).click() + actions = ActionChains(self.driver) + actions.send_keys(Keys.ESCAPE).perform() # type: ignore + try: + self.wait_for_disappear(selectOption) + except BaseException: + sleep(1) + self.wait_for(selectOption).click() + self.wait_for_disappear(selectOption) + @staticmethod def choose_option(list_options: list, name: str) -> bool: for option in list_options: diff --git a/backend/selenium_tests/page_object/targeting/create_new.py b/backend/selenium_tests/page_object/targeting/create_new.py deleted file mode 100644 index cd4bda0e98..0000000000 --- a/backend/selenium_tests/page_object/targeting/create_new.py +++ /dev/null @@ -1,13 +0,0 @@ -from page_object.base_components import BaseComponents -from selenium.webdriver.remote.webelement import WebElement - - -class CreateNew(BaseComponents): - # Locators - targetingCriteria = 'h6[data-cy="title-targeting-criteria"]' - # Texts - textTargetingCriteria = "Targeting Criteria" - # Elements - - def getTargetingCriteria(self) -> WebElement: - return self.wait_for(self.targetingCriteria) diff --git a/backend/selenium_tests/page_object/targeting/t_details_page.py b/backend/selenium_tests/page_object/targeting/t_details_page.py deleted file mode 100644 index 17f3fa6a95..0000000000 --- a/backend/selenium_tests/page_object/targeting/t_details_page.py +++ /dev/null @@ -1,16 +0,0 @@ -from page_object.base_components import BaseComponents -from selenium.webdriver.remote.webelement import WebElement - - -class TDetailsPage(BaseComponents): - # Locators - titlePage = 'h5[data-cy="page-header-title"]' - status = 'div[data-cy="target-population-status"]' - # Texts - # Elements - - def getTitlePage(self) -> WebElement: - return self.wait_for(self.titlePage) - - def getStatus(self) -> WebElement: - return self.wait_for(self.status) diff --git a/backend/selenium_tests/page_object/targeting/targeting.py b/backend/selenium_tests/page_object/targeting/targeting.py index 5f86be9233..e60742905d 100644 --- a/backend/selenium_tests/page_object/targeting/targeting.py +++ b/backend/selenium_tests/page_object/targeting/targeting.py @@ -1,6 +1,8 @@ from page_object.base_components import BaseComponents from selenium.webdriver.remote.webelement import WebElement +from hct_mis_api.apps.core.utils import encode_id_base64 + class Targeting(BaseComponents): # Locators @@ -10,7 +12,8 @@ class Targeting(BaseComponents): programFilter = 'div[data-cy="filters-program"]' minNumberOfHouseholds = 'div[data-cy="filters-total-households-count-min"]' maxNumberOfHouseholds = 'div[data-cy="filters-total-households-count-max"]' - buttonCreateNew = 'a[data-cy="button-target-population-create-new"]' + buttonCreateNew = 'button[data-cy="button-new-tp"]' + buttonCreateNewByFilters = 'li[data-cy="menu-item-filters"]' tabTitle = 'h6[data-cy="table-title"]' tabColumnLabel = 'span[data-cy="table-label"]' statusOptions = 'li[role="option"]' @@ -31,6 +34,13 @@ class Targeting(BaseComponents): buttonApply = 'button[data-cy="button-filters-apply"]' buttonClear = 'button[data-cy="button-filters-clear"]' + def navigate_to_page(self, business_area_slug: str, program_id: str) -> None: + self.driver.get(self.get_page_url(business_area_slug, program_id)) + + def get_page_url(self, business_area_slug: str, program_id: str) -> str: + encoded_program_id = encode_id_base64(program_id, "Program") + return f"{self.driver.live_server.url}/{business_area_slug}/programs/{encoded_program_id}/target-population" + # Elements def getTitlePage(self) -> WebElement: @@ -54,6 +64,9 @@ def getMaxNumberOfHouseholdsFilter(self) -> WebElement: def getButtonCreateNew(self) -> WebElement: return self.wait_for(self.buttonCreateNew) + def getButtonCreateNewByFilters(self) -> WebElement: + return self.wait_for(self.buttonCreateNewByFilters) + def getTabTitle(self) -> WebElement: return self.wait_for(self.tabTitle) diff --git a/backend/selenium_tests/page_object/targeting/targeting_create.py b/backend/selenium_tests/page_object/targeting/targeting_create.py new file mode 100644 index 0000000000..b530446a26 --- /dev/null +++ b/backend/selenium_tests/page_object/targeting/targeting_create.py @@ -0,0 +1,58 @@ +from page_object.base_components import BaseComponents +from selenium.webdriver.remote.webelement import WebElement + + +class TargetingCreate(BaseComponents): + # Locators + targetingCriteria = 'h6[data-cy="title-targeting-criteria"]' + addCriteriaButton = 'div[data-cy="button-target-population-add-criteria"]' + addHouseholdRuleButton = '[data-cy="button-household-rule"]' + addIndividualRuleButton = '[data-cy="button-individual-rule"]' + addPeopleRuleButton = '[data-cy="button-household-rule"]' + titlePage = 'h5[data-cy="page-header-title"]' + fieldName = 'input[data-cy="input-name"]' + targetingCriteriaAutoComplete = 'input[data-cy="autocomplete-target-criteria-option-{}"]' + targetingCriteriaValue = '[data-cy="select-filters[{}].value"]' + targetingCriteriaAddDialogSaveButton = 'button[data-cy="button-target-population-add-criteria"]' + criteriaContainer = 'div[data-cy="criteria-container"]' + targetPopulationSaveButton = 'button[data-cy="button-target-population-create"]' + # Texts + textTargetingCriteria = "Targeting Criteria" + + # Elements + + def getTargetingCriteria(self) -> WebElement: + return self.wait_for(self.targetingCriteria) + + def getTitlePage(self) -> WebElement: + return self.wait_for(self.titlePage) + + def getAddCriteriaButton(self) -> WebElement: + return self.wait_for(self.addCriteriaButton) + + def getAddHouseholdRuleButton(self) -> WebElement: + return self.wait_for(self.addHouseholdRuleButton) + + def getAddIndividualRuleButton(self) -> WebElement: + return self.wait_for(self.addIndividualRuleButton) + + def getAddPeopleRuleButton(self) -> WebElement: + return self.wait_for(self.addPeopleRuleButton) + + def getTargetingCriteriaAutoComplete(self, index: int = 0) -> WebElement: + return self.wait_for(self.targetingCriteriaAutoComplete.format(index)) + + def getTargetingCriteriaValue(self, index: int = 0) -> WebElement: + return self.wait_for(self.targetingCriteriaValue.format(index)) + + def getTargetingCriteriaAddDialogSaveButton(self) -> WebElement: + return self.wait_for(self.targetingCriteriaAddDialogSaveButton) + + def getCriteriaContainer(self) -> WebElement: + return self.wait_for(self.criteriaContainer) + + def getFieldName(self) -> WebElement: + return self.wait_for(self.fieldName) + + def getTargetPopulationSaveButton(self) -> WebElement: + return self.wait_for(self.targetPopulationSaveButton) diff --git a/backend/selenium_tests/page_object/targeting/targeting_details.py b/backend/selenium_tests/page_object/targeting/targeting_details.py new file mode 100644 index 0000000000..41f3b80100 --- /dev/null +++ b/backend/selenium_tests/page_object/targeting/targeting_details.py @@ -0,0 +1,37 @@ +from page_object.base_components import BaseComponents +from selenium.webdriver.remote.webelement import WebElement + + +class TargetingDetails(BaseComponents): + # Locators + titlePage = 'h5[data-cy="page-header-title"]' + status = 'div[data-cy="target-population-status"]' + criteria_container = 'div[data-cy="criteria-container"]' + lock_button = 'button[data-cy="button-target-population-lock"]' + household_table_cell = "table tr:nth-of-type({}) td:nth-of-type({})" + people_table_rows = '[data-cy="target-population-people-row"]' + household_table_rows = '[data-cy="target-population-household-row"]' + + # Texts + # Elements + + def getTitlePage(self) -> WebElement: + return self.wait_for(self.titlePage) + + def getStatus(self) -> WebElement: + return self.wait_for(self.status) + + def getCriteriaContainer(self) -> WebElement: + return self.wait_for(self.criteria_container) + + def getLockButton(self) -> WebElement: + return self.wait_for(self.lock_button) + + def getHouseholdTableCell(self, row: int, column: int) -> WebElement: + return self.wait_for(self.household_table_cell.format(row, column)) + + def getPeopleTableRows(self) -> list[WebElement]: + return self.get_elements(self.people_table_rows) + + def getHouseholdTableRows(self) -> list[WebElement]: + return self.get_elements(self.household_table_rows) diff --git a/backend/selenium_tests/programme_management/test_programme_management.py b/backend/selenium_tests/programme_management/test_programme_management.py index d48290ea7b..2d8d9da0da 100644 --- a/backend/selenium_tests/programme_management/test_programme_management.py +++ b/backend/selenium_tests/programme_management/test_programme_management.py @@ -397,6 +397,7 @@ def test_create_programme_add_partners_Business_Area( assert "UNHCR" in pageProgrammeDetails.getLabelPartnerName().text assert "Business Area" in pageProgrammeDetails.getLabelAreaAccess().text + @pytest.mark.skip(reason="Unstable test") @pytest.mark.parametrize( "test_data", [ diff --git a/backend/selenium_tests/registration_data_import/test_registration_data_import.py b/backend/selenium_tests/registration_data_import/test_registration_data_import.py index f705a1b60e..596da1fb4a 100644 --- a/backend/selenium_tests/registration_data_import/test_registration_data_import.py +++ b/backend/selenium_tests/registration_data_import/test_registration_data_import.py @@ -116,6 +116,7 @@ def test_smoke_registration_data_details_page( class TestRegistrationDataImport: + @pytest.mark.skip(reason="Unstable test") def test_smoke_registration_data_import_happy_path( self, registration_datahub: None, diff --git a/backend/selenium_tests/targeting/test_create_targeting.py b/backend/selenium_tests/targeting/test_create_targeting.py new file mode 100644 index 0000000000..0fe1396f29 --- /dev/null +++ b/backend/selenium_tests/targeting/test_create_targeting.py @@ -0,0 +1,167 @@ +from datetime import datetime + +from django.db import transaction + +import pytest +from dateutil.relativedelta import relativedelta +from page_object.targeting.targeting import Targeting +from page_object.targeting.targeting_create import TargetingCreate +from page_object.targeting.targeting_details import TargetingDetails +from selenium.webdriver import ActionChains, Keys + +from hct_mis_api.apps.core.fixtures import DataCollectingTypeFactory +from hct_mis_api.apps.core.models import BusinessArea, DataCollectingType +from hct_mis_api.apps.household.fixtures import create_household_and_individuals +from hct_mis_api.apps.household.models import HEARING, HOST, REFUGEE, SEEING, Household +from hct_mis_api.apps.program.fixtures import ProgramFactory +from hct_mis_api.apps.program.models import Program + +pytestmark = pytest.mark.django_db(transaction=True) + + +@pytest.fixture +def sw_program() -> Program: + return get_program_with_dct_type_and_name( + "SW Program", dct_type=DataCollectingType.Type.SOCIAL, status=Program.ACTIVE + ) + + +@pytest.fixture +def non_sw_program() -> Program: + return get_program_with_dct_type_and_name( + "Non SW Program", dct_type=DataCollectingType.Type.STANDARD, status=Program.ACTIVE + ) + + +@pytest.fixture +def household_with_disability() -> Household: + program = Program.objects.first() + with transaction.atomic(): + household, individuals = create_household_and_individuals( + household_data={"business_area": program.business_area, "program": program, "residence_status": HOST}, + individuals_data=[ + {"business_area": program.business_area, "observed_disability": [SEEING, HEARING]}, + ], + ) + return household + + +@pytest.fixture +def household_without_disabilities() -> Household: + program = Program.objects.first() + with transaction.atomic(): + household, individuals = create_household_and_individuals( + household_data={"business_area": program.business_area, "program": program, "residence_status": HOST}, + individuals_data=[ + {"business_area": program.business_area, "observed_disability": []}, + ], + ) + return household + + +@pytest.fixture +def household_refugee() -> Household: + program = Program.objects.first() + with transaction.atomic(): + household, individuals = create_household_and_individuals( + household_data={"business_area": program.business_area, "program": program, "residence_status": REFUGEE}, + individuals_data=[ + {"business_area": program.business_area, "observed_disability": []}, + ], + ) + return household + + +def get_program_with_dct_type_and_name( + name: str, dct_type: str = DataCollectingType.Type.STANDARD, status: str = Program.ACTIVE +) -> Program: + BusinessArea.objects.filter(slug="afghanistan").update(is_payment_plan_applicable=True) + dct = DataCollectingTypeFactory(type=dct_type) + program = ProgramFactory( + name=name, + start_date=datetime.now() - relativedelta(months=1), + end_date=datetime.now() + relativedelta(months=1), + data_collecting_type=dct, + status=status, + ) + return program + + +@pytest.mark.usefixtures("login") +class TestCreateTargeting: + def test_create_targeting_for_people( + self, + sw_program: Program, + household_with_disability: Household, + household_without_disabilities: Household, + pageTargeting: Targeting, + pageTargetingCreate: TargetingCreate, + pageTargetingDetails: TargetingDetails, + ) -> None: + pageTargeting.navigate_to_page("afghanistan", sw_program.id) + pageTargeting.getButtonCreateNew().click() + pageTargeting.getButtonCreateNewByFilters().click() + assert "New Target Population" in pageTargetingCreate.getTitlePage().text + pageTargetingCreate.getAddCriteriaButton().click() + assert pageTargetingCreate.getAddPeopleRuleButton().text.upper() == "ADD PEOPLE RULE" + pageTargetingCreate.getAddPeopleRuleButton().click() + pageTargetingCreate.getTargetingCriteriaAutoComplete().click() + pageTargetingCreate.getTargetingCriteriaAutoComplete().send_keys("Does the Social Worker have disability?") + pageTargetingCreate.getTargetingCriteriaAutoComplete().send_keys(Keys.ARROW_DOWN) + pageTargetingCreate.getTargetingCriteriaAutoComplete().send_keys(Keys.ENTER) + pageTargetingCreate.getTargetingCriteriaValue().click() + pageTargetingCreate.select_multiple_option_by_name(HEARING, SEEING) + pageTargetingCreate.getTargetingCriteriaAddDialogSaveButton().click() + disability_expected_criteria_text = "Does the Social Worker have disability?: Difficulty hearing (even if using a hearing aid), Difficulty seeing (even if wearing glasses)" + assert pageTargetingCreate.getCriteriaContainer().text == disability_expected_criteria_text + targeting_name = "Test targeting people" + pageTargetingCreate.getFieldName().send_keys(targeting_name) + pageTargetingCreate.getTargetPopulationSaveButton().click() + pageTargetingDetails.getLockButton() + assert pageTargetingDetails.getTitlePage().text == targeting_name + assert pageTargetingDetails.getCriteriaContainer().text == disability_expected_criteria_text + assert Household.objects.count() == 2 + assert ( + pageTargetingDetails.getHouseholdTableCell(1, 1).text + == household_with_disability.individuals.first().unicef_id + ) + assert len(pageTargetingDetails.getPeopleTableRows()) == 1 + + def test_create_targeting_for_normal_program( + self, + non_sw_program: Program, + household_with_disability: Household, + household_without_disabilities: Household, + household_refugee: Household, + pageTargeting: Targeting, + pageTargetingCreate: TargetingCreate, + pageTargetingDetails: TargetingDetails, + ) -> None: + pageTargeting.navigate_to_page("afghanistan", non_sw_program.id) + pageTargeting.getButtonCreateNew().click() + pageTargeting.getButtonCreateNewByFilters().click() + assert "New Target Population" in pageTargetingCreate.getTitlePage().text + pageTargetingCreate.getAddCriteriaButton().click() + assert pageTargetingCreate.getAddPeopleRuleButton().text.upper() == "ADD HOUSEHOLD RULE" + pageTargetingCreate.getAddHouseholdRuleButton().click() + pageTargetingCreate.getTargetingCriteriaAutoComplete().click() + pageTargetingCreate.getTargetingCriteriaAutoComplete().send_keys("Residence Status") + pageTargetingCreate.getTargetingCriteriaAutoComplete().send_keys(Keys.ARROW_DOWN) + pageTargetingCreate.getTargetingCriteriaAutoComplete().send_keys(Keys.ENTER) + pageTargetingCreate.getTargetingCriteriaValue().click() + pageTargetingCreate.select_option_by_name(REFUGEE) + pageTargetingCreate.getTargetingCriteriaAddDialogSaveButton().click() + disability_expected_criteria_text = "Residence status: Displaced | Refugee / Asylum Seeker" + assert pageTargetingCreate.getCriteriaContainer().text == disability_expected_criteria_text + targeting_name = "Test targeting people" + pageTargetingCreate.getFieldName().send_keys(targeting_name) + pageTargetingCreate.getTargetPopulationSaveButton().click() + pageTargetingDetails.getLockButton() + assert pageTargetingDetails.getTitlePage().text == targeting_name + assert pageTargetingDetails.getCriteriaContainer().text == disability_expected_criteria_text + assert Household.objects.count() == 3 + assert Program.objects.count() == 1 + assert pageTargetingDetails.getHouseholdTableCell(1, 1).text == household_refugee.unicef_id + actions = ActionChains(pageTargetingDetails.driver) + actions.move_to_element(pageTargetingDetails.getHouseholdTableCell(1, 1)).perform() # type: ignore + assert len(pageTargetingDetails.getHouseholdTableRows()) == 1 diff --git a/compose.selenium.yml b/compose.selenium.yml index 95b15ca0ee..e9edacc8cc 100644 --- a/compose.selenium.yml +++ b/compose.selenium.yml @@ -3,7 +3,7 @@ version: '3.7' volumes: backend-data-selenium: backend-web-app-selenium: - db-selenium: + db-selenium-data: data_es-selenium: services: @@ -21,11 +21,11 @@ services: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - CACHE_LOCATION=redis://redis:6379/1 - - DATABASE_URL=postgis://postgres:postgres@db:5432/postgres - - DATABASE_URL_HUB_MIS=postgis://postgres:postgres@db:5432/mis_datahub - - DATABASE_URL_HUB_CA=postgis://postgres:postgres@db:5432/ca_datahub - - DATABASE_URL_HUB_ERP=postgis://postgres:postgres@db:5432/erp_datahub - - DATABASE_URL_HUB_REGISTRATION=postgis://postgres:postgres@db:5432/rdi_datahub + - DATABASE_URL=postgis://postgres:postgres@db_selenium:5432/postgres + - DATABASE_URL_HUB_MIS=postgis://postgres:postgres@db_selenium:5432/mis_datahub + - DATABASE_URL_HUB_CA=postgis://postgres:postgres@db_selenium:5432/ca_datahub + - DATABASE_URL_HUB_ERP=postgis://postgres:postgres@db_selenium:5432/erp_datahub + - DATABASE_URL_HUB_REGISTRATION=postgis://postgres:postgres@db_selenium:5432/rdi_datahub - USE_DUMMY_EXCHANGE_RATES=yes - CELERY_TASK_ALWAYS_EAGER=true build: @@ -35,9 +35,9 @@ services: volumes: - ./backend/report/screenshot/:/code/screenshot/ - ./backend/report/:/code/report/ - - backend-data:/data - backend-data-selenium:/data - ./backend/selenium_tests:/code/selenium_tests + - ./backend/hct_mis_api:/code/hct_mis_api - type: volume source: backend-web-app-selenium target: /code/hct_mis_api/apps/web/static @@ -45,13 +45,13 @@ services: nocopy: false command: | sh -c " - waitforit -host=db -port=5432 -timeout=30 && + waitforit -host=db_selenium -port=5432 -timeout=30 && pytest -svvv selenium_tests --html-report=./report/report.html " ports: - "8080:8080" depends_on: - db: + db_selenium: condition: service_started redis: condition: service_started @@ -78,13 +78,11 @@ services: redis: restart: always image: redis:4.0.11-alpine3.8 - expose: - - "6379" - db: + db_selenium: image: kartoza/postgis:14-3 volumes: - - db-selenium:/var/lib/postgresql/data + - db-selenium-data:/var/lib/postgresql/data - ./postgres/init:/docker-entrypoint-initdb.d environment: - POSTGRES_MULTIPLE_DATABASES=unicef_hct_mis_cashassist,rdi_datahub,mis_datahub,erp_datahub,ca_datahub @@ -94,8 +92,6 @@ services: - PGUSER=postgres - POSTGRES_HOST_AUTH_METHOD=trust - POSTGRES_SSL_MODE=off - ports: - - "5433:5432" elasticsearch: image: unicef/hct-elasticsearch diff --git a/deployment/docker-compose.selenium.yml b/deployment/docker-compose.selenium.yml index 3b5a138712..3940dd0634 100644 --- a/deployment/docker-compose.selenium.yml +++ b/deployment/docker-compose.selenium.yml @@ -1,11 +1,6 @@ version: '3.7' - volumes: - backend-data: backend-web-app: - db: - data_es: - services: selenium: stdin_open: true @@ -30,7 +25,6 @@ services: - ../backend:/code/ - ../backend/report/screenshot/:/code/screenshot/ - ../backend/report/:/code/report/ - - backend-data:/data - type: volume source: backend-web-app target: /code/hct_mis_api/apps/web @@ -71,7 +65,6 @@ services: db: image: kartoza/postgis:14-3 volumes: - - db:/var/lib/postgresql/data - ./postgres/init:/docker-entrypoint-initdb.d environment: - POSTGRES_MULTIPLE_DATABASES=unicef_hct_mis_cashassist,rdi_datahub,mis_datahub,erp_datahub,ca_datahub @@ -101,7 +94,5 @@ services: memlock: soft: -1 hard: -1 - volumes: - - data_es:/usr/share/elasticsearch/data ports: - 9200:9200 diff --git a/frontend/src/__generated__/graphql.tsx b/frontend/src/__generated__/graphql.tsx index ec389de103..d8cf54f96b 100644 --- a/frontend/src/__generated__/graphql.tsx +++ b/frontend/src/__generated__/graphql.tsx @@ -9229,17 +9229,17 @@ export type _TableTotalCashTransferredDataNode = { totalHouseholds?: Maybe; }; -export type GrievanceTicketDetailedFragment = { __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, category: number, consent: boolean, createdAt: any, updatedAt: any, description: string, language: string, admin?: string | null, area: string, adminUrl?: string | null, issueType?: number | null, priority?: number | null, urgency?: number | null, comments?: string | null, partner?: { __typename?: 'PartnerType', id: string, name: string } | null, businessArea: { __typename?: 'UserBusinessAreaNode', postponeDeduplication: boolean }, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, pCode?: string | null } | null, assignedTo?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, paymentRecord?: { __typename?: 'PaymentRecordAndPaymentNode', id?: string | null, caId?: string | null, deliveredQuantity?: number | null, entitlementQuantity?: number | null, objType?: string | null, parent?: { __typename?: 'CashPlanAndPaymentPlanNode', id?: string | null, unicefId?: string | null, objType?: string | null } | null, verification?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null, relatedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, linkedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, category: number, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, existingTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, category: number, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, addIndividualTicketDetails?: { __typename?: 'TicketAddIndividualDetailsNode', id: string, individualData?: any | null, approveStatus: boolean, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, individualDataUpdateTicketDetails?: { __typename?: 'TicketIndividualDataUpdateDetailsNode', id: string, individualData?: any | null, roleReassignData: any, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null } | null, householdDataUpdateTicketDetails?: { __typename?: 'TicketHouseholdDataUpdateDetailsNode', id: string, householdData?: any | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null } | null, deleteIndividualTicketDetails?: { __typename?: 'TicketDeleteIndividualDetailsNode', id: string, roleReassignData: any, approveStatus: boolean } | null, deleteHouseholdTicketDetails?: { __typename?: 'TicketDeleteHouseholdDetailsNode', id: string, approveStatus: boolean, reasonHousehold?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, systemFlaggingTicketDetails?: { __typename?: 'TicketSystemFlaggingDetailsNode', id: string, approveStatus: boolean, roleReassignData: any, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, fullName: string, birthDate: any, lastRegistrationDate: any, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, documentNumber: string, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> } }, sanctionListIndividual: { __typename?: 'SanctionListIndividualNode', id: string, fullName: string, referenceNumber: string, datesOfBirth: { __typename?: 'SanctionListIndividualDateOfBirthNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDateOfBirthNodeEdge', node?: { __typename?: 'SanctionListIndividualDateOfBirthNode', id: string, date: any } | null } | null> }, documents: { __typename?: 'SanctionListIndividualDocumentNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDocumentNodeEdge', node?: { __typename?: 'SanctionListIndividualDocumentNode', id: string, documentNumber: string, typeOfDocument: string } | null } | null> } } } | null, paymentVerificationTicketDetails?: { __typename?: 'TicketPaymentVerificationDetailsNode', id: string, newStatus?: TicketPaymentVerificationDetailsNewStatus | null, oldReceivedAmount?: number | null, newReceivedAmount?: number | null, approveStatus: boolean, paymentVerificationStatus: TicketPaymentVerificationDetailsPaymentVerificationStatus, hasMultiplePaymentVerifications?: boolean | null, paymentVerification?: { __typename?: 'PaymentVerificationNode', id: string, receivedAmount?: number | null } | null, paymentVerifications: { __typename?: 'PaymentVerificationNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationNodeEdge', node?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null> } } | null, needsAdjudicationTicketDetails?: { __typename?: 'TicketNeedsAdjudicationDetailsNode', id: string, hasDuplicatedDocument?: boolean | null, isMultipleDuplicatesVersion: boolean, roleReassignData: any, extraData?: { __typename?: 'TicketNeedsAdjudicationDetailsExtraDataNode', goldenRecords?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null, possibleDuplicate?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, birthDate: any, lastRegistrationDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null }, possibleDuplicate?: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, possibleDuplicates?: Array<{ __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null> | null, selectedIndividual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, activeIndividualsCount?: number | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, selectedIndividuals?: Array<{ __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, activeIndividualsCount?: number | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null> | null } | null, ticketNotes: { __typename?: 'TicketNoteNodeConnection', edges: Array<{ __typename?: 'TicketNoteNodeEdge', node?: { __typename?: 'TicketNoteNode', id: string, createdAt: any, updatedAt: any, description: string, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null } | null> }, programs?: Array<{ __typename?: 'ProgramNode', name: string, id: string } | null> | null, documentation?: Array<{ __typename?: 'GrievanceDocumentNode', id: string, createdAt: any, updatedAt: any, name?: string | null, fileSize?: number | null, contentType: string, filePath?: string | null, fileName?: string | null, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null> | null }; +export type GrievanceTicketDetailedFragment = { __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, category: number, consent: boolean, createdAt: any, updatedAt: any, description: string, language: string, admin?: string | null, area: string, adminUrl?: string | null, issueType?: number | null, priority?: number | null, urgency?: number | null, comments?: string | null, partner?: { __typename?: 'PartnerType', id: string, name: string } | null, businessArea: { __typename?: 'UserBusinessAreaNode', postponeDeduplication: boolean }, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, pCode?: string | null } | null, assignedTo?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, paymentRecord?: { __typename?: 'PaymentRecordAndPaymentNode', id?: string | null, caId?: string | null, deliveredQuantity?: number | null, entitlementQuantity?: number | null, objType?: string | null, parent?: { __typename?: 'CashPlanAndPaymentPlanNode', id?: string | null, unicefId?: string | null, objType?: string | null } | null, verification?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null, relatedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, linkedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, category: number, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, existingTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, category: number, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, addIndividualTicketDetails?: { __typename?: 'TicketAddIndividualDetailsNode', id: string, individualData?: any | null, approveStatus: boolean, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, individualDataUpdateTicketDetails?: { __typename?: 'TicketIndividualDataUpdateDetailsNode', id: string, individualData?: any | null, roleReassignData: any, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null } | null, householdDataUpdateTicketDetails?: { __typename?: 'TicketHouseholdDataUpdateDetailsNode', id: string, householdData?: any | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null } | null, deleteIndividualTicketDetails?: { __typename?: 'TicketDeleteIndividualDetailsNode', id: string, roleReassignData: any, approveStatus: boolean } | null, deleteHouseholdTicketDetails?: { __typename?: 'TicketDeleteHouseholdDetailsNode', id: string, approveStatus: boolean, reasonHousehold?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, systemFlaggingTicketDetails?: { __typename?: 'TicketSystemFlaggingDetailsNode', id: string, approveStatus: boolean, roleReassignData: any, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, fullName: string, birthDate: any, lastRegistrationDate: any, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, documentNumber: string, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> } }, sanctionListIndividual: { __typename?: 'SanctionListIndividualNode', id: string, fullName: string, referenceNumber: string, datesOfBirth: { __typename?: 'SanctionListIndividualDateOfBirthNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDateOfBirthNodeEdge', node?: { __typename?: 'SanctionListIndividualDateOfBirthNode', id: string, date: any } | null } | null> }, documents: { __typename?: 'SanctionListIndividualDocumentNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDocumentNodeEdge', node?: { __typename?: 'SanctionListIndividualDocumentNode', id: string, documentNumber: string, typeOfDocument: string } | null } | null> } } } | null, paymentVerificationTicketDetails?: { __typename?: 'TicketPaymentVerificationDetailsNode', id: string, newStatus?: TicketPaymentVerificationDetailsNewStatus | null, oldReceivedAmount?: number | null, newReceivedAmount?: number | null, approveStatus: boolean, paymentVerificationStatus: TicketPaymentVerificationDetailsPaymentVerificationStatus, hasMultiplePaymentVerifications?: boolean | null, paymentVerification?: { __typename?: 'PaymentVerificationNode', id: string, receivedAmount?: number | null } | null, paymentVerifications: { __typename?: 'PaymentVerificationNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationNodeEdge', node?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null> } } | null, needsAdjudicationTicketDetails?: { __typename?: 'TicketNeedsAdjudicationDetailsNode', id: string, hasDuplicatedDocument?: boolean | null, isMultipleDuplicatesVersion: boolean, roleReassignData: any, extraData?: { __typename?: 'TicketNeedsAdjudicationDetailsExtraDataNode', goldenRecords?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null, possibleDuplicate?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, birthDate: any, lastRegistrationDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null }, possibleDuplicate?: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, possibleDuplicates?: Array<{ __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null> | null, selectedIndividual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, activeIndividualsCount?: number | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, currency?: string | null, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, adminAreaTitle?: string | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, selectedIndividuals?: Array<{ __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, activeIndividualsCount?: number | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, currency?: string | null, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, adminAreaTitle?: string | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null> | null } | null, ticketNotes: { __typename?: 'TicketNoteNodeConnection', edges: Array<{ __typename?: 'TicketNoteNodeEdge', node?: { __typename?: 'TicketNoteNode', id: string, createdAt: any, updatedAt: any, description: string, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null } | null> }, programs?: Array<{ __typename?: 'ProgramNode', name: string, id: string } | null> | null, documentation?: Array<{ __typename?: 'GrievanceDocumentNode', id: string, createdAt: any, updatedAt: any, name?: string | null, fileSize?: number | null, contentType: string, filePath?: string | null, fileName?: string | null, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null> | null }; export type HouseholdMinimalFragment = { __typename?: 'HouseholdNode', id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, flexFields?: any | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, address: string, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } }; -export type HouseholdDetailedFragment = { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } }; +export type HouseholdDetailedFragment = { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } }; export type MergedHouseholdMinimalFragment = { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, size?: number | null, firstRegistrationDate: any, hasDuplicates?: boolean | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string }, admin1?: { __typename?: 'AreaNode', id: string, name: string } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null }; -export type IndividualMinimalFragment = { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null }; +export type IndividualMinimalFragment = { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null }; -export type IndividualDetailedFragment = { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } }; +export type IndividualDetailedFragment = { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } }; export type MergedIndividualMinimalFragment = { __typename?: 'IndividualNode', id: string, unicefId?: string | null, age?: number | null, fullName: string, birthDate: any, sex: IndividualSex, role?: string | null, relationship?: IndividualRelationship | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, fullName?: string | null, score?: number | null, proximityToScore?: number | null, age?: number | null, location?: string | null } | null> | null, deduplicationBatchResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, fullName?: string | null, score?: number | null, proximityToScore?: number | null, age?: number | null, location?: string | null } | null> | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', id: string, datahubId?: any | null } | null }; @@ -9342,7 +9342,7 @@ export type ApproveHouseholdDataChangeMutationVariables = Exact<{ }>; -export type ApproveHouseholdDataChangeMutation = { __typename?: 'Mutations', approveHouseholdDataChange?: { __typename?: 'HouseholdDataChangeApproveMutation', grievanceTicket?: { __typename?: 'GrievanceTicketNode', id: string, status: number, householdDataUpdateTicketDetails?: { __typename?: 'TicketHouseholdDataUpdateDetailsNode', id: string, householdData?: any | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null } | null } | null } | null }; +export type ApproveHouseholdDataChangeMutation = { __typename?: 'Mutations', approveHouseholdDataChange?: { __typename?: 'HouseholdDataChangeApproveMutation', grievanceTicket?: { __typename?: 'GrievanceTicketNode', id: string, status: number, householdDataUpdateTicketDetails?: { __typename?: 'TicketHouseholdDataUpdateDetailsNode', id: string, householdData?: any | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null } | null } | null } | null }; export type ApproveIndividualDataChangeMutationVariables = Exact<{ grievanceTicketId: Scalars['ID']['input']; @@ -9360,7 +9360,7 @@ export type ApproveIndividualDataChangeMutationVariables = Exact<{ }>; -export type ApproveIndividualDataChangeMutation = { __typename?: 'Mutations', approveIndividualDataChange?: { __typename?: 'IndividualDataChangeApproveMutation', grievanceTicket?: { __typename?: 'GrievanceTicketNode', id: string, status: number, individualDataUpdateTicketDetails?: { __typename?: 'TicketIndividualDataUpdateDetailsNode', id: string, individualData?: any | null, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null } | null } | null } | null }; +export type ApproveIndividualDataChangeMutation = { __typename?: 'Mutations', approveIndividualDataChange?: { __typename?: 'IndividualDataChangeApproveMutation', grievanceTicket?: { __typename?: 'GrievanceTicketNode', id: string, status: number, individualDataUpdateTicketDetails?: { __typename?: 'TicketIndividualDataUpdateDetailsNode', id: string, individualData?: any | null, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null } | null } | null } | null }; export type ApproveNeedsAdjudicationMutationVariables = Exact<{ grievanceTicketId: Scalars['ID']['input']; @@ -9443,7 +9443,7 @@ export type GrievanceTicketStatusChangeMutationVariables = Exact<{ }>; -export type GrievanceTicketStatusChangeMutation = { __typename?: 'Mutations', grievanceStatusChange?: { __typename?: 'GrievanceStatusChangeMutation', grievanceTicket?: { __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, category: number, consent: boolean, createdAt: any, updatedAt: any, description: string, language: string, admin?: string | null, area: string, adminUrl?: string | null, issueType?: number | null, priority?: number | null, urgency?: number | null, comments?: string | null, partner?: { __typename?: 'PartnerType', id: string, name: string } | null, businessArea: { __typename?: 'UserBusinessAreaNode', postponeDeduplication: boolean }, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, pCode?: string | null } | null, assignedTo?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, paymentRecord?: { __typename?: 'PaymentRecordAndPaymentNode', id?: string | null, caId?: string | null, deliveredQuantity?: number | null, entitlementQuantity?: number | null, objType?: string | null, parent?: { __typename?: 'CashPlanAndPaymentPlanNode', id?: string | null, unicefId?: string | null, objType?: string | null } | null, verification?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null, relatedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, linkedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, category: number, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, existingTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, category: number, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, addIndividualTicketDetails?: { __typename?: 'TicketAddIndividualDetailsNode', id: string, individualData?: any | null, approveStatus: boolean, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, individualDataUpdateTicketDetails?: { __typename?: 'TicketIndividualDataUpdateDetailsNode', id: string, individualData?: any | null, roleReassignData: any, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null } | null, householdDataUpdateTicketDetails?: { __typename?: 'TicketHouseholdDataUpdateDetailsNode', id: string, householdData?: any | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null } | null, deleteIndividualTicketDetails?: { __typename?: 'TicketDeleteIndividualDetailsNode', id: string, roleReassignData: any, approveStatus: boolean } | null, deleteHouseholdTicketDetails?: { __typename?: 'TicketDeleteHouseholdDetailsNode', id: string, approveStatus: boolean, reasonHousehold?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, systemFlaggingTicketDetails?: { __typename?: 'TicketSystemFlaggingDetailsNode', id: string, approveStatus: boolean, roleReassignData: any, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, fullName: string, birthDate: any, lastRegistrationDate: any, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, documentNumber: string, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> } }, sanctionListIndividual: { __typename?: 'SanctionListIndividualNode', id: string, fullName: string, referenceNumber: string, datesOfBirth: { __typename?: 'SanctionListIndividualDateOfBirthNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDateOfBirthNodeEdge', node?: { __typename?: 'SanctionListIndividualDateOfBirthNode', id: string, date: any } | null } | null> }, documents: { __typename?: 'SanctionListIndividualDocumentNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDocumentNodeEdge', node?: { __typename?: 'SanctionListIndividualDocumentNode', id: string, documentNumber: string, typeOfDocument: string } | null } | null> } } } | null, paymentVerificationTicketDetails?: { __typename?: 'TicketPaymentVerificationDetailsNode', id: string, newStatus?: TicketPaymentVerificationDetailsNewStatus | null, oldReceivedAmount?: number | null, newReceivedAmount?: number | null, approveStatus: boolean, paymentVerificationStatus: TicketPaymentVerificationDetailsPaymentVerificationStatus, hasMultiplePaymentVerifications?: boolean | null, paymentVerification?: { __typename?: 'PaymentVerificationNode', id: string, receivedAmount?: number | null } | null, paymentVerifications: { __typename?: 'PaymentVerificationNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationNodeEdge', node?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null> } } | null, needsAdjudicationTicketDetails?: { __typename?: 'TicketNeedsAdjudicationDetailsNode', id: string, hasDuplicatedDocument?: boolean | null, isMultipleDuplicatesVersion: boolean, roleReassignData: any, extraData?: { __typename?: 'TicketNeedsAdjudicationDetailsExtraDataNode', goldenRecords?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null, possibleDuplicate?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, birthDate: any, lastRegistrationDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null }, possibleDuplicate?: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, possibleDuplicates?: Array<{ __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null> | null, selectedIndividual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, activeIndividualsCount?: number | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, selectedIndividuals?: Array<{ __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, activeIndividualsCount?: number | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null> | null } | null, ticketNotes: { __typename?: 'TicketNoteNodeConnection', edges: Array<{ __typename?: 'TicketNoteNodeEdge', node?: { __typename?: 'TicketNoteNode', id: string, createdAt: any, updatedAt: any, description: string, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null } | null> }, programs?: Array<{ __typename?: 'ProgramNode', name: string, id: string } | null> | null, documentation?: Array<{ __typename?: 'GrievanceDocumentNode', id: string, createdAt: any, updatedAt: any, name?: string | null, fileSize?: number | null, contentType: string, filePath?: string | null, fileName?: string | null, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null> | null } | null } | null }; +export type GrievanceTicketStatusChangeMutation = { __typename?: 'Mutations', grievanceStatusChange?: { __typename?: 'GrievanceStatusChangeMutation', grievanceTicket?: { __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, category: number, consent: boolean, createdAt: any, updatedAt: any, description: string, language: string, admin?: string | null, area: string, adminUrl?: string | null, issueType?: number | null, priority?: number | null, urgency?: number | null, comments?: string | null, partner?: { __typename?: 'PartnerType', id: string, name: string } | null, businessArea: { __typename?: 'UserBusinessAreaNode', postponeDeduplication: boolean }, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, pCode?: string | null } | null, assignedTo?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, paymentRecord?: { __typename?: 'PaymentRecordAndPaymentNode', id?: string | null, caId?: string | null, deliveredQuantity?: number | null, entitlementQuantity?: number | null, objType?: string | null, parent?: { __typename?: 'CashPlanAndPaymentPlanNode', id?: string | null, unicefId?: string | null, objType?: string | null } | null, verification?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null, relatedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, linkedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, category: number, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, existingTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, category: number, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, addIndividualTicketDetails?: { __typename?: 'TicketAddIndividualDetailsNode', id: string, individualData?: any | null, approveStatus: boolean, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, individualDataUpdateTicketDetails?: { __typename?: 'TicketIndividualDataUpdateDetailsNode', id: string, individualData?: any | null, roleReassignData: any, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null } | null, householdDataUpdateTicketDetails?: { __typename?: 'TicketHouseholdDataUpdateDetailsNode', id: string, householdData?: any | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null } | null, deleteIndividualTicketDetails?: { __typename?: 'TicketDeleteIndividualDetailsNode', id: string, roleReassignData: any, approveStatus: boolean } | null, deleteHouseholdTicketDetails?: { __typename?: 'TicketDeleteHouseholdDetailsNode', id: string, approveStatus: boolean, reasonHousehold?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, systemFlaggingTicketDetails?: { __typename?: 'TicketSystemFlaggingDetailsNode', id: string, approveStatus: boolean, roleReassignData: any, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, fullName: string, birthDate: any, lastRegistrationDate: any, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, documentNumber: string, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> } }, sanctionListIndividual: { __typename?: 'SanctionListIndividualNode', id: string, fullName: string, referenceNumber: string, datesOfBirth: { __typename?: 'SanctionListIndividualDateOfBirthNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDateOfBirthNodeEdge', node?: { __typename?: 'SanctionListIndividualDateOfBirthNode', id: string, date: any } | null } | null> }, documents: { __typename?: 'SanctionListIndividualDocumentNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDocumentNodeEdge', node?: { __typename?: 'SanctionListIndividualDocumentNode', id: string, documentNumber: string, typeOfDocument: string } | null } | null> } } } | null, paymentVerificationTicketDetails?: { __typename?: 'TicketPaymentVerificationDetailsNode', id: string, newStatus?: TicketPaymentVerificationDetailsNewStatus | null, oldReceivedAmount?: number | null, newReceivedAmount?: number | null, approveStatus: boolean, paymentVerificationStatus: TicketPaymentVerificationDetailsPaymentVerificationStatus, hasMultiplePaymentVerifications?: boolean | null, paymentVerification?: { __typename?: 'PaymentVerificationNode', id: string, receivedAmount?: number | null } | null, paymentVerifications: { __typename?: 'PaymentVerificationNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationNodeEdge', node?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null> } } | null, needsAdjudicationTicketDetails?: { __typename?: 'TicketNeedsAdjudicationDetailsNode', id: string, hasDuplicatedDocument?: boolean | null, isMultipleDuplicatesVersion: boolean, roleReassignData: any, extraData?: { __typename?: 'TicketNeedsAdjudicationDetailsExtraDataNode', goldenRecords?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null, possibleDuplicate?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, birthDate: any, lastRegistrationDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null }, possibleDuplicate?: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, possibleDuplicates?: Array<{ __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null> | null, selectedIndividual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, activeIndividualsCount?: number | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, currency?: string | null, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, adminAreaTitle?: string | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, selectedIndividuals?: Array<{ __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, activeIndividualsCount?: number | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, currency?: string | null, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, adminAreaTitle?: string | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null> | null } | null, ticketNotes: { __typename?: 'TicketNoteNodeConnection', edges: Array<{ __typename?: 'TicketNoteNodeEdge', node?: { __typename?: 'TicketNoteNode', id: string, createdAt: any, updatedAt: any, description: string, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null } | null> }, programs?: Array<{ __typename?: 'ProgramNode', name: string, id: string } | null> | null, documentation?: Array<{ __typename?: 'GrievanceDocumentNode', id: string, createdAt: any, updatedAt: any, name?: string | null, fileSize?: number | null, contentType: string, filePath?: string | null, fileName?: string | null, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null> | null } | null } | null }; export type ReassignRoleGrievanceMutationVariables = Exact<{ grievanceTicketId: Scalars['ID']['input']; @@ -10194,7 +10194,7 @@ export type GrievanceTicketQueryVariables = Exact<{ }>; -export type GrievanceTicketQuery = { __typename?: 'Query', grievanceTicket?: { __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, category: number, consent: boolean, createdAt: any, updatedAt: any, description: string, language: string, admin?: string | null, area: string, adminUrl?: string | null, issueType?: number | null, priority?: number | null, urgency?: number | null, comments?: string | null, partner?: { __typename?: 'PartnerType', id: string, name: string } | null, businessArea: { __typename?: 'UserBusinessAreaNode', postponeDeduplication: boolean }, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, pCode?: string | null } | null, assignedTo?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, paymentRecord?: { __typename?: 'PaymentRecordAndPaymentNode', id?: string | null, caId?: string | null, deliveredQuantity?: number | null, entitlementQuantity?: number | null, objType?: string | null, parent?: { __typename?: 'CashPlanAndPaymentPlanNode', id?: string | null, unicefId?: string | null, objType?: string | null } | null, verification?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null, relatedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, linkedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, category: number, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, existingTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, category: number, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, addIndividualTicketDetails?: { __typename?: 'TicketAddIndividualDetailsNode', id: string, individualData?: any | null, approveStatus: boolean, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, individualDataUpdateTicketDetails?: { __typename?: 'TicketIndividualDataUpdateDetailsNode', id: string, individualData?: any | null, roleReassignData: any, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null } | null, householdDataUpdateTicketDetails?: { __typename?: 'TicketHouseholdDataUpdateDetailsNode', id: string, householdData?: any | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null } | null, deleteIndividualTicketDetails?: { __typename?: 'TicketDeleteIndividualDetailsNode', id: string, roleReassignData: any, approveStatus: boolean } | null, deleteHouseholdTicketDetails?: { __typename?: 'TicketDeleteHouseholdDetailsNode', id: string, approveStatus: boolean, reasonHousehold?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, systemFlaggingTicketDetails?: { __typename?: 'TicketSystemFlaggingDetailsNode', id: string, approveStatus: boolean, roleReassignData: any, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, fullName: string, birthDate: any, lastRegistrationDate: any, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, documentNumber: string, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> } }, sanctionListIndividual: { __typename?: 'SanctionListIndividualNode', id: string, fullName: string, referenceNumber: string, datesOfBirth: { __typename?: 'SanctionListIndividualDateOfBirthNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDateOfBirthNodeEdge', node?: { __typename?: 'SanctionListIndividualDateOfBirthNode', id: string, date: any } | null } | null> }, documents: { __typename?: 'SanctionListIndividualDocumentNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDocumentNodeEdge', node?: { __typename?: 'SanctionListIndividualDocumentNode', id: string, documentNumber: string, typeOfDocument: string } | null } | null> } } } | null, paymentVerificationTicketDetails?: { __typename?: 'TicketPaymentVerificationDetailsNode', id: string, newStatus?: TicketPaymentVerificationDetailsNewStatus | null, oldReceivedAmount?: number | null, newReceivedAmount?: number | null, approveStatus: boolean, paymentVerificationStatus: TicketPaymentVerificationDetailsPaymentVerificationStatus, hasMultiplePaymentVerifications?: boolean | null, paymentVerification?: { __typename?: 'PaymentVerificationNode', id: string, receivedAmount?: number | null } | null, paymentVerifications: { __typename?: 'PaymentVerificationNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationNodeEdge', node?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null> } } | null, needsAdjudicationTicketDetails?: { __typename?: 'TicketNeedsAdjudicationDetailsNode', id: string, hasDuplicatedDocument?: boolean | null, isMultipleDuplicatesVersion: boolean, roleReassignData: any, extraData?: { __typename?: 'TicketNeedsAdjudicationDetailsExtraDataNode', goldenRecords?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null, possibleDuplicate?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, birthDate: any, lastRegistrationDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null }, possibleDuplicate?: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, possibleDuplicates?: Array<{ __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null> | null, selectedIndividual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, activeIndividualsCount?: number | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, selectedIndividuals?: Array<{ __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, activeIndividualsCount?: number | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null> | null } | null, ticketNotes: { __typename?: 'TicketNoteNodeConnection', edges: Array<{ __typename?: 'TicketNoteNodeEdge', node?: { __typename?: 'TicketNoteNode', id: string, createdAt: any, updatedAt: any, description: string, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null } | null> }, programs?: Array<{ __typename?: 'ProgramNode', name: string, id: string } | null> | null, documentation?: Array<{ __typename?: 'GrievanceDocumentNode', id: string, createdAt: any, updatedAt: any, name?: string | null, fileSize?: number | null, contentType: string, filePath?: string | null, fileName?: string | null, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null> | null } | null }; +export type GrievanceTicketQuery = { __typename?: 'Query', grievanceTicket?: { __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, category: number, consent: boolean, createdAt: any, updatedAt: any, description: string, language: string, admin?: string | null, area: string, adminUrl?: string | null, issueType?: number | null, priority?: number | null, urgency?: number | null, comments?: string | null, partner?: { __typename?: 'PartnerType', id: string, name: string } | null, businessArea: { __typename?: 'UserBusinessAreaNode', postponeDeduplication: boolean }, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, pCode?: string | null } | null, assignedTo?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, paymentRecord?: { __typename?: 'PaymentRecordAndPaymentNode', id?: string | null, caId?: string | null, deliveredQuantity?: number | null, entitlementQuantity?: number | null, objType?: string | null, parent?: { __typename?: 'CashPlanAndPaymentPlanNode', id?: string | null, unicefId?: string | null, objType?: string | null } | null, verification?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null, relatedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, linkedTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, unicefId?: string | null, category: number, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, existingTickets?: Array<{ __typename?: 'GrievanceTicketNode', id: string, category: number, unicefId?: string | null, status: number, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null> | null, addIndividualTicketDetails?: { __typename?: 'TicketAddIndividualDetailsNode', id: string, individualData?: any | null, approveStatus: boolean, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, individualDataUpdateTicketDetails?: { __typename?: 'TicketIndividualDataUpdateDetailsNode', id: string, individualData?: any | null, roleReassignData: any, individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null } | null, householdDataUpdateTicketDetails?: { __typename?: 'TicketHouseholdDataUpdateDetailsNode', id: string, householdData?: any | null, household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null } | null, deleteIndividualTicketDetails?: { __typename?: 'TicketDeleteIndividualDetailsNode', id: string, roleReassignData: any, approveStatus: boolean } | null, deleteHouseholdTicketDetails?: { __typename?: 'TicketDeleteHouseholdDetailsNode', id: string, approveStatus: boolean, reasonHousehold?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } | null } | null, systemFlaggingTicketDetails?: { __typename?: 'TicketSystemFlaggingDetailsNode', id: string, approveStatus: boolean, roleReassignData: any, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, fullName: string, birthDate: any, lastRegistrationDate: any, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, documentNumber: string, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> } }, sanctionListIndividual: { __typename?: 'SanctionListIndividualNode', id: string, fullName: string, referenceNumber: string, datesOfBirth: { __typename?: 'SanctionListIndividualDateOfBirthNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDateOfBirthNodeEdge', node?: { __typename?: 'SanctionListIndividualDateOfBirthNode', id: string, date: any } | null } | null> }, documents: { __typename?: 'SanctionListIndividualDocumentNodeConnection', edges: Array<{ __typename?: 'SanctionListIndividualDocumentNodeEdge', node?: { __typename?: 'SanctionListIndividualDocumentNode', id: string, documentNumber: string, typeOfDocument: string } | null } | null> } } } | null, paymentVerificationTicketDetails?: { __typename?: 'TicketPaymentVerificationDetailsNode', id: string, newStatus?: TicketPaymentVerificationDetailsNewStatus | null, oldReceivedAmount?: number | null, newReceivedAmount?: number | null, approveStatus: boolean, paymentVerificationStatus: TicketPaymentVerificationDetailsPaymentVerificationStatus, hasMultiplePaymentVerifications?: boolean | null, paymentVerification?: { __typename?: 'PaymentVerificationNode', id: string, receivedAmount?: number | null } | null, paymentVerifications: { __typename?: 'PaymentVerificationNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationNodeEdge', node?: { __typename?: 'PaymentVerificationNode', id: string } | null } | null> } } | null, needsAdjudicationTicketDetails?: { __typename?: 'TicketNeedsAdjudicationDetailsNode', id: string, hasDuplicatedDocument?: boolean | null, isMultipleDuplicatesVersion: boolean, roleReassignData: any, extraData?: { __typename?: 'TicketNeedsAdjudicationDetailsExtraDataNode', goldenRecords?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null, possibleDuplicate?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, goldenRecordsIndividual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, birthDate: any, lastRegistrationDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null }, possibleDuplicate?: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null, possibleDuplicates?: Array<{ __typename?: 'IndividualNode', id: string, unicefId?: string | null, lastRegistrationDate: any, fullName: string, birthDate: any, sex: IndividualSex, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', unicefId?: string | null, id: string, village: string, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null } | null, deduplicationGoldenRecordResults?: Array<{ __typename?: 'DeduplicationResultNode', hitId?: string | null, proximityToScore?: number | null, score?: number | null } | null> | null } | null> | null, selectedIndividual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, activeIndividualsCount?: number | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, currency?: string | null, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, adminAreaTitle?: string | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null, selectedIndividuals?: Array<{ __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, activeIndividualsCount?: number | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, adminUrl?: string | null, createdAt: any, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, currency?: string | null, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unhcrId: string, adminAreaTitle?: string | null, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, individual: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null> | null } | null, ticketNotes: { __typename?: 'TicketNoteNodeConnection', edges: Array<{ __typename?: 'TicketNoteNodeEdge', node?: { __typename?: 'TicketNoteNode', id: string, createdAt: any, updatedAt: any, description: string, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null } | null> }, programs?: Array<{ __typename?: 'ProgramNode', name: string, id: string } | null> | null, documentation?: Array<{ __typename?: 'GrievanceDocumentNode', id: string, createdAt: any, updatedAt: any, name?: string | null, fileSize?: number | null, contentType: string, filePath?: string | null, fileName?: string | null, createdBy?: { __typename?: 'UserNode', id: string, firstName: string, lastName: string, email: string } | null } | null> | null } | null }; export type GrievanceTicketFlexFieldsQueryVariables = Exact<{ id: Scalars['ID']['input']; @@ -10267,7 +10267,7 @@ export type PaymentQueryVariables = Exact<{ }>; -export type PaymentQuery = { __typename?: 'Query', payment?: { __typename?: 'PaymentNode', id: string, unicefId?: string | null, distributionModality?: string | null, status: PaymentStatus, statusDate: any, snapshotCollectorBankName?: string | null, snapshotCollectorBankAccountNumber?: string | null, debitCardNumber?: string | null, debitCardIssuer?: string | null, currency: string, entitlementQuantity?: number | null, deliveredQuantity?: number | null, deliveryDate?: any | null, deliveredQuantityUsd?: number | null, deliveryType?: PaymentDeliveryType | null, transactionReferenceId?: string | null, additionalCollectorName?: string | null, additionalDocumentType?: string | null, additionalDocumentNumber?: string | null, reasonForUnsuccessfulPayment?: string | null, snapshotCollectorFullName?: string | null, adminUrl?: string | null, targetPopulation?: { __typename?: 'TargetPopulationNode', id: string, name: string } | null, sourcePayment?: { __typename?: 'PaymentNode', id: string, unicefId?: string | null } | null, verification?: { __typename?: 'PaymentVerificationNode', id: string, status: PaymentVerificationStatus, statusDate?: any | null, receivedAmount?: number | null, isManuallyEditable?: boolean | null, adminUrl?: string | null } | null, household: { __typename?: 'HouseholdNode', id: string, size?: number | null, status?: string | null, unicefId?: string | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, phoneNo: string, phoneNoAlternative: string, phoneNoValid?: boolean | null, phoneNoAlternativeValid?: boolean | null, fullName: string } }, collector: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, email: string, phoneNo: string, phoneNoValid?: boolean | null, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null }, parent: { __typename?: 'PaymentPlanNode', id: string, status: PaymentPlanStatus, isFollowUp: boolean, unicefId?: string | null, program: { __typename?: 'ProgramNode', id: string, name: string }, verificationPlans?: { __typename?: 'PaymentVerificationPlanNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationPlanNodeEdge', node?: { __typename?: 'PaymentVerificationPlanNode', id: string, status: PaymentVerificationPlanStatus, verificationChannel: PaymentVerificationPlanVerificationChannel } | null } | null> } | null }, serviceProvider?: { __typename?: 'FinancialServiceProviderNode', id: string, fullName?: string | null } | null } | null }; +export type PaymentQuery = { __typename?: 'Query', payment?: { __typename?: 'PaymentNode', id: string, unicefId?: string | null, distributionModality?: string | null, status: PaymentStatus, statusDate: any, snapshotCollectorBankName?: string | null, snapshotCollectorBankAccountNumber?: string | null, debitCardNumber?: string | null, debitCardIssuer?: string | null, currency: string, entitlementQuantity?: number | null, deliveredQuantity?: number | null, deliveryDate?: any | null, deliveredQuantityUsd?: number | null, deliveryType?: PaymentDeliveryType | null, transactionReferenceId?: string | null, additionalCollectorName?: string | null, additionalDocumentType?: string | null, additionalDocumentNumber?: string | null, reasonForUnsuccessfulPayment?: string | null, snapshotCollectorFullName?: string | null, adminUrl?: string | null, targetPopulation?: { __typename?: 'TargetPopulationNode', id: string, name: string } | null, sourcePayment?: { __typename?: 'PaymentNode', id: string, unicefId?: string | null } | null, verification?: { __typename?: 'PaymentVerificationNode', id: string, status: PaymentVerificationStatus, statusDate?: any | null, receivedAmount?: number | null, isManuallyEditable?: boolean | null, adminUrl?: string | null } | null, household: { __typename?: 'HouseholdNode', id: string, size?: number | null, status?: string | null, unicefId?: string | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, phoneNo: string, phoneNoAlternative: string, phoneNoValid?: boolean | null, phoneNoAlternativeValid?: boolean | null, fullName: string } }, collector: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, email: string, phoneNo: string, phoneNoValid?: boolean | null, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null }, parent: { __typename?: 'PaymentPlanNode', id: string, status: PaymentPlanStatus, isFollowUp: boolean, unicefId?: string | null, program: { __typename?: 'ProgramNode', id: string, name: string }, verificationPlans?: { __typename?: 'PaymentVerificationPlanNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationPlanNodeEdge', node?: { __typename?: 'PaymentVerificationPlanNode', id: string, status: PaymentVerificationPlanStatus, verificationChannel: PaymentVerificationPlanVerificationChannel } | null } | null> } | null }, serviceProvider?: { __typename?: 'FinancialServiceProviderNode', id: string, fullName?: string | null } | null } | null }; export type PaymentPlanQueryVariables = Exact<{ id: Scalars['ID']['input']; @@ -10353,7 +10353,7 @@ export type AllPaymentsForTableQueryVariables = Exact<{ }>; -export type AllPaymentsForTableQuery = { __typename?: 'Query', allPayments?: { __typename?: 'PaymentNodeConnection', totalCount?: number | null, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null }, edges: Array<{ __typename?: 'PaymentNodeEdge', cursor: string, node?: { __typename?: 'PaymentNode', id: string, unicefId?: string | null, status: PaymentStatus, entitlementQuantity?: number | null, entitlementQuantityUsd?: number | null, currency: string, deliveredQuantity?: number | null, deliveredQuantityUsd?: number | null, paymentPlanHardConflicted?: boolean | null, paymentPlanSoftConflicted?: boolean | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, size?: number | null, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null }, paymentPlanHardConflictedData?: Array<{ __typename?: 'PaymentConflictDataNode', paymentPlanUnicefId?: string | null, paymentPlanId?: string | null, paymentPlanStartDate?: string | null, paymentPlanEndDate?: string | null, paymentPlanStatus?: string | null, paymentId?: string | null, paymentUnicefId?: string | null } | null> | null, paymentPlanSoftConflictedData?: Array<{ __typename?: 'PaymentConflictDataNode', paymentPlanUnicefId?: string | null, paymentPlanId?: string | null, paymentPlanStartDate?: string | null, paymentPlanEndDate?: string | null, paymentPlanStatus?: string | null, paymentId?: string | null, paymentUnicefId?: string | null } | null> | null, collector: { __typename?: 'IndividualNode', id: string, fullName: string }, financialServiceProvider?: { __typename?: 'FinancialServiceProviderNode', id: string, name: string } | null } | null } | null> } | null }; +export type AllPaymentsForTableQuery = { __typename?: 'Query', allPayments?: { __typename?: 'PaymentNodeConnection', totalCount?: number | null, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null }, edges: Array<{ __typename?: 'PaymentNodeEdge', cursor: string, node?: { __typename?: 'PaymentNode', id: string, unicefId?: string | null, status: PaymentStatus, entitlementQuantity?: number | null, entitlementQuantityUsd?: number | null, currency: string, deliveredQuantity?: number | null, deliveredQuantityUsd?: number | null, paymentPlanHardConflicted?: boolean | null, paymentPlanSoftConflicted?: boolean | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, size?: number | null, admin2?: { __typename?: 'AreaNode', id: string, name: string } | null, individuals?: { __typename?: 'IndividualNodeConnection', edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string } | null } | null> } | null }, paymentPlanHardConflictedData?: Array<{ __typename?: 'PaymentConflictDataNode', paymentPlanUnicefId?: string | null, paymentPlanId?: string | null, paymentPlanStartDate?: string | null, paymentPlanEndDate?: string | null, paymentPlanStatus?: string | null, paymentId?: string | null, paymentUnicefId?: string | null } | null> | null, paymentPlanSoftConflictedData?: Array<{ __typename?: 'PaymentConflictDataNode', paymentPlanUnicefId?: string | null, paymentPlanId?: string | null, paymentPlanStartDate?: string | null, paymentPlanEndDate?: string | null, paymentPlanStatus?: string | null, paymentId?: string | null, paymentUnicefId?: string | null } | null> | null, collector: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string }, financialServiceProvider?: { __typename?: 'FinancialServiceProviderNode', id: string, name: string } | null } | null } | null> } | null }; export type CashPlanQueryVariables = Exact<{ id: Scalars['ID']['input']; @@ -10395,7 +10395,7 @@ export type PaymentRecordQueryVariables = Exact<{ }>; -export type PaymentRecordQuery = { __typename?: 'Query', paymentRecord?: { __typename?: 'PaymentRecordNode', id: string, status: PaymentRecordStatus, statusDate: any, caId?: string | null, caHashId?: any | null, registrationCaId?: string | null, fullName: string, distributionModality: string, totalPersonsCovered: number, currency: string, entitlementQuantity?: number | null, deliveredQuantity?: number | null, deliveryDate?: any | null, entitlementCardIssueDate?: any | null, entitlementCardNumber?: string | null, deliveredQuantityUsd?: number | null, deliveryType?: PaymentRecordDeliveryType | null, transactionReferenceId?: string | null, targetPopulation: { __typename?: 'TargetPopulationNode', id: string, name: string }, verification?: { __typename?: 'PaymentVerificationNode', id: string, status: PaymentVerificationStatus, statusDate?: any | null, receivedAmount?: number | null, isManuallyEditable?: boolean | null, adminUrl?: string | null } | null, household: { __typename?: 'HouseholdNode', id: string, size?: number | null, status?: string | null, unicefId?: string | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, phoneNo: string, phoneNoAlternative: string, phoneNoValid?: boolean | null, phoneNoAlternativeValid?: boolean | null } }, parent?: { __typename?: 'CashPlanNode', id: string, unicefId?: string | null, caId?: string | null, program: { __typename?: 'ProgramNode', id: string, name: string }, verificationPlans?: { __typename?: 'PaymentVerificationPlanNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationPlanNodeEdge', node?: { __typename?: 'PaymentVerificationPlanNode', id: string, status: PaymentVerificationPlanStatus, verificationChannel: PaymentVerificationPlanVerificationChannel } | null } | null> } | null } | null, serviceProvider: { __typename?: 'ServiceProviderNode', id: string, fullName?: string | null, shortName?: string | null } } | null }; +export type PaymentRecordQuery = { __typename?: 'Query', paymentRecord?: { __typename?: 'PaymentRecordNode', id: string, status: PaymentRecordStatus, statusDate: any, caId?: string | null, caHashId?: any | null, registrationCaId?: string | null, fullName: string, distributionModality: string, totalPersonsCovered: number, currency: string, entitlementQuantity?: number | null, deliveredQuantity?: number | null, deliveryDate?: any | null, entitlementCardIssueDate?: any | null, entitlementCardNumber?: string | null, deliveredQuantityUsd?: number | null, deliveryType?: PaymentRecordDeliveryType | null, transactionReferenceId?: string | null, targetPopulation: { __typename?: 'TargetPopulationNode', id: string, name: string }, verification?: { __typename?: 'PaymentVerificationNode', id: string, status: PaymentVerificationStatus, statusDate?: any | null, receivedAmount?: number | null, isManuallyEditable?: boolean | null, adminUrl?: string | null } | null, household: { __typename?: 'HouseholdNode', id: string, size?: number | null, status?: string | null, unicefId?: string | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, phoneNo: string, phoneNoAlternative: string, phoneNoValid?: boolean | null, phoneNoAlternativeValid?: boolean | null, fullName: string } }, parent?: { __typename?: 'CashPlanNode', id: string, unicefId?: string | null, caId?: string | null, program: { __typename?: 'ProgramNode', id: string, name: string }, verificationPlans?: { __typename?: 'PaymentVerificationPlanNodeConnection', edges: Array<{ __typename?: 'PaymentVerificationPlanNodeEdge', node?: { __typename?: 'PaymentVerificationPlanNode', id: string, status: PaymentVerificationPlanStatus, verificationChannel: PaymentVerificationPlanVerificationChannel } | null } | null> } | null } | null, serviceProvider: { __typename?: 'ServiceProviderNode', id: string, fullName?: string | null, shortName?: string | null } } | null }; export type AllPaymentVerificationLogEntriesQueryVariables = Exact<{ businessArea: Scalars['String']['input']; @@ -10427,7 +10427,7 @@ export type AllPaymentVerificationsQueryVariables = Exact<{ }>; -export type AllPaymentVerificationsQuery = { __typename?: 'Query', allPaymentVerifications?: { __typename?: 'PaymentVerificationNodeConnection', totalCount?: number | null, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null }, edges: Array<{ __typename?: 'PaymentVerificationNodeEdge', cursor: string, node?: { __typename?: 'PaymentVerificationNode', id: string, status: PaymentVerificationStatus, receivedAmount?: number | null, paymentVerificationPlan: { __typename?: 'PaymentVerificationPlanNode', id: string, unicefId?: string | null, verificationChannel: PaymentVerificationPlanVerificationChannel }, payment?: { __typename?: 'GenericPaymentNode', id?: string | null, unicefId?: string | null, deliveredQuantity?: number | null, currency?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, unicefId?: string | null, id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, familyName: string, phoneNo: string, phoneNoAlternative: string } } | null } | null } | null } | null> } | null }; +export type AllPaymentVerificationsQuery = { __typename?: 'Query', allPaymentVerifications?: { __typename?: 'PaymentVerificationNodeConnection', totalCount?: number | null, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null }, edges: Array<{ __typename?: 'PaymentVerificationNodeEdge', cursor: string, node?: { __typename?: 'PaymentVerificationNode', id: string, status: PaymentVerificationStatus, receivedAmount?: number | null, paymentVerificationPlan: { __typename?: 'PaymentVerificationPlanNode', id: string, unicefId?: string | null, verificationChannel: PaymentVerificationPlanVerificationChannel }, payment?: { __typename?: 'GenericPaymentNode', id?: string | null, unicefId?: string | null, deliveredQuantity?: number | null, currency?: string | null, household?: { __typename?: 'HouseholdNode', status?: string | null, unicefId?: string | null, id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, unicefId?: string | null, fullName: string, familyName: string, phoneNo: string, phoneNoAlternative: string } } | null } | null } | null } | null> } | null }; export type AllRapidProFlowsQueryVariables = Exact<{ businessAreaSlug: Scalars['String']['input']; @@ -10585,7 +10585,7 @@ export type HouseholdQueryVariables = Exact<{ }>; -export type HouseholdQuery = { __typename?: 'Query', household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null }; +export type HouseholdQuery = { __typename?: 'Query', household?: { __typename?: 'HouseholdNode', activeIndividualsCount?: number | null, countryOrigin?: string | null, country?: string | null, zipCode?: string | null, femaleAgeGroup05Count?: number | null, femaleAgeGroup611Count?: number | null, femaleAgeGroup1217Count?: number | null, femaleAgeGroup1859Count?: number | null, femaleAgeGroup60Count?: number | null, pregnantCount?: number | null, maleAgeGroup05Count?: number | null, maleAgeGroup611Count?: number | null, maleAgeGroup1217Count?: number | null, maleAgeGroup1859Count?: number | null, maleAgeGroup60Count?: number | null, femaleAgeGroup05DisabledCount?: number | null, femaleAgeGroup611DisabledCount?: number | null, femaleAgeGroup1217DisabledCount?: number | null, femaleAgeGroup1859DisabledCount?: number | null, femaleAgeGroup60DisabledCount?: number | null, maleAgeGroup05DisabledCount?: number | null, maleAgeGroup611DisabledCount?: number | null, maleAgeGroup1217DisabledCount?: number | null, maleAgeGroup1859DisabledCount?: number | null, maleAgeGroup60DisabledCount?: number | null, fchildHoh?: boolean | null, childHoh?: boolean | null, start?: any | null, deviceid: string, orgNameEnumerator: string, returnee?: boolean | null, address: string, nameEnumerator: string, lastSyncAt?: any | null, consentSharing?: Array | null, orgEnumerator: HouseholdOrgEnumerator, updatedAt: any, consent?: boolean | null, collectIndividualData: HouseholdCollectIndividualData, flexFields?: any | null, registrationId?: string | null, id: string, status?: string | null, adminUrl?: string | null, createdAt: any, residenceStatus?: string | null, maleChildrenCount?: number | null, femaleChildrenCount?: number | null, childrenDisabledCount?: number | null, size?: number | null, totalCashReceived?: any | null, totalCashReceivedUsd?: any | null, currency?: string | null, firstRegistrationDate: any, lastRegistrationDate: any, sanctionListPossibleMatch?: boolean | null, sanctionListConfirmedMatch?: boolean | null, hasDuplicates?: boolean | null, unicefId?: string | null, unhcrId: string, geopoint?: any | null, village: string, adminAreaTitle?: string | null, individuals?: { __typename?: 'IndividualNodeConnection', totalCount?: number | null, edges: Array<{ __typename?: 'IndividualNodeEdge', node?: { __typename?: 'IndividualNode', id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, email: string, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, countryIso3?: string | null, documentNumber: string, photo?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> }, household?: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null, status?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null } | null } | null> } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> }, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, paymentrecordSet: { __typename?: 'PaymentRecordNodeConnection', edges: Array<{ __typename?: 'PaymentRecordNodeEdge', node?: { __typename?: 'PaymentRecordNode', id: string, fullName: string, parent?: { __typename?: 'CashPlanNode', id: string, totalPersonsCovered: number, totalDeliveredQuantity?: number | null, assistanceMeasurement: string, program: { __typename?: 'ProgramNode', id: string, name: string } } | null } | null } | null> }, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin3?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin4?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, headOfHousehold: { __typename?: 'IndividualNode', id: string, fullName: string, givenName: string, familyName: string } } | null }; export type HouseholdChoiceDataQueryVariables = Exact<{ [key: string]: never; }>; @@ -10604,7 +10604,7 @@ export type IndividualQueryVariables = Exact<{ }>; -export type IndividualQuery = { __typename?: 'Query', individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, address: string, countryOrigin?: string | null, unicefId?: string | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null }; +export type IndividualQuery = { __typename?: 'Query', individual?: { __typename?: 'IndividualNode', givenName: string, familyName: string, estimatedBirthDate?: boolean | null, pregnant?: boolean | null, lastSyncAt?: any | null, deduplicationBatchStatus: IndividualDeduplicationBatchStatus, disability: IndividualDisability, importedIndividualId?: any | null, commsDisability: string, firstRegistrationDate: any, whoAnswersAltPhone: string, memoryDisability: string, middleName: string, whoAnswersPhone: string, phoneNoAlternative: string, phoneNoAlternativeValid?: boolean | null, email: string, hearingDisability: string, observedDisability?: Array | null, individualId: string, seeingDisability: string, physicalDisability: string, selfcareDisability: string, photo?: string | null, workStatus: string, enrolledInNutritionProgramme?: boolean | null, administrationOfRutf?: boolean | null, flexFields?: any | null, preferredLanguage?: string | null, paymentDeliveryPhoneNo?: string | null, id: string, age?: number | null, lastRegistrationDate: any, adminUrl?: string | null, createdAt: any, updatedAt: any, fullName: string, sex: IndividualSex, unicefId?: string | null, birthDate: any, maritalStatus: IndividualMaritalStatus, phoneNo: string, phoneNoValid?: boolean | null, sanctionListPossibleMatch: boolean, sanctionListConfirmedMatch: boolean, deduplicationGoldenRecordStatus: IndividualDeduplicationGoldenRecordStatus, sanctionListLastCheck?: any | null, role?: string | null, relationship?: IndividualRelationship | null, status?: string | null, paymentChannels?: Array<{ __typename?: 'BankAccountInfoNode', id: string, bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null> | null, documents: { __typename?: 'DocumentNodeConnection', edges: Array<{ __typename?: 'DocumentNodeEdge', node?: { __typename?: 'DocumentNode', id: string, country?: string | null, photo?: string | null, documentNumber: string, countryIso3?: string | null, type: { __typename?: 'DocumentTypeNode', label: string, key: string } } | null } | null> }, household?: { __typename?: 'HouseholdNode', status?: string | null, id: string, residenceStatus?: string | null, address: string, village: string, zipCode?: string | null, geopoint?: any | null, country?: string | null, countryOrigin?: string | null, unicefId?: string | null, totalCashReceivedUsd?: any | null, lastRegistrationDate: any, start?: any | null, firstRegistrationDate: any, registrationDataImport?: { __typename?: 'RegistrationDataImportNode', name: string, dataSource: RegistrationDataImportDataSource, importDate: any, importedBy?: { __typename?: 'UserNode', firstName: string, lastName: string, email: string, username: string } | null } | null, deliveredQuantities?: Array<{ __typename?: 'DeliveredQuantityNode', totalDeliveredQuantity?: any | null, currency?: string | null } | null> | null, adminArea?: { __typename?: 'AreaNode', id: string, name: string, level: number } | null, admin1?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, admin2?: { __typename?: 'AreaNode', id: string, name: string, level: number, pCode?: string | null } | null, programs: { __typename?: 'ProgramNodeConnection', edges: Array<{ __typename?: 'ProgramNodeEdge', node?: { __typename?: 'ProgramNode', id: string, name: string } | null } | null> } } | null, headingHousehold?: { __typename?: 'HouseholdNode', id: string, headOfHousehold: { __typename?: 'IndividualNode', id: string, givenName: string, familyName: string, fullName: string } } | null, householdsAndRoles: Array<{ __typename?: 'IndividualRoleInHouseholdNode', id: any, role?: IndividualRoleInHouseholdRole | null, household: { __typename?: 'HouseholdNode', id: string, unicefId?: string | null } }>, bankAccountInfo?: { __typename?: 'BankAccountInfoNode', bankName: string, bankAccountNumber: string, accountHolderName: string, bankBranchName: string } | null, identities: { __typename?: 'IndividualIdentityNodeConnection', edges: Array<{ __typename?: 'IndividualIdentityNodeEdge', node?: { __typename?: 'IndividualIdentityNode', id: string, partner?: string | null, country?: string | null, number: string } | null } | null> } } | null }; export type IndividualChoiceDataQueryVariables = Exact<{ [key: string]: never; }>; @@ -11130,6 +11130,10 @@ export const IndividualMinimalFragmentDoc = gql` } } } + totalCashReceivedUsd + lastRegistrationDate + start + firstRegistrationDate } } `; @@ -11186,10 +11190,30 @@ export const IndividualDetailedFragmentDoc = gql` enrolledInNutritionProgramme administrationOfRutf household { + registrationDataImport { + name + dataSource + importDate + importedBy { + firstName + lastName + email + username + } + } status id + residenceStatus address + village + zipCode + geopoint + country countryOrigin + deliveredQuantities { + totalDeliveredQuantity + currency + } adminArea { id name @@ -18188,6 +18212,7 @@ export const PaymentDocument = gql` unicefId headOfHousehold { id + unicefId phoneNo phoneNoAlternative phoneNoValid @@ -18984,6 +19009,15 @@ export const AllPaymentsForTableDocument = gql` id name } + individuals { + edges { + node { + id + unicefId + fullName + } + } + } } entitlementQuantity entitlementQuantityUsd @@ -19012,6 +19046,7 @@ export const AllPaymentsForTableDocument = gql` } collector { id + unicefId fullName } financialServiceProvider { @@ -19396,10 +19431,12 @@ export const PaymentRecordDocument = gql` unicefId headOfHousehold { id + unicefId phoneNo phoneNoAlternative phoneNoValid phoneNoAlternativeValid + fullName } } parent { @@ -19600,6 +19637,7 @@ export const AllPaymentVerificationsDocument = gql` id headOfHousehold { id + unicefId fullName familyName phoneNo diff --git a/frontend/src/apollo/fragments/IndividualFragments.ts b/frontend/src/apollo/fragments/IndividualFragments.ts index e6fe557b68..dcb2c2959f 100644 --- a/frontend/src/apollo/fragments/IndividualFragments.ts +++ b/frontend/src/apollo/fragments/IndividualFragments.ts @@ -72,6 +72,10 @@ export const individualMinimal = gql` } } } + totalCashReceivedUsd + lastRegistrationDate + start + firstRegistrationDate } } `; @@ -129,10 +133,30 @@ export const individualDetailed = gql` enrolledInNutritionProgramme administrationOfRutf household { + registrationDataImport { + name + dataSource + importDate + importedBy { + firstName + lastName + email + username + } + } status id + residenceStatus address + village + zipCode + geopoint + country countryOrigin + deliveredQuantities { + totalDeliveredQuantity + currency + } adminArea { id name diff --git a/frontend/src/apollo/queries/paymentmodule/Payment.ts b/frontend/src/apollo/queries/paymentmodule/Payment.ts index 9711020cab..7b16b50c4a 100644 --- a/frontend/src/apollo/queries/paymentmodule/Payment.ts +++ b/frontend/src/apollo/queries/paymentmodule/Payment.ts @@ -39,6 +39,7 @@ export const Payment = gql` unicefId headOfHousehold { id + unicefId phoneNo phoneNoAlternative phoneNoValid diff --git a/frontend/src/apollo/queries/payments/AllPaymentsForTable.ts b/frontend/src/apollo/queries/payments/AllPaymentsForTable.ts index b432b9ae2d..71f1cee9b7 100644 --- a/frontend/src/apollo/queries/payments/AllPaymentsForTable.ts +++ b/frontend/src/apollo/queries/payments/AllPaymentsForTable.ts @@ -40,6 +40,15 @@ export const AllPaymentsForTable = gql` id name } + individuals { + edges { + node { + id + unicefId + fullName + } + } + } } entitlementQuantity entitlementQuantityUsd @@ -68,6 +77,7 @@ export const AllPaymentsForTable = gql` } collector { id + unicefId fullName } financialServiceProvider { diff --git a/frontend/src/apollo/queries/payments/PaymentRecord.ts b/frontend/src/apollo/queries/payments/PaymentRecord.ts index b03185c93d..c1c0f5c29e 100644 --- a/frontend/src/apollo/queries/payments/PaymentRecord.ts +++ b/frontend/src/apollo/queries/payments/PaymentRecord.ts @@ -37,10 +37,12 @@ export const PAYMENT_RECORD_QUERY = gql` unicefId headOfHousehold { id + unicefId phoneNo phoneNoAlternative phoneNoValid phoneNoAlternativeValid + fullName } } parent { diff --git a/frontend/src/apollo/queries/payments/verification/AllPaymentVerifications.ts b/frontend/src/apollo/queries/payments/verification/AllPaymentVerifications.ts index 008586441e..da63ceba93 100644 --- a/frontend/src/apollo/queries/payments/verification/AllPaymentVerifications.ts +++ b/frontend/src/apollo/queries/payments/verification/AllPaymentVerifications.ts @@ -54,6 +54,7 @@ export const AllPaymentVerifications = gql` id headOfHousehold { id + unicefId fullName familyName phoneNo diff --git a/frontend/src/components/core/Drawer/menuItems.tsx b/frontend/src/components/core/Drawer/menuItems.tsx index e702744f9a..002523cb86 100644 --- a/frontend/src/components/core/Drawer/menuItems.tsx +++ b/frontend/src/components/core/Drawer/menuItems.tsx @@ -35,12 +35,11 @@ export type MenuItem = { flag?: string; external?: boolean; scopes: string[]; - isSocialWorker?: boolean + isSocialWorker?: boolean; }; export const SCOPE_PROGRAM = 'SCOPE_PROGRAM'; export const SCOPE_ALL_PROGRAMS = 'SCOPE_ALL_PROGRAMS'; - export const menuItems: MenuItem[] = [ { name: 'Country Dashboard', @@ -55,16 +54,6 @@ export const menuItems: MenuItem[] = [ href: '/registration-data-import', selectedRegexp: /^\/registration-data-import.*$/, icon: , - isSocialWorker: false, - permissions: [PERMISSIONS.RDI_VIEW_DETAILS, PERMISSIONS.RDI_VIEW_LIST], - scopes: [SCOPE_PROGRAM], - }, - { - name: 'Registration Data Import', - href: '/registration-data-import-for-people', - selectedRegexp: /^\/registration-data-import.*$/, - icon: , - isSocialWorker: true, permissions: [PERMISSIONS.RDI_VIEW_DETAILS, PERMISSIONS.RDI_VIEW_LIST], scopes: [SCOPE_PROGRAM], }, diff --git a/frontend/src/components/core/Table/TableComponent.tsx b/frontend/src/components/core/Table/TableComponent.tsx index 87c765640d..2ae099617a 100644 --- a/frontend/src/components/core/Table/TableComponent.tsx +++ b/frontend/src/components/core/Table/TableComponent.tsx @@ -27,6 +27,7 @@ const Root = styled('div')` const Paper = styled(MuiPaper)` width: 100%; margin-bottom: 8px; + overflow: clip; `; const Table = styled(MuiTable)` diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.tsx b/frontend/src/components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.tsx index c6dd72e03c..44ac95c41f 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.tsx +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.tsx @@ -1,26 +1,14 @@ import Step from '@mui/material/Step'; import StepLabel from '@mui/material/StepLabel'; import Stepper from '@mui/material/Stepper'; -import CancelIcon from '@mui/icons-material/Cancel'; import * as React from 'react'; import { useTranslation } from 'react-i18next'; -import styled from 'styled-components'; import { PaymentPlanQuery } from '@generated/graphql'; -import { StepIconProps } from '@mui/material'; - -const StyledCancelIcon = styled(CancelIcon)` - color: #e90202; -`; interface AcceptanceProcessStepperProps { acceptanceProcess: PaymentPlanQuery['paymentPlan']['approvalProcess']['edges'][0]['node']; } -const StepIconWrapper: React.FC = (props) => { - const { error } = props; - return error ? : null; -}; - export function AcceptanceProcessStepper({ acceptanceProcess, }: AcceptanceProcessStepperProps): React.ReactElement { @@ -70,12 +58,7 @@ export function AcceptanceProcessStepper({ {steps.map((step) => ( - - {step.name} - + {step.name} ))} diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/__snapshots__/AcceptanceProcessRow.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/__snapshots__/AcceptanceProcessRow.test.tsx.snap index efb0d6f90b..7a81fdfaba 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/__snapshots__/AcceptanceProcessRow.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/__snapshots__/AcceptanceProcessRow.test.tsx.snap @@ -3,7 +3,7 @@ exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow should render 1`] = `
Sent for approval by Root Rootkowski on @@ -164,7 +164,7 @@ exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/Acceptanc
on
diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/FspSection/FspSection.tsx b/frontend/src/components/paymentmodule/PaymentPlanDetails/FspSection/FspSection.tsx index 6c90ee58d9..f860d4bccc 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/FspSection/FspSection.tsx +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/FspSection/FspSection.tsx @@ -14,10 +14,10 @@ interface FspSectionProps { paymentPlan: PaymentPlanQuery['paymentPlan']; } -export function FspSection({ +export const FspSection = ({ baseUrl, paymentPlan, -}: FspSectionProps): React.ReactElement { +}: FspSectionProps): React.ReactElement => { const { t } = useTranslation(); const { id } = useParams(); const { isActiveProgram } = useProgramContext(); @@ -64,7 +64,7 @@ export function FspSection({ {deliveryMechanisms.map((el) => ( <> - + {el.chosenConfiguration && ( @@ -108,4 +108,4 @@ export function FspSection({ ); -} +}; diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/FspSection/__snapshots__/FspSection.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/FspSection/__snapshots__/FspSection.test.tsx.snap index ab4b7cab8d..2e2f368f76 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/FspSection/__snapshots__/FspSection.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/FspSection/__snapshots__/FspSection.test.tsx.snap @@ -17,12 +17,14 @@ exports[`components/paymentmodule/PaymentPlanDetails/FspSection should render Ed FSPs Edit FSP +
diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/__snapshots__/ImportXlsxPaymentPlanPaymentList.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/__snapshots__/ImportXlsxPaymentPlanPaymentList.test.tsx.snap index ab32a0dd96..8a98fe1402 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/__snapshots__/ImportXlsxPaymentPlanPaymentList.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/__snapshots__/ImportXlsxPaymentPlanPaymentList.test.tsx.snap @@ -6,10 +6,9 @@ exports[`components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymen class="MuiBox-root css-0" >
diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/__snapshots__/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/__snapshots__/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx.snap index 1cd192e7de..23514352ac 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/__snapshots__/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/__snapshots__/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx.snap @@ -8,10 +8,9 @@ exports[`components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymen class="MuiBox-root css-0" > diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/AcceptedPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/AcceptedPaymentPlanHeaderButtons.test.tsx.snap index d98b82a59c..5f30b8cb0e 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/AcceptedPaymentPlanHeaderButtons.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/AcceptedPaymentPlanHeaderButtons.test.tsx.snap @@ -110,10 +110,9 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/He class="MuiBox-root css-1ynyhby" >
diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InAuthorizationPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InAuthorizationPaymentPlanHeaderButtons.test.tsx.snap index 3af7a42e17..c888f0a2cb 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InAuthorizationPaymentPlanHeaderButtons.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InAuthorizationPaymentPlanHeaderButtons.test.tsx.snap @@ -23,13 +23,15 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/He class="MuiBox-root css-hpgf8j" > diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InReviewPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InReviewPaymentPlanHeaderButtons.test.tsx.snap index a0cfbf55b6..dccbd8e964 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InReviewPaymentPlanHeaderButtons.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InReviewPaymentPlanHeaderButtons.test.tsx.snap @@ -23,13 +23,15 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/He class="MuiBox-root css-hpgf8j" > diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/LockedPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/LockedPaymentPlanHeaderButtons.test.tsx.snap index ff59c49adc..39fd92a70f 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/LockedPaymentPlanHeaderButtons.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/LockedPaymentPlanHeaderButtons.test.tsx.snap @@ -9,13 +9,15 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/He class="MuiBox-root css-hpgf8j" > diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/OpenPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/OpenPaymentPlanHeaderButtons.test.tsx.snap index 669d84c029..2653fdf16b 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/OpenPaymentPlanHeaderButtons.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/OpenPaymentPlanHeaderButtons.test.tsx.snap @@ -9,9 +9,8 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/He class="MuiBox-root css-hpgf8j" >
diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/AuthorizePaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/AuthorizePaymentPlan.test.tsx.snap index 4198408cbb..37fd359063 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/AuthorizePaymentPlan.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/AuthorizePaymentPlan.test.tsx.snap @@ -6,13 +6,15 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/Au class="MuiBox-root css-hpgf8j" > diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/DeletePaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/DeletePaymentPlan.test.tsx.snap index 2f3eabf90d..11626906a4 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/DeletePaymentPlan.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/DeletePaymentPlan.test.tsx.snap @@ -6,9 +6,8 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/De class="MuiBox-root css-hpgf8j" > diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/MarkAsReleasedPaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/MarkAsReleasedPaymentPlan.test.tsx.snap index ec84606438..1e7d743b4c 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/MarkAsReleasedPaymentPlan.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/MarkAsReleasedPaymentPlan.test.tsx.snap @@ -6,13 +6,15 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/Ma class="MuiBox-root css-hpgf8j" > diff --git a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/PaymentPlanDetailsHeader.test.tsx.snap b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/PaymentPlanDetailsHeader.test.tsx.snap index ec84606438..1e7d743b4c 100644 --- a/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/PaymentPlanDetailsHeader.test.tsx.snap +++ b/frontend/src/components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/PaymentPlanDetailsHeader.test.tsx.snap @@ -6,13 +6,15 @@ exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/Ma class="MuiBox-root css-hpgf8j" > diff --git a/frontend/src/components/paymentmodulepeople/CreateFollowUpPaymentPlan/CreateFollowUpPaymentPlan.tsx b/frontend/src/components/paymentmodulepeople/CreateFollowUpPaymentPlan/CreateFollowUpPaymentPlan.tsx new file mode 100644 index 0000000000..76ec71820e --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateFollowUpPaymentPlan/CreateFollowUpPaymentPlan.tsx @@ -0,0 +1,267 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Grid, + Typography, +} from '@mui/material'; +import CalendarTodayRoundedIcon from '@mui/icons-material/CalendarTodayRounded'; +import { Field, Form, Formik } from 'formik'; +import moment from 'moment'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import * as Yup from 'yup'; +import { useNavigate } from 'react-router-dom'; +import { + PaymentPlanQuery, + useCreateFollowUpPpMutation, +} from '@generated/graphql'; +import { PERMISSIONS, hasPermissions } from '../../../config/permissions'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { usePermissions } from '@hooks/usePermissions'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { FormikDateField } from '@shared/Formik/FormikDateField'; +import { today, tomorrow } from '@utils/utils'; +import { DividerLine } from '@core/DividerLine'; +import { FieldBorder } from '@core/FieldBorder'; +import { GreyText } from '@core/GreyText'; +import { LabelizedField } from '@core/LabelizedField'; +import { LoadingButton } from '@core/LoadingButton'; +import { useProgramContext } from '../../../programContext'; + +export interface CreateFollowUpPaymentPlanProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function CreateFollowUpPaymentPlan({ + paymentPlan, +}: CreateFollowUpPaymentPlanProps): React.ReactElement { + const navigate = useNavigate(); + const { t } = useTranslation(); + const [dialogOpen, setDialogOpen] = useState(false); + const { baseUrl } = useBaseUrl(); + const permissions = usePermissions(); + const [mutate, { loading }] = useCreateFollowUpPpMutation(); + const { isActiveProgram } = useProgramContext(); + const { showMessage } = useSnackbar(); + + const { id, totalWithdrawnHouseholdsCount, unsuccessfulPaymentsCount } = + paymentPlan; + + if (permissions === null) return null; + + const validationSchema = Yup.object().shape({ + dispersionStartDate: Yup.date().required( + t('Dispersion Start Date is required'), + ), + dispersionEndDate: Yup.date() + .required(t('Dispersion End Date is required')) + .min(today, t('Dispersion End Date cannot be in the past')) + .when( + 'dispersionStartDate', + (dispersionStartDate: any, schema: Yup.DateSchema) => + dispersionStartDate + ? schema.min( + new Date(dispersionStartDate), + `${t('Dispersion End Date has to be greater than')} ${moment( + dispersionStartDate, + ).format('YYYY-MM-DD')}`, + ) + : schema, + ), + }); + + type FormValues = Yup.InferType; + const initialValues: FormValues = { + dispersionStartDate: null, + dispersionEndDate: null, + }; + + const handleSubmit = async (values: FormValues): Promise => { + try { + const res = await mutate({ + variables: { + paymentPlanId: id, + dispersionStartDate: values.dispersionStartDate, + dispersionEndDate: values.dispersionEndDate, + }, + }); + setDialogOpen(false); + showMessage(t('Payment Plan Created')); + navigate( + `/${baseUrl}/payment-module/followup-payment-plans/${res.data.createFollowUpPaymentPlan.paymentPlan.id}`, + ); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + return ( + + {({ submitForm, values }) => ( +
+ + + + setDialogOpen(false)} + scroll="paper" + maxWidth="md" + > + + {t('Create Follow-up Payment Plan')} + + + + + + {unsuccessfulPaymentsCount === 0 && ( + + + + {t( + 'Follow-up Payment Plan might be started just for unsuccessful payments', + )} + + + + )} + {totalWithdrawnHouseholdsCount > 0 && ( + + + + {t( + 'Withdrawn Household cannot be added into follow-up payment plan', + )} + + + + )} + + + + + + {t('Main Payment Plan Details')} + + + + + {/* //TODO: Figure it out */} + {/* + + {t('Follow-up Payment Plan Details')} + + */} + + + {unsuccessfulPaymentsCount} + + + {/* + + + + */} + + + {totalWithdrawnHouseholdsCount} + + + + + + + + {t('Set the Dispersion Dates')} + + + + + } + data-cy="input-dispersion-start-date" + tooltip={t( + 'The first day from which payments could be delivered.', + )} + /> + + + + } + data-cy="input-dispersion-end-date" + tooltip={t( + 'The last day on which payments could be delivered.', + )} + /> + + + + + + + + + + {t('Save')} + + + + +
+ )} +
+ ); +} diff --git a/frontend/src/components/paymentmodulepeople/CreateFollowUpPaymentPlan/index.tsx b/frontend/src/components/paymentmodulepeople/CreateFollowUpPaymentPlan/index.tsx new file mode 100644 index 0000000000..d7e8301ae6 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateFollowUpPaymentPlan/index.tsx @@ -0,0 +1 @@ +export { CreateFollowUpPaymentPlan } from './CreateFollowUpPaymentPlan'; diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/CreatePaymentPlanHeader.test.tsx b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/CreatePaymentPlanHeader.test.tsx new file mode 100644 index 0000000000..3fd618a996 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/CreatePaymentPlanHeader.test.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { render } from '../../../../testUtils/testUtils'; +import { CreatePaymentPlanHeader } from './CreatePaymentPlanHeader'; +import { fakeBaseUrl } from '../../../../../fixtures/core/fakeBaseUrl'; + +describe('components/paymentmodule/CreatePaymentPlanHeader', () => { + it('should render', () => { + const { container } = render( + Promise.resolve()} + baseUrl={fakeBaseUrl} + permissions={[PERMISSIONS.PM_VIEW_LIST]} + loadingCreate={false} + />, + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/CreatePaymentPlanHeader.tsx b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/CreatePaymentPlanHeader.tsx new file mode 100644 index 0000000000..ee3b47ddc6 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/CreatePaymentPlanHeader.tsx @@ -0,0 +1,59 @@ +import { Box, Button } from '@mui/material'; +import { Link } from 'react-router-dom'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { BreadCrumbsItem } from '@core/BreadCrumbs'; +import { PageHeader } from '@core/PageHeader'; +import { LoadingButton } from '@core/LoadingButton'; + +interface CreatePaymentPlanHeaderProps { + handleSubmit: () => Promise; + baseUrl: string; + permissions: string[]; + loadingCreate: boolean; +} + +export function CreatePaymentPlanHeader({ + handleSubmit, + baseUrl, + permissions, + loadingCreate, +}: CreatePaymentPlanHeaderProps): React.ReactElement { + const { t } = useTranslation(); + + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/`, + }, + ]; + + return ( + + + + + + + {t('Save')} + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/__snapshots__/CreatePaymentPlanHeader.test.tsx.snap b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/__snapshots__/CreatePaymentPlanHeader.test.tsx.snap new file mode 100644 index 0000000000..3728f6561e --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/__snapshots__/CreatePaymentPlanHeader.test.tsx.snap @@ -0,0 +1,103 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/CreatePaymentPlanHeader should render 1`] = ` +
+
+
+
+ +
+
+
+ +
+
+
+ New Payment Plan +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/index.tsx b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/index.tsx new file mode 100644 index 0000000000..f9d44b6eaf --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/CreatePaymentPlanHeader/index.tsx @@ -0,0 +1 @@ +export { CreatePaymentPlanHeader } from './CreatePaymentPlanHeader'; diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanParameters/PaymentPlanParameters.tsx b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanParameters/PaymentPlanParameters.tsx new file mode 100644 index 0000000000..781ef5bc1b --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanParameters/PaymentPlanParameters.tsx @@ -0,0 +1,124 @@ +import { OverviewContainer } from '@core/OverviewContainer'; +import { Title } from '@core/Title'; +import { useTargetPopulationLazyQuery } from '@generated/graphql'; +import { Grid, Typography } from '@mui/material'; +import { FormikCurrencyAutocomplete } from '@shared/Formik/FormikCurrencyAutocomplete'; +import { FormikDateField } from '@shared/Formik/FormikDateField'; +import { tomorrow } from '@utils/utils'; +import { Field } from 'formik'; +import * as React from 'react'; +import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { PaperContainer } from '../../../targeting/PaperContainer'; +import { CalendarTodayRounded } from '@mui/icons-material'; + +interface PaymentPlanParametersProps { + values; + paymentPlan?; +} + +export const PaymentPlanParameters = ({ + values, + paymentPlan, +}: PaymentPlanParametersProps): React.ReactElement => { + const { t } = useTranslation(); + const [loadTargetPopulation, { data, loading }] = + useTargetPopulationLazyQuery(); + + useEffect(() => { + if (values.targetingId) { + loadTargetPopulation({ + variables: { + id: values.targetingId, + }, + }); + } + }, [values.targetingId, loadTargetPopulation]); + + return ( + + + <Typography variant="h6">{t('Parameters')}</Typography> + + + + + } + data-cy="input-start-date" + tooltip={t( + 'The first day of the period intended to be covered by the payment plan. Note that individuals/households cannot be paid twice from the same programme within this period.', + )} + /> + + + } + data-cy="input-end-date" + tooltip={t( + 'The last day of the period intended to be covered by the payment plan. Note that individuals/households cannot be paid twice from the same programme within this period.', + )} + /> + + + + + + } + data-cy="input-dispersion-start-date" + tooltip={t( + 'The first day from which payments could be delivered.', + )} + /> + + + } + data-cy="input-dispersion-end-date" + tooltip={t('The last day on which payments could be delivered.')} + /> + + + + + ); +}; diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanParameters/index.tsx b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanParameters/index.tsx new file mode 100644 index 0000000000..170b75cdd1 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanParameters/index.tsx @@ -0,0 +1 @@ +export { PaymentPlanParameters } from './PaymentPlanParameters'; diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting.test.tsx b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting.test.tsx new file mode 100644 index 0000000000..fc841d4be1 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting.test.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import { fakeAllTargetPopulation } from '../../../../../fixtures/targeting/fakeAllTargetPopulation'; +import { render } from '../../../../testUtils/testUtils'; +import { PaymentPlanTargeting } from './PaymentPlanTargeting'; + +describe('components/paymentmodule/PaymentPlanTargeting', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting.tsx b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting.tsx new file mode 100644 index 0000000000..6e4d16f8f7 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting.tsx @@ -0,0 +1,68 @@ +import { Box, Grid, Typography } from '@mui/material'; +import styled from 'styled-components'; +import { Field } from 'formik'; +import get from 'lodash/get'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { FormikSelectField } from '@shared/Formik/FormikSelectField'; +import { AllTargetPopulationsQuery } from '@generated/graphql'; +import { GreyText } from '@core/GreyText'; +import { LoadingComponent } from '@core/LoadingComponent'; +import { OverviewContainer } from '@core/OverviewContainer'; +import { Title } from '@core/Title'; +import { PaperContainer } from '../../../targeting/PaperContainer'; + +const StyledBox = styled(Box)` + width: 100%; +`; + +export function PaymentPlanTargeting({ + allTargetPopulations, + loading, + disabled, +}: { + allTargetPopulations: AllTargetPopulationsQuery; + loading: boolean; + disabled?: boolean; +}): React.ReactElement { + const { t } = useTranslation(); + if (loading) return ; + + const allTargetPopulationsEdges = get( + allTargetPopulations, + 'allTargetPopulation.edges', + [], + ); + const mappedTargetPopulations = allTargetPopulationsEdges.map((edge) => ({ + name: edge.node.name, + value: edge.node.id, + })); + + return ( + + + <Typography variant="h6">{t('Targeting')}</Typography> + + + + {t('Select Target Population')} + + + + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/__snapshots__/PaymentPlanTargeting.test.tsx.snap b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/__snapshots__/PaymentPlanTargeting.test.tsx.snap new file mode 100644 index 0000000000..41a68c3f9e --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/__snapshots__/PaymentPlanTargeting.test.tsx.snap @@ -0,0 +1,118 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanTargeting should render 1`] = ` +
+
+
+
+ Targeting +
+
+
+
+
+ Select Target Population +
+
+
+
+ +
+ + + + +
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/index.tsx b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/index.tsx new file mode 100644 index 0000000000..a1341e5f4c --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreatePaymentPlan/PaymentPlanTargeting/index.tsx @@ -0,0 +1 @@ +export { PaymentPlanTargeting } from './PaymentPlanTargeting'; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/CreateSetUpFspHeader.test.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/CreateSetUpFspHeader.test.tsx new file mode 100644 index 0000000000..655d3b6d15 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/CreateSetUpFspHeader.test.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { render } from '../../../../testUtils/testUtils'; +import { CreateSetUpFspHeader } from './CreateSetUpFspHeader'; +import { fakeBaseUrl } from '../../../../../fixtures/core/fakeBaseUrl'; + +describe('components/paymentmodule/CreateSetUpFsp/CreateSetUpFspHeader', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/CreateSetUpFspHeader.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/CreateSetUpFspHeader.tsx new file mode 100644 index 0000000000..288e2b1491 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/CreateSetUpFspHeader.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useParams, useLocation } from 'react-router-dom'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { BreadCrumbsItem } from '@core/BreadCrumbs'; +import { PageHeader } from '@core/PageHeader'; + +interface CreateSetUpFspHeaderProps { + baseUrl: string; + permissions: string[]; +} + +export function CreateSetUpFspHeader({ + baseUrl, + permissions, +}: CreateSetUpFspHeaderProps): React.ReactElement { + const location = useLocation(); + const { t } = useTranslation(); + const { id } = useParams(); + const isFollowUp = location.pathname.indexOf('followup') !== -1; + + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/${ + isFollowUp ? 'followup-payment-plans' : 'payment-plans' + }/${id}`, + }, + ]; + + return ( + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/__snapshots__/CreateSetUpFspHeader.test.tsx.snap b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/__snapshots__/CreateSetUpFspHeader.test.tsx.snap new file mode 100644 index 0000000000..1e89a32368 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/__snapshots__/CreateSetUpFspHeader.test.tsx.snap @@ -0,0 +1,73 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/CreateSetUpFsp/CreateSetUpFspHeader should render 1`] = ` +
+
+
+
+ +
+
+
+ +
+
+
+ Set up FSP +
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/index.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/index.tsx new file mode 100644 index 0000000000..09d01af2b8 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/CreateSetUpFspHeader/index.tsx @@ -0,0 +1 @@ +export { CreateSetUpFspHeader } from './CreateSetUpFspHeader'; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/DeliveryMechanismRow.test.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/DeliveryMechanismRow.test.tsx new file mode 100644 index 0000000000..2d0aa40c41 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/DeliveryMechanismRow.test.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import { render } from '../../../../testUtils/testUtils'; +import { fakeDeliveryMechanisms } from '../../../../../fixtures/paymentmodule/fakeDeliveryMechanisms'; +import { fakeFspsData } from '../../../../../fixtures/paymentmodule/fakeFspsData'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { DeliveryMechanismRow } from './DeliveryMechanismRow'; + +describe('components/paymentmodule/CreateSetUpFsp/DeliveryMechanismRow', () => { + it('should render', () => { + const values = { + deliveryMechanisms: [ + { + deliveryMechanism: '', + fsp: '', + chosenConfiguration: '', + }, + ], + }; + const mapping = fakeFspsData?.availableFspsForDeliveryMechanisms[0]; + const mappedFsps = mapping?.fsps.map((el) => ({ + name: el.name, + value: el.id, + })); + const deliveryMechanismsChoices = + fakeDeliveryMechanisms.allDeliveryMechanisms.map((el) => ({ + name: el.name, + value: el.value, + })); + + const { container } = render( + {}} + />, + ); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/DeliveryMechanismRow.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/DeliveryMechanismRow.tsx new file mode 100644 index 0000000000..0788048ed6 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/DeliveryMechanismRow.tsx @@ -0,0 +1,115 @@ +import { Box, Grid } from '@mui/material'; +import { Field } from 'formik'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { FormikSelectField } from '@shared/Formik/FormikSelectField'; +import { LabelizedField } from '@core/LabelizedField'; + +interface DeliveryMechanismRowProps { + index: number; + step: number; + values; + arrayHelpers; + deliveryMechanismsChoices; + fspsChoices; + permissions: string[]; + setFieldValue: (name, value) => void; +} + +export function DeliveryMechanismRow({ + index, + step, + values, + deliveryMechanismsChoices, + fspsChoices, + setFieldValue, +}: DeliveryMechanismRowProps): React.ReactElement { + const { t } = useTranslation(); + const chosenFsp = values.deliveryMechanisms[index].fsp; + + const handleFspChange = (e): void => { + setFieldValue(`deliveryMechanisms[${index}].chosenConfiguration`, ''); + setFieldValue(`deliveryMechanisms[${index}].fsp`, e.target.value); + }; + + return ( + + + + + + {/* {index + 1} */} + {step === 0 && deliveryMechanismsChoices && ( + + )} + {step === 1 && ( + + )} + + + + {step === 1 && fspsChoices && ( + <> + + + handleFspChange(e)} + /> + + + {fspsChoices.find((el) => el.value == chosenFsp)?.configurations + .length > 0 && ( + + + el.value == chosenFsp) + ?.configurations + ? fspsChoices + .find((el) => el.value == chosenFsp) + ?.configurations.map((el) => ({ + name: el.label, + value: el.key, + })) + : [] + } + /> + + + )} + + )} + {/* {step === 0 && values.deliveryMechanisms[index].deliveryMechanism && ( + + {hasPermissions( + PERMISSIONS.PM_LOCK_AND_UNLOCK_FSP, + permissions, + ) ? ( + arrayHelpers.remove(index)}> + + + ) : null} + + )} */} + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/__snapshots__/DeliveryMechanismRow.test.tsx.snap b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/__snapshots__/DeliveryMechanismRow.test.tsx.snap new file mode 100644 index 0000000000..2460961dc4 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/__snapshots__/DeliveryMechanismRow.test.tsx.snap @@ -0,0 +1,91 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/CreateSetUpFsp/DeliveryMechanismRow should render 1`] = ` +
+
+
+
+
+
+
+ +
+ + + + +
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/index.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/index.tsx new file mode 100644 index 0000000000..c6bd3dadb9 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/DeliveryMechanismRow/index.tsx @@ -0,0 +1 @@ +export { DeliveryMechanismRow } from './DeliveryMechanismRow'; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/SetUpFspButtonActions.test.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/SetUpFspButtonActions.test.tsx new file mode 100644 index 0000000000..34ab26c331 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/SetUpFspButtonActions.test.tsx @@ -0,0 +1,26 @@ +import { act } from '@testing-library/react'; +import * as React from 'react'; +import wait from 'waait'; +import { render } from '../../../../testUtils/testUtils'; +import { SetUpFspButtonActions } from './SetUpFspButtonActions'; +import { fakeBaseUrl } from '../../../../../fixtures/core/fakeBaseUrl'; + +describe('components/paymentmodule/CreateSetUpFsp/SetUpFspButtonActions', () => { + it('should render', async () => { + const step = 0; + const setStep = jest.fn(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const submitForm = (_values): Promise => Promise.resolve(); + const { container } = render( + , + ); + await act(() => wait(0)); // wait for response + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/SetUpFspButtonActions.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/SetUpFspButtonActions.tsx new file mode 100644 index 0000000000..ab32785967 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/SetUpFspButtonActions.tsx @@ -0,0 +1,50 @@ +import { Box, Button } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Link, useLocation } from 'react-router-dom'; + +interface SetUpFspButtonActionsProps { + step: number; + submitForm: (values) => void; + baseUrl: string; + paymentPlanId: string; + handleBackStep: () => void; +} + +export function SetUpFspButtonActions({ + step, + submitForm, + baseUrl, + paymentPlanId, + handleBackStep, +}: SetUpFspButtonActionsProps): React.ReactElement { + const { t } = useTranslation(); + const location = useLocation(); + const isFollowUp = location.pathname.indexOf('followup') !== -1; + + return ( + + + {step === 0 && ( + + )} + {step === 1 && } + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/__snapshots__/SetUpFspButtonActions.test.tsx.snap b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/__snapshots__/SetUpFspButtonActions.test.tsx.snap new file mode 100644 index 0000000000..c0a492860f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/__snapshots__/SetUpFspButtonActions.test.tsx.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/CreateSetUpFsp/SetUpFspButtonActions should render 1`] = ` +
+
+ + +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/index.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/index.tsx new file mode 100644 index 0000000000..42d66d381f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspButtonActions/index.tsx @@ -0,0 +1 @@ +export { SetUpFspButtonActions } from './SetUpFspButtonActions'; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/SetUpFspCore.test.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/SetUpFspCore.test.tsx new file mode 100644 index 0000000000..a8069c80e9 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/SetUpFspCore.test.tsx @@ -0,0 +1,35 @@ +import { act } from '@testing-library/react'; +import * as React from 'react'; +import wait from 'waait'; +import { MockedProvider } from '@apollo/react-testing'; +import { render } from '../../../../testUtils/testUtils'; +import { fakeDeliveryMechanisms } from '../../../../../fixtures/paymentmodule/fakeDeliveryMechanisms'; +import { fakeChooseDeliveryMechForPaymentPlanMutation } from '../../../../../fixtures/paymentmodule/fakeChooseDeliveryMechForPaymentPlanMutation'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { SetUpFspCore } from './SetUpFspCore'; + +describe('components/paymentmodule/CreateSetUpFsp/SetUpFspCore', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/SetUpFspCore.tsx b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/SetUpFspCore.tsx new file mode 100644 index 0000000000..39605ae1b5 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/SetUpFspCore.tsx @@ -0,0 +1,272 @@ +import { useLocation, useNavigate, useParams } from 'react-router-dom'; +import { Box } from '@mui/material'; +import Step from '@mui/material/Step'; +import StepLabel from '@mui/material/StepLabel'; +import Stepper from '@mui/material/Stepper'; +import { FieldArray, Form, Formik } from 'formik'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { + AvailableFspsForDeliveryMechanismsDocument, + PaymentPlanDocument, + useAllDeliveryMechanismsQuery, + useAssignFspToDeliveryMechMutation, + useAvailableFspsForDeliveryMechanismsQuery, + useChooseDeliveryMechForPaymentPlanMutation, +} from '@generated/graphql'; +import { AutoSubmitFormOnEnter } from '@core/AutoSubmitFormOnEnter'; +import { ContainerColumnWithBorder } from '@core/ContainerColumnWithBorder'; +import { LoadingComponent } from '@core/LoadingComponent'; +import { DeliveryMechanismRow } from '../DeliveryMechanismRow'; +import { SetUpFspButtonActions } from '../SetUpFspButtonActions/SetUpFspButtonActions'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +export interface FormValues { + deliveryMechanisms: { + chosenConfiguration: string; + deliveryMechanism: string; + fsp: string; + }[]; +} + +interface SetUpFspCoreProps { + permissions: string[]; + initialValues: FormValues; +} + +export const SetUpFspCore = ({ + permissions, + initialValues, +}: SetUpFspCoreProps): React.ReactElement => { + const { baseUrl } = useBaseUrl(); + const navigate = useNavigate(); + const { t } = useTranslation(); + const { id } = useParams(); + const location = useLocation(); + + const { data: deliveryMechanismsData, loading: deliveryMechanismLoading } = + useAllDeliveryMechanismsQuery({ + fetchPolicy: 'network-only', + }); + + const { data: fspsData } = useAvailableFspsForDeliveryMechanismsQuery({ + variables: { + input: { + paymentPlanId: id, + }, + }, + fetchPolicy: 'network-only', + }); + + const isEdit = location.pathname.indexOf('edit') !== -1; + const isFollowUp = location.pathname.indexOf('followup') !== -1; + + const [activeStep, setActiveStep] = useState(isEdit ? 1 : 0); + // const [warning, setWarning] = useState(''); + + const [chooseDeliveryMechanisms] = + useChooseDeliveryMechForPaymentPlanMutation(); + + const [assignFspToDeliveryMechanism] = useAssignFspToDeliveryMechMutation(); + + const { showMessage } = useSnackbar(); + + if (!deliveryMechanismsData) return null; + if (deliveryMechanismLoading) return ; + + const steps = [ + t('Choose Delivery Mechanism'), + t('Assign FSP per Delivery Mechanism'), + ]; + + const handleBackStep = (): void => { + setActiveStep((prevActiveStep) => prevActiveStep - 1); + }; + + const handleNextStep = (): void => { + setActiveStep((prevActiveStep) => prevActiveStep + 1); + }; + + const handleChooseDeliveryMechanisms = async ( + values: FormValues, + ): Promise => { + // setWarning(''); + const mappedDeliveryMechanisms = values.deliveryMechanisms.map( + (el) => el.deliveryMechanism, + ); + try { + await chooseDeliveryMechanisms({ + variables: { + input: { + paymentPlanId: id, + deliveryMechanisms: mappedDeliveryMechanisms, + }, + }, + refetchQueries: () => [ + { + query: AvailableFspsForDeliveryMechanismsDocument, + variables: { + input: { + paymentPlanId: id, + }, + }, + }, + { + query: PaymentPlanDocument, + variables: { + id, + }, + }, + ], + }); + + showMessage(t('Delivery Mechanisms have been set')); + handleNextStep(); + } catch (e) { + // if ( + // e.graphQLErrors.length && + // e.graphQLErrors[0]?.message.includes('sufficient') + // ) { + // setWarning(e.graphQLErrors[0].message); + // } + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + const handleAssignFspToDeliveryMechanism = async ( + values: FormValues, + ): Promise => { + const mappings = values.deliveryMechanisms.map((el, index) => ({ + fspId: el.fsp, + deliveryMechanism: el.deliveryMechanism, + order: index + 1, + chosenConfiguration: el.chosenConfiguration, + })); + try { + await assignFspToDeliveryMechanism({ + variables: { + input: { + paymentPlanId: id, + mappings, + }, + }, + }); + showMessage(t('FSPs have been assigned to the delivery mechanisms')); + navigate( + `/${baseUrl}/payment-module/${ + isFollowUp ? 'followup-payment-plans' : 'payment-plans' + }/${id}`, + ); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + const handleSubmit = (values: FormValues): void => { + if (activeStep === 0) { + handleChooseDeliveryMechanisms(values); + } + if (activeStep === 1) { + handleAssignFspToDeliveryMechanism(values); + } + }; + + return ( + handleSubmit(values)} + enableReinitialize + > + {({ values, submitForm, setFieldValue }) => ( +
+ + + + + + {steps.map((step) => ( + + {step} + + ))} + + + {/* // warning not shown in Payment Module 1.0 */} + {/* {warning && } */} + ( + <> + {values.deliveryMechanisms.map((item, index: number) => { + const mapping = + fspsData?.availableFspsForDeliveryMechanisms[index]; + const mappedFsps = mapping?.fsps.map((el) => ({ + name: el.name, + value: el.id, + configurations: el.configurations, + })); + + const deliveryMechanismsChoices = + deliveryMechanismsData.allDeliveryMechanisms.map( + (el) => ({ + name: el.name, + value: el.value, + }), + ); + + return ( + + ); + })} + {/* // button not shown in Payment Module 1.0 */} + {/* {activeStep === 0 && ( + + + + + + + + )} */} + + )} + /> + + + + + )} +
+ ); +}; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/__snapshots__/SetUpFspCore.test.tsx.snap b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/__snapshots__/SetUpFspCore.test.tsx.snap new file mode 100644 index 0000000000..fbfec4c224 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/__snapshots__/SetUpFspCore.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/CreateSetUpFsp/SetUpFspCore should render 1`] = `
`; diff --git a/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/index.ts b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/index.ts new file mode 100644 index 0000000000..a5c5325281 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/CreateSetUpFsp/SetUpFspCore/index.ts @@ -0,0 +1 @@ +export { SetUpFspCore } from './SetUpFspCore'; diff --git a/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/EditFspHeader.test.tsx b/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/EditFspHeader.test.tsx new file mode 100644 index 0000000000..a792d7be1f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/EditFspHeader.test.tsx @@ -0,0 +1,18 @@ +import * as React from 'react'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { render } from '../../../../testUtils/testUtils'; +import { EditFspHeader } from './EditFspHeader'; +import { fakeBaseUrl } from '../../../../../fixtures/core/fakeBaseUrl'; + +describe('components/paymentmodule/EditFspHeader', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/EditFspHeader.tsx b/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/EditFspHeader.tsx new file mode 100644 index 0000000000..b172074a59 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/EditFspHeader.tsx @@ -0,0 +1,50 @@ +import { Box, Button } from '@mui/material'; +import { Link } from 'react-router-dom'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { BreadCrumbsItem } from '@core/BreadCrumbs'; +import { PageHeader } from '@core/PageHeader'; + +interface EditFspHeaderProps { + handleSubmit: () => Promise; + baseUrl: string; + permissions: string[]; +} + +export function EditFspHeader({ + handleSubmit, + baseUrl, + permissions, +}: EditFspHeaderProps): React.ReactElement { + const { t } = useTranslation(); + + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/`, + }, + ]; + + return ( + + + + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/__snapshots__/EditFspHeader.test.tsx.snap b/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/__snapshots__/EditFspHeader.test.tsx.snap new file mode 100644 index 0000000000..2765a47825 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/__snapshots__/EditFspHeader.test.tsx.snap @@ -0,0 +1,102 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/EditFspHeader should render 1`] = ` +
+
+
+
+ +
+
+
+ +
+
+
+ Edit FSP +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/index.tsx b/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/index.tsx new file mode 100644 index 0000000000..f26f8e67c2 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditFsp/EditFspHeader/index.tsx @@ -0,0 +1 @@ +export { EditFspHeader } from './EditFspHeader'; diff --git a/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/EditPaymentPlanHeader.test.tsx b/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/EditPaymentPlanHeader.test.tsx new file mode 100644 index 0000000000..0d4ae4fbb3 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/EditPaymentPlanHeader.test.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { render } from '../../../../testUtils/testUtils'; +import { EditPaymentPlanHeader } from './EditPaymentPlanHeader'; +import { fakeBaseUrl } from '../../../../../fixtures/core/fakeBaseUrl'; + +describe('components/paymentmodule/EditPaymentPlanHeader', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/EditPaymentPlanHeader.tsx b/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/EditPaymentPlanHeader.tsx new file mode 100644 index 0000000000..ea3fabdfa8 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/EditPaymentPlanHeader.tsx @@ -0,0 +1,89 @@ +import { Box, Button } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Link } from 'react-router-dom'; +import styled from 'styled-components'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { + paymentPlanBackgroundActionStatusToColor, + paymentPlanStatusToColor, +} from '@utils/utils'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { BreadCrumbsItem } from '@core/BreadCrumbs'; +import { PageHeader } from '@core/PageHeader'; +import { StatusBox } from '@core/StatusBox'; + +const StatusWrapper = styled.div` + width: 140px; + margin-left: 30px; +`; + +interface EditPaymentPlanHeaderProps { + handleSubmit: () => Promise; + baseUrl: string; + permissions: string[]; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function EditPaymentPlanHeader({ + handleSubmit, + baseUrl, + permissions, + paymentPlan, +}: EditPaymentPlanHeaderProps): React.ReactElement { + const { t } = useTranslation(); + const { id, isFollowUp } = paymentPlan; + + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/${ + isFollowUp ? 'followup-payment-plans' : 'payment-plans' + }/${id}`, + }, + ]; + + return ( + + {t(isFollowUp ? 'Follow-up Payment Plan' : 'Payment Plan')} ID{' '} + {paymentPlan.unicefId} + + + + {paymentPlan.backgroundActionStatus && ( + + + + )} + + } + breadCrumbs={ + hasPermissions(PERMISSIONS.PM_VIEW_LIST, permissions) + ? breadCrumbsItems + : null + } + > + + + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/__snapshots__/EditPaymentPlanHeader.test.tsx.snap b/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/__snapshots__/EditPaymentPlanHeader.test.tsx.snap new file mode 100644 index 0000000000..05d08e0289 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/__snapshots__/EditPaymentPlanHeader.test.tsx.snap @@ -0,0 +1,123 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/EditPaymentPlanHeader should render 1`] = ` +
+
+
+
+ +
+
+
+ +
+
+
+
+ Payment Plan + ID + + PP-0060-22-00000001 +
+
+
+ LOCKED +
+
+
+
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/index.tsx b/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/index.tsx new file mode 100644 index 0000000000..4f11d8dd2d --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditPaymentPlan/EditPaymentPlanHeader/index.tsx @@ -0,0 +1 @@ +export { EditPaymentPlanHeader } from './EditPaymentPlanHeader'; diff --git a/frontend/src/components/paymentmodulepeople/EditSetUpFsp/DeliveryMechanismWarning.test.tsx b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/DeliveryMechanismWarning.test.tsx new file mode 100644 index 0000000000..0f24c5a234 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/DeliveryMechanismWarning.test.tsx @@ -0,0 +1,12 @@ +import * as React from 'react'; +import { render } from '../../../testUtils/testUtils'; +import { DeliveryMechanismWarning } from './DeliveryMechanismWarning'; + +describe('components/paymentmodule/DeliveryMechanismWarning', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/EditSetUpFsp/DeliveryMechanismWarning.tsx b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/DeliveryMechanismWarning.tsx new file mode 100644 index 0000000000..02b28166d7 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/DeliveryMechanismWarning.tsx @@ -0,0 +1,37 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import styled from 'styled-components'; +import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline'; + +const WarningBox = styled(Box)` + width: 70%; + background-color: #fef7f7; + color: #e90202; +`; + +const ErrorOutline = styled(ErrorOutlineIcon)` + color: #e90202; + margin-right: 5px; +`; + +interface DeliveryMechanismWarningProps { + warning: string; +} + +export function DeliveryMechanismWarning({ + warning, +}: DeliveryMechanismWarningProps): React.ReactElement { + return ( + + + {warning} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/EditSetUpFspHeader.test.tsx b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/EditSetUpFspHeader.test.tsx new file mode 100644 index 0000000000..97f909993d --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/EditSetUpFspHeader.test.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { render } from '../../../../testUtils/testUtils'; +import { EditSetUpFspHeader } from './EditSetUpFspHeader'; + +describe('components/paymentmodule/EditSetUpFsp/EditSetUpFspHeader', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/EditSetUpFspHeader.tsx b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/EditSetUpFspHeader.tsx new file mode 100644 index 0000000000..b9d4988812 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/EditSetUpFspHeader.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useParams, useLocation } from 'react-router-dom'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { BreadCrumbsItem } from '@core/BreadCrumbs'; +import { PageHeader } from '@core/PageHeader'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +interface EditFspHeaderProps { + permissions: string[]; +} + +export function EditSetUpFspHeader({ + permissions, +}: EditFspHeaderProps): React.ReactElement { + const { baseUrl } = useBaseUrl(); + const location = useLocation(); + const { t } = useTranslation(); + const { id } = useParams(); + const isFollowUp = location.pathname.indexOf('followup') !== -1; + + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/${ + isFollowUp ? 'followup-payment-plans' : 'payment-plans' + }/${id}`, + }, + ]; + return ( + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/__snapshots__/EditSetUpFspHeader.test.tsx.snap b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/__snapshots__/EditSetUpFspHeader.test.tsx.snap new file mode 100644 index 0000000000..26e98efb68 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/__snapshots__/EditSetUpFspHeader.test.tsx.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/EditSetUpFsp/EditSetUpFspHeader should render 1`] = ` +
+
+
+
+
+
+
+
+ Edit Set up FSP +
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/index.tsx b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/index.tsx new file mode 100644 index 0000000000..57a5c58d7c --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/EditSetUpFspHeader/index.tsx @@ -0,0 +1 @@ +export { EditSetUpFspHeader } from './EditSetUpFspHeader'; diff --git a/frontend/src/components/paymentmodulepeople/EditSetUpFsp/__snapshots__/DeliveryMechanismWarning.test.tsx.snap b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/__snapshots__/DeliveryMechanismWarning.test.tsx.snap new file mode 100644 index 0000000000..d39a172317 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/EditSetUpFsp/__snapshots__/DeliveryMechanismWarning.test.tsx.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/DeliveryMechanismWarning should render 1`] = ` +
+
+ + Test DM warning comp +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails.tsx b/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails.tsx new file mode 100644 index 0000000000..e6ebf97da4 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails.tsx @@ -0,0 +1,104 @@ +import { Grid, Typography } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { renderUserName } from '@utils/utils'; +import { BlackLink } from '@core/BlackLink'; +import { ContainerColumnWithBorder } from '@core/ContainerColumnWithBorder'; +import { LabelizedField } from '@core/LabelizedField'; +import { OverviewContainer } from '@core/OverviewContainer'; +import { Title } from '@core/Title'; +import { UniversalMoment } from '@core/UniversalMoment'; + +interface FollowUpPaymentPlanDetailsProps { + baseUrl: string; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function FollowUpPaymentPlanDetails({ + baseUrl, + paymentPlan, +}: FollowUpPaymentPlanDetailsProps): React.ReactElement { + const { t } = useTranslation(); + const { + createdBy, + program, + currency, + startDate, + endDate, + dispersionStartDate, + dispersionEndDate, + sourcePaymentPlan: { + id: sourcePaymentPlanId, + unicefId: sourcePaymentPlanUnicefId, + }, + targetPopulation, + } = paymentPlan; + + return ( + + + + <Typography variant="h6">{t('Details')}</Typography> + + + + + + + {sourcePaymentPlanUnicefId} + + + + + + {renderUserName(createdBy)} + + + + + + {program.name} + + + + + + + {targetPopulation.name} + + + + + {currency} + + + + {startDate} + + + + + {endDate} + + + + + {dispersionStartDate} + + + + + {dispersionEndDate} + + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails/index.tsx b/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails/index.tsx new file mode 100644 index 0000000000..a2c1d44a85 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails/index.tsx @@ -0,0 +1 @@ +export { FollowUpPaymentPlanDetails } from './FollowUpPaymentPlanDetails'; diff --git a/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetailsHeader/FollowUpPaymentPlanDetailsHeader.tsx b/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetailsHeader/FollowUpPaymentPlanDetailsHeader.tsx new file mode 100644 index 0000000000..1d9ec7d830 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetailsHeader/FollowUpPaymentPlanDetailsHeader.tsx @@ -0,0 +1,205 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { + paymentPlanBackgroundActionStatusToColor, + paymentPlanStatusToColor, +} from '@utils/utils'; +import { BreadCrumbsItem } from '../../../core/BreadCrumbs'; +import { PageHeader } from '../../../core/PageHeader'; +import { StatusBox } from '../../../core/StatusBox'; +import { AcceptedPaymentPlanHeaderButtons } from '../../PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons'; +import { InApprovalPaymentPlanHeaderButtons } from '../../PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons'; +import { InAuthorizationPaymentPlanHeaderButtons } from '../../PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons'; +import { InReviewPaymentPlanHeaderButtons } from '../../PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons'; +import { LockedFspPaymentPlanHeaderButtons } from '../../PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedFspPaymentPlanHeaderButtons'; +import { LockedPaymentPlanHeaderButtons } from '../../PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons'; +import { OpenPaymentPlanHeaderButtons } from '../../PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons'; +import { PaymentPlanQuery } from '@generated/graphql'; + +const StatusWrapper = styled.div` + width: 140px; + margin-left: 30px; +`; + +interface FollowUpPaymentPlanDetailsHeaderProps { + baseUrl: string; + permissions: string[]; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function FollowUpPaymentPlanDetailsHeader({ + baseUrl, + permissions, + paymentPlan, +}: FollowUpPaymentPlanDetailsHeaderProps): React.ReactElement { + const { t } = useTranslation(); + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/`, + }, + ]; + + const canRemove = hasPermissions(PERMISSIONS.PM_CREATE, permissions); + const canEdit = hasPermissions(PERMISSIONS.PM_CREATE, permissions); + const canLock = hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK, permissions); + const canUnlock = hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK, permissions); + const canSendForApproval = hasPermissions( + PERMISSIONS.PM_SEND_FOR_APPROVAL, + permissions, + ); + const canApprove = hasPermissions( + PERMISSIONS.PM_ACCEPTANCE_PROCESS_APPROVE, + permissions, + ); + const canAuthorize = hasPermissions( + PERMISSIONS.PM_ACCEPTANCE_PROCESS_AUTHORIZE, + permissions, + ); + const canMarkAsReleased = hasPermissions( + PERMISSIONS.PM_ACCEPTANCE_PROCESS_FINANCIAL_REVIEW, + permissions, + ); + const canDownloadXlsx = hasPermissions( + PERMISSIONS.PM_DOWNLOAD_XLSX_FOR_FSP, + permissions, + ); + const canExportXlsx = hasPermissions( + PERMISSIONS.PM_EXPORT_XLSX_FOR_FSP, + permissions, + ); + const canSendToPaymentGateway = + hasPermissions(PERMISSIONS.PM_SEND_TO_PAYMENT_GATEWAY, permissions) && + paymentPlan.canSendToPaymentGateway; + const canSplit = + hasPermissions(PERMISSIONS.PM_SPLIT, permissions) && paymentPlan.canSplit; + + let buttons: React.ReactElement | null = null; + switch (paymentPlan.status) { + case 'OPEN': + buttons = ( + + ); + break; + case 'LOCKED': + buttons = ( + + ); + break; + case 'LOCKED_FSP': + buttons = ( + + ); + break; + case 'IN_APPROVAL': + buttons = ( + + ); + break; + case 'IN_AUTHORIZATION': + buttons = ( + + ); + break; + case 'IN_REVIEW': + buttons = ( + + ); + break; + case 'ACCEPTED': + buttons = ( + + ); + break; + case 'FINISHED': // TODO: may create another one for that explicitly but good for now + buttons = ( + + ); + break; + default: + break; + } + + return ( + + {t('Follow-up Payment Plan')} ID:{' '} + + {paymentPlan.unicefId} + + + + + {paymentPlan.backgroundActionStatus && ( + + + + )} + + } + breadCrumbs={ + hasPermissions(PERMISSIONS.PM_VIEW_DETAILS, permissions) + ? breadCrumbsItems + : null + } + > + {buttons} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetailsHeader/index.tsx b/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetailsHeader/index.tsx new file mode 100644 index 0000000000..3cce216c8c --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetailsHeader/index.tsx @@ -0,0 +1 @@ +export { FollowUpPaymentPlanDetailsHeader } from './FollowUpPaymentPlanDetailsHeader'; diff --git a/frontend/src/components/paymentmodulepeople/ForceFailedButton.tsx b/frontend/src/components/paymentmodulepeople/ForceFailedButton.tsx new file mode 100644 index 0000000000..0dc65c7fd5 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/ForceFailedButton.tsx @@ -0,0 +1,88 @@ +import { Box, Button, DialogContent, DialogTitle } from '@mui/material'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Dialog } from '@containers/dialogs/Dialog'; +import { DialogActions } from '@containers/dialogs/DialogActions'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { useMarkPayAsFailedMutation } from '@generated/graphql'; + +export interface ForceFailedButtonProps { + paymentId: string; + disabled?: boolean; +} +export function ForceFailedButton({ + paymentId, + disabled = false, +}: ForceFailedButtonProps): React.ReactElement { + const { t } = useTranslation(); + const [isOpenModal, setOpenModal] = useState(false); + const { showMessage } = useSnackbar(); + const [mutate, { loading }] = useMarkPayAsFailedMutation(); + + const submit = async (): Promise => { + try { + await mutate({ + variables: { + paymentId, + }, + }); + setOpenModal(false); + showMessage(t('Payment has been marked as failed.')); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + return ( + + + + + setOpenModal(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Mark as failed')} + + + + + {t('Are you sure you would like to mark payment as failed?')} + + + + + + + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/FspHeader.test.tsx b/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/FspHeader.test.tsx new file mode 100644 index 0000000000..ea164432d4 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/FspHeader.test.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { render } from '../../../../testUtils/testUtils'; +import { FspHeader } from './FspHeader'; +import { fakeBaseUrl } from '../../../../../fixtures/core/fakeBaseUrl'; + +describe('components/paymentmodule/FspPlanDetails/FspHeader', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/FspHeader.tsx b/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/FspHeader.tsx new file mode 100644 index 0000000000..2e23c74d5e --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/FspHeader.tsx @@ -0,0 +1,52 @@ +import { Box, Button } from '@mui/material'; +import { Link } from 'react-router-dom'; +import EditIcon from '@mui/icons-material/EditRounded'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { BreadCrumbsItem } from '@core/BreadCrumbs'; +import { PageHeader } from '@core/PageHeader'; + +interface FspHeaderProps { + baseUrl: string; + permissions: string[]; +} + +export function FspHeader({ + baseUrl, + permissions, +}: FspHeaderProps): React.ReactElement { + const { t } = useTranslation(); + + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/`, + }, + ]; + + return ( + + + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/__snapshots__/FspHeader.test.tsx.snap b/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/__snapshots__/FspHeader.test.tsx.snap new file mode 100644 index 0000000000..527bfacab5 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/__snapshots__/FspHeader.test.tsx.snap @@ -0,0 +1,107 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/FspPlanDetails/FspHeader should render 1`] = ` +
+
+
+
+ +
+
+
+ +
+
+
+ Set up FSP +
+
+
+
+
+ +
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/index.tsx b/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/index.tsx new file mode 100644 index 0000000000..ab635206c2 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FspPlanDetails/FspHeader/index.tsx @@ -0,0 +1 @@ +export { FspHeader } from './FspHeader'; diff --git a/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/TotalAmount.test.tsx b/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/TotalAmount.test.tsx new file mode 100644 index 0000000000..5e4808db46 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/TotalAmount.test.tsx @@ -0,0 +1,10 @@ +import * as React from 'react'; +import { render } from '../../../../testUtils/testUtils'; +import { TotalAmount } from './TotalAmount'; + +describe('components/paymentmodule/FspPlanDetails/TotalAmount', () => { + it('should render', () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/TotalAmount.tsx b/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/TotalAmount.tsx new file mode 100644 index 0000000000..5c9f3f3063 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/TotalAmount.tsx @@ -0,0 +1,25 @@ +import { Box, Typography } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { ContainerColumnWithBorder } from '@core/ContainerColumnWithBorder'; +import { Title } from '@core/Title'; + +export function TotalAmount(): React.ReactElement { + const { t } = useTranslation(); + + return ( + + + + + <Typography variant="h6"> + {t('Total Amount')} + (PLN) + {t('per FSP')} + </Typography> + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/__snapshots__/TotalAmount.test.tsx.snap b/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/__snapshots__/TotalAmount.test.tsx.snap new file mode 100644 index 0000000000..7959353b18 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/__snapshots__/TotalAmount.test.tsx.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/FspPlanDetails/TotalAmount should render 1`] = ` +
+
+
+
+
+
+ Total Amount + (PLN) + per FSP +
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/index.tsx b/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/index.tsx new file mode 100644 index 0000000000..b19eebb2f7 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/FspPlanDetails/TotalAmount/index.tsx @@ -0,0 +1 @@ +export { TotalAmount } from './TotalAmount'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentDetails/PaymentDetails.tsx b/frontend/src/components/paymentmodulepeople/PaymentDetails/PaymentDetails.tsx new file mode 100644 index 0000000000..588c3d448f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentDetails/PaymentDetails.tsx @@ -0,0 +1,312 @@ +import { Grid, Paper, Typography } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { + PaymentDeliveryType, + PaymentQuery, + PaymentStatus, + PaymentVerificationStatus, +} from '@generated/graphql'; +import { UniversalActivityLogTable } from '@containers/tables/UniversalActivityLogTable'; +import { useBusinessArea } from '@hooks/useBusinessArea'; +import { + formatCurrencyWithSymbol, + getPhoneNoLabel, + paymentStatusDisplayMap, + paymentStatusToColor, + verificationRecordsStatusToColor, +} from '@utils/utils'; +import { BlackLink } from '@core/BlackLink'; +import { ContainerColumnWithBorder } from '@core/ContainerColumnWithBorder'; +import { DividerLine } from '@core/DividerLine'; +import { LabelizedField } from '@core/LabelizedField'; +import { StatusBox } from '@core/StatusBox'; +import { Title } from '@core/Title'; +import { UniversalMoment } from '@core/UniversalMoment'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +const Overview = styled(Paper)` + margin: 20px; + padding: ${({ theme }) => theme.spacing(8)} + ${({ theme }) => theme.spacing(11)}; +`; + +interface PaymentDetailsProps { + payment: PaymentQuery['payment']; + canViewActivityLog: boolean; + canViewHouseholdDetails: boolean; +} + +export function PaymentDetails({ + payment, + canViewActivityLog, + canViewHouseholdDetails, +}: PaymentDetailsProps): React.ReactElement { + const businessArea = useBusinessArea(); + const { t } = useTranslation(); + const { programId } = useBaseUrl(); + + let paymentVerification: PaymentQuery['payment']['verification'] = null; + if ( + payment.verification && + payment.verification.status !== PaymentVerificationStatus.Pending + ) { + paymentVerification = payment.verification; + } + + const showFailureReason = [ + PaymentStatus.NotDistributed, + PaymentStatus.ForceFailed, + PaymentStatus.TransactionErroneous, + ].includes(payment.status); + + return ( + <> + + + <Typography variant="h6">{t('Details')}</Typography> + + + + + + + + + + + + + + + + + + {payment.deliveryDate}} + /> + + + + + {payment.targetPopulation?.name} + + + + + + + + + + + + {paymentVerification != null ? ( + + + <Typography variant="h6">{t('Verification Details')}</Typography> + + + + + + + + + + + + + + ) : null} + + + <Typography variant="h6">{t('Household')}</Typography> + + + + + {payment.household?.id && canViewHouseholdDetails ? ( + + {payment.household.unicefId} + + ) : ( +
+ {payment.household?.id ? payment.household.unicefId : '-'} +
+ )} +
+
+ + + + + + + + + + + + + + + +
+
+ + + <Typography variant="h6">{t('Entitlement Details')}</Typography> + + + + + + + + + + + + + + + + + + + + + {payment.deliveryType === PaymentDeliveryType.DepositToCard && ( + <> + + + + + + + + )} + + + + + <Typography variant="h6">{t('Reconciliation Details')}</Typography> + + + + + + + + + + + + + + + {showFailureReason && ( + + + + )} + + + + + + {canViewActivityLog && ( + + )} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentDetails/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentDetails/index.tsx new file mode 100644 index 0000000000..25f9811c5e --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentDetails/index.tsx @@ -0,0 +1 @@ +export { PaymentDetails } from './PaymentDetails'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcess.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcess.tsx new file mode 100644 index 0000000000..5c6372bc27 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcess.tsx @@ -0,0 +1,111 @@ +import { Box, Button, Typography } from '@mui/material'; +import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { + PaymentPlanQuery, + PaymentPlanStatus, + useExportPdfPpSummaryMutation, +} from '@generated/graphql'; +import { PERMISSIONS, hasPermissions } from '../../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { ContainerColumnWithBorder } from '@core/ContainerColumnWithBorder'; +import { LoadingButton } from '@core/LoadingButton'; +import { Title } from '@core/Title'; +import { useProgramContext } from '../../../../programContext'; +import { AcceptanceProcessRow } from './AcceptanceProcessRow'; + +const ButtonContainer = styled(Box)` + width: 200px; +`; + +interface AcceptanceProcessProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function AcceptanceProcess({ + paymentPlan, +}: AcceptanceProcessProps): React.ReactElement { + const { t } = useTranslation(); + const { showMessage } = useSnackbar(); + const permissions = usePermissions(); + const { isActiveProgram } = useProgramContext(); + + const { edges } = paymentPlan.approvalProcess; + const [showAll, setShowAll] = useState(false); + const [mutate, { loading: exportPdfLoading }] = + useExportPdfPpSummaryMutation(); + + const matchDataSize = ( + data: PaymentPlanQuery['paymentPlan']['approvalProcess']['edges'], + ): PaymentPlanQuery['paymentPlan']['approvalProcess']['edges'] => + showAll ? data : [data[0]]; + + if (!edges.length) { + return null; + } + const handleExportPdf = async (): Promise => { + try { + await mutate({ + variables: { + paymentPlanId: paymentPlan.id, + }, + }); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } finally { + showMessage(t('PDF generated. Please check your email.')); + } + }; + + const canExportPdf = + hasPermissions(PERMISSIONS.PM_EXPORT_PDF_SUMMARY, permissions) && + (paymentPlan.status === PaymentPlanStatus.Accepted || + paymentPlan.status === PaymentPlanStatus.Finished); + + return ( + + + + + <Typography variant="h6">{t('Acceptance Process')}</Typography> + + {canExportPdf && ( + + {t('Download Payment Plan Summary')} + + )} + + {matchDataSize(edges).map((edge) => ( + + ))} + {edges.length > 1 && ( + + + + )} + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow.test.tsx new file mode 100644 index 0000000000..2c7bfeac78 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow.test.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { render } from '../../../../testUtils/testUtils'; +import { AcceptanceProcessRow } from './AcceptanceProcessRow'; + +describe('components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow.tsx new file mode 100644 index 0000000000..d34e5e84c1 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow.tsx @@ -0,0 +1,124 @@ +import { Box, Grid } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { renderUserName } from '@utils/utils'; +import { DividerLine } from '@core/DividerLine'; +import { AcceptanceProcessStepper } from './AcceptanceProcessStepper/AcceptanceProcessStepper'; +import { GreyInfoCard } from './GreyInfoCard'; + +const StyledBox = styled(Box)` + width: 100%; +`; + +interface AcceptanceProcessRowProps { + acceptanceProcess: PaymentPlanQuery['paymentPlan']['approvalProcess']['edges'][0]['node']; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function AcceptanceProcessRow({ + acceptanceProcess, + paymentPlan, +}: AcceptanceProcessRowProps): React.ReactElement { + const { t } = useTranslation(); + const { + actions, + sentForApprovalDate, + sentForApprovalBy, + sentForAuthorizationDate, + sentForAuthorizationBy, + sentForFinanceReleaseDate, + sentForFinanceReleaseBy, + rejectedOn, + } = acceptanceProcess; + + const { approvalProcess } = paymentPlan; + + const getRejectedOnString = (stage: string): string => { + switch (stage) { + case 'IN_APPROVAL': + return t('Rejected in Approval stage'); + case 'IN_AUTHORIZATION': + return t('Rejected in Authorization stage'); + case 'IN_REVIEW': + return t('Rejected in Finance Release stage'); + + default: + return ''; + } + }; + + return ( + + + + + {actions.approval.length > 0 && ( + + )} + + + {actions.authorization.length > 0 && ( + + )} + + + {actions.financeRelease.length > 0 && ( + + )} + + {actions.reject.length > 0 && ( + + + {rejectedOn === 'IN_APPROVAL' && ( + + )} + + + {rejectedOn === 'IN_AUTHORIZATION' && ( + + )} + + + {rejectedOn === 'IN_REVIEW' && ( + + )} + + + )} + + {approvalProcess.totalCount > 1 && } + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.test.tsx new file mode 100644 index 0000000000..73beda5b83 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.test.tsx @@ -0,0 +1,54 @@ +import { act } from '@testing-library/react'; +import * as React from 'react'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { render } from '../../../../../testUtils/testUtils'; +import { AcceptanceProcessStepper } from './AcceptanceProcessStepper'; + +describe('components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper', () => { + it('should render default step Sent for Approval Date', async () => { + const { container } = render( + , + ); + await act(() => wait(0)); // wait for response + expect(container).toMatchSnapshot(); + }); + it('should render step Sent for Approval Date', async () => { + const { container } = render( + , + ); + await act(() => wait(0)); // wait for response + expect(container).toMatchSnapshot(); + }); + it('should render step Sent for Authorization Date', async () => { + const { container } = render( + , + ); + await act(() => wait(0)); // wait for response + expect(container).toMatchSnapshot(); + }); + it('should render step Sent for Finance Release Date', async () => { + const { container } = render( + , + ); + await act(() => wait(0)); // wait for response + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.tsx new file mode 100644 index 0000000000..44ac95c41f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/AcceptanceProcessStepper.tsx @@ -0,0 +1,66 @@ +import Step from '@mui/material/Step'; +import StepLabel from '@mui/material/StepLabel'; +import Stepper from '@mui/material/Stepper'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { PaymentPlanQuery } from '@generated/graphql'; + +interface AcceptanceProcessStepperProps { + acceptanceProcess: PaymentPlanQuery['paymentPlan']['approvalProcess']['edges'][0]['node']; +} + +export function AcceptanceProcessStepper({ + acceptanceProcess, +}: AcceptanceProcessStepperProps): React.ReactElement { + const { + rejectedOn, + actions, + approvalNumberRequired, + authorizationNumberRequired, + financeReleaseNumberRequired, + } = acceptanceProcess; + const { t } = useTranslation(); + const steps = [ + { + name: `${t('Approval')} (${ + actions.approval.length + }/${approvalNumberRequired})`, + hasError: rejectedOn === 'IN_APPROVAL', + isCompleted: actions.approval.length === approvalNumberRequired, + }, + { + name: `${t('Authorization')} (${ + actions.authorization.length + }/${authorizationNumberRequired})`, + hasError: rejectedOn === 'IN_AUTHORIZATION', + isCompleted: actions.authorization.length === authorizationNumberRequired, + }, + { + name: `${t('Finance Release')} (${ + actions.financeRelease.length + }/${financeReleaseNumberRequired})`, + hasError: rejectedOn === 'IN_REVIEW', + isCompleted: + actions.financeRelease.length === financeReleaseNumberRequired, + }, + ]; + const getActiveStep = (): number => { + if (actions.authorization.length === authorizationNumberRequired) { + return 2; + } + if (actions.approval.length === approvalNumberRequired) { + return 1; + } + return 0; + }; + + return ( + + {steps.map((step) => ( + + {step.name} + + ))} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/__snapshots__/AcceptanceProcessStepper.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/__snapshots__/AcceptanceProcessStepper.test.tsx.snap new file mode 100644 index 0000000000..3810b41072 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/__snapshots__/AcceptanceProcessStepper.test.tsx.snap @@ -0,0 +1,557 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper should render default step Sent for Approval Date 1`] = ` +
+
+
+ + + + + + + Approval (1/1) + + + +
+
+ +
+
+ + + + + + + Authorization (0/1) + + + +
+
+ +
+
+ + + + + + + Finance Release (0/1) + + + +
+
+
+`; + +exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper should render step Sent for Approval Date 1`] = ` +
+
+
+ + + + + + + Approval (1/1) + + + +
+
+ +
+
+ + + + + + + Authorization (0/1) + + + +
+
+ +
+
+ + + + + + + Finance Release (0/1) + + + +
+
+
+`; + +exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper should render step Sent for Authorization Date 1`] = ` +
+
+
+ + + + + + + Approval (1/1) + + + +
+
+ +
+
+ + + + + + + Authorization (0/1) + + + +
+
+ +
+
+ + + + + + + Finance Release (0/1) + + + +
+
+
+`; + +exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper should render step Sent for Finance Release Date 1`] = ` +
+
+
+ + + + + + + Approval (1/1) + + + +
+
+ +
+
+ + + + + + + Authorization (0/1) + + + +
+
+ +
+
+ + + + + + + Finance Release (0/1) + + + +
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/index.tsx new file mode 100644 index 0000000000..b13214ef87 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessStepper/index.tsx @@ -0,0 +1 @@ +export { AcceptanceProcessStepper } from './AcceptanceProcessStepper'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/GreyInfoCard.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/GreyInfoCard.test.tsx new file mode 100644 index 0000000000..8149bc9266 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/GreyInfoCard.test.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { render } from '../../../../testUtils/testUtils'; +import { GreyInfoCard } from './GreyInfoCard'; + +describe('components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/GreyInfoCard', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/GreyInfoCard.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/GreyInfoCard.tsx new file mode 100644 index 0000000000..e2b683e32d --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/GreyInfoCard.tsx @@ -0,0 +1,85 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import styled from 'styled-components'; +import { UniversalMoment } from '@core/UniversalMoment'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { MessageDialog } from './MessageDialog'; + +const GreyText = styled.div` + color: #9e9e9e; +`; + +const GreyTitle = styled.div` + color: #7c8990; + text-transform: uppercase; + font-size: 12px; +`; + +const IconPlaceholder = styled.div` + width: 16px; + height: 16px; +`; + +const GreyBox = styled(Box)` + background-color: #f4f5f6; +`; + +interface GreyInfoCardProps { + topMessage: string; + topDate: string; + approvals: PaymentPlanQuery['paymentPlan']['approvalProcess']['edges'][number]['node']['actions']['approval']; +} + +export function GreyInfoCard({ + topMessage, + topDate, + approvals, +}: GreyInfoCardProps): React.ReactElement { + const mappedApprovals = approvals.map((action) => { + const { info, createdAt, comment, createdBy } = action; + return ( + info && ( + + {info} + + + on {createdAt} + + + + {comment ? ( + + ) : ( + + )} + + + ) + ); + }); + + return ( + + + + {topMessage} on + {topDate} + + + + {mappedApprovals} + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/MessageDialog.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/MessageDialog.test.tsx new file mode 100644 index 0000000000..bc4ecad8b4 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/MessageDialog.test.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { fakeApolloMe } from '../../../../../fixtures/core/fakeApolloMe'; +import { render } from '../../../../testUtils/testUtils'; +import { MessageDialog } from './MessageDialog'; + +describe('components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/MessageDialog', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/MessageDialog.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/MessageDialog.tsx new file mode 100644 index 0000000000..2535b14a58 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/MessageDialog.tsx @@ -0,0 +1,102 @@ +import { + Box, + Button, + DialogContent, + DialogTitle, + IconButton, +} from '@mui/material'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import MessageIcon from '@mui/icons-material/Message'; +import styled from 'styled-components'; +import { Dialog } from '@containers/dialogs/Dialog'; +import { DialogActions } from '@containers/dialogs/DialogActions'; +import { UniversalMoment } from '@core/UniversalMoment'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DividerLine } from '@core/DividerLine'; +import { renderUserName } from '@utils/utils'; +import { UserNode } from '@generated/graphql'; + +const DialogTitleWrapper = styled.div` + border-bottom: 1px solid ${({ theme }) => theme.hctPalette.lighterGray}; +`; + +const DialogFooter = styled.div` + padding: 12px 16px; + margin: 0; + border-top: 1px solid ${({ theme }) => theme.hctPalette.lighterGray}; + text-align: right; +`; + +const GreyText = styled.div` + color: #9e9e9e; +`; + +const MessageIconContainer = styled(Box)` + position: relative; + top: 4px; + font-size: 16px; + color: #043f91; +`; + +export interface MessageDialogProps { + comment: string; + author: Pick; + date: string; +} +export function MessageDialog({ + comment, + author, + date, +}: MessageDialogProps): React.ReactElement { + const { t } = useTranslation(); + const [MessageDialogOpen, setMessageDialogOpen] = useState(false); + return ( + <> + setMessageDialogOpen(true)}> + + + + + setMessageDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Comment')} + + + + + + {renderUserName(author)}{' '} + + + on {date} + + + + + {comment} + + + + + + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/AcceptanceProcessRow.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/AcceptanceProcessRow.test.tsx.snap new file mode 100644 index 0000000000..7a81fdfaba --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/AcceptanceProcessRow.test.tsx.snap @@ -0,0 +1,207 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcessRow should render 1`] = ` +
+
+
+
+ + + + + + + Approval (1/1) + + + +
+
+ +
+
+ + + + + + + Authorization (0/1) + + + +
+
+ +
+
+ + + + + + + Finance Release (0/1) + + + +
+
+
+
+
+
+
+ Sent for approval by Root Rootkowski + on + +
+
+
+
+ Approved by Root Rootkowski +
+
+ on + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/GreyInfoCard.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/GreyInfoCard.test.tsx.snap new file mode 100644 index 0000000000..5fee6dc88f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/GreyInfoCard.test.tsx.snap @@ -0,0 +1,55 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/GreyInfoCard should render 1`] = ` +
+
+
+
+ Test top message + on + +
+
+
+
+ Approved by Root Rootkowski +
+
+ on + +
+
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/MessageDialog.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/MessageDialog.test.tsx.snap new file mode 100644 index 0000000000..d1d6f43191 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/__snapshots__/MessageDialog.test.tsx.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/MessageDialog should render 1`] = ` +
+ +
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/index.tsx new file mode 100644 index 0000000000..251d9cbc1c --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/AcceptanceProcess/index.tsx @@ -0,0 +1 @@ +export { AcceptanceProcess } from './AcceptanceProcess'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/Entitlement.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/Entitlement.test.tsx new file mode 100644 index 0000000000..db1f3c7fa6 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/Entitlement.test.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloAllSteficonRules } from '../../../../../fixtures/steficon/fakeApolloAllSteficonRules'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { render } from '../../../../testUtils/testUtils'; +import { Entitlement } from './Entitlement'; +import {PERMISSIONS} from "../../../../config/permissions"; + +describe('components/paymentmodule/PaymentPlanDetails/Entitlement', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/Entitlement.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/Entitlement.tsx new file mode 100644 index 0000000000..d4a14683c1 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/Entitlement.tsx @@ -0,0 +1,347 @@ +import { + Box, + Button, + FormControl, + Grid, + InputLabel, + MenuItem, + Select, + Typography, +} from '@mui/material'; +import { GetApp } from '@mui/icons-material'; +import AttachFileIcon from '@mui/icons-material/AttachFile'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { + PaymentPlanBackgroundActionStatus, + PaymentPlanDocument, + PaymentPlanQuery, + PaymentPlanStatus, + useAllSteficonRulesQuery, + useExportXlsxPpListMutation, + useSetSteficonRuleOnPpListMutation, +} from '@generated/graphql'; +import { ContainerColumnWithBorder } from '@core/ContainerColumnWithBorder'; +import { LabelizedField } from '@core/LabelizedField'; +import { LoadingButton } from '@core/LoadingButton'; +import { LoadingComponent } from '@core/LoadingComponent'; +import { Title } from '@core/Title'; +import { UniversalMoment } from '@core/UniversalMoment'; +import { BigValue } from '../../../rdi/details/RegistrationDetails/RegistrationDetails'; +import { ImportXlsxPaymentPlanPaymentList } from '../ImportXlsxPaymentPlanPaymentList/ImportXlsxPaymentPlanPaymentList'; +import { useProgramContext } from '../../../../programContext'; + +const GreyText = styled.p` + color: #9e9e9e; + font-size: 16px; +`; + +const GreyTextSmall = styled.p` + color: #9e9e9e; + font-size: 14px; +`; + +const OrDivider = styled.div` + border-top: 1px solid #b1b1b5; + height: 2px; + width: 50%; + margin-top: 20px; +`; + +const Divider = styled.div` + border-top: 1px solid #b1b1b5; + height: 20px; +`; + +const DividerLabel = styled.div` + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; + font-weight: 500; + color: #253b46; + text-transform: uppercase; + padding: 5px; + border: 1px solid #b1b1b5; + border-radius: 50%; + background-color: #fff; + margin-top: 20px; +`; + +const DownloadIcon = styled(GetApp)` + color: #043f91; +`; + +const SpinaczIconContainer = styled(Box)` + position: relative; + top: 4px; + font-size: 16px; + color: #666666; +`; + +const BoxWithBorderRight = styled(Box)` + border-right: 1px solid #b1b1b5; +`; + +interface EntitlementProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + permissions: string[]; +} + +export function Entitlement({ + paymentPlan, + permissions, +}: EntitlementProps): React.ReactElement { + const { t } = useTranslation(); + const { showMessage } = useSnackbar(); + const { isActiveProgram } = useProgramContext(); + + const [steficonRuleValue, setSteficonRuleValue] = useState( + paymentPlan.steficonRule?.rule.id || '', + ); + const options = { + refetchQueries: () => [ + { + query: PaymentPlanDocument, + variables: { + id: paymentPlan.id, + }, + }, + ], + }; + + const [setSteficonRule, { loading: loadingSetSteficonRule }] = + useSetSteficonRuleOnPpListMutation(options); + + const { data: steficonData, loading } = useAllSteficonRulesQuery({ + variables: { enabled: true, deprecated: false, type: 'PAYMENT_PLAN' }, + fetchPolicy: 'network-only', + }); + const [mutateExport, { loading: loadingExport }] = + useExportXlsxPpListMutation(); + + if (!steficonData) { + return null; + } + if (loading) { + return ; + } + + const canApplySteficonRule = hasPermissions( + PERMISSIONS.PM_APPLY_RULE_ENGINE_FORMULA_WITH_ENTITLEMENTS, + permissions, + ); + + const shouldDisableEntitlementSelect = + !canApplySteficonRule || + paymentPlan.status !== PaymentPlanStatus.Locked || + !isActiveProgram; + + const shouldDisableDownloadTemplate = + paymentPlan.status !== PaymentPlanStatus.Locked || !isActiveProgram; + + const shouldDisableExportXlsx = + loadingExport || + paymentPlan.status !== PaymentPlanStatus.Locked || + paymentPlan?.backgroundActionStatus === + PaymentPlanBackgroundActionStatus.XlsxExporting || + !isActiveProgram; + + return ( + + + + + <Typography variant="h6">{t('Entitlement')}</Typography> + + {t('Select Entitlement Formula')} + + + + + {t('Entitlement Formula')} + + + + + + + + + + + + + Or + + + + + + + {paymentPlan.hasPaymentListExportFile ? ( + + ) : ( + } + data-cy="button-export-xlsx" + onClick={async () => { + try { + await mutateExport({ + variables: { + paymentPlanId: paymentPlan.id, + }, + }); + showMessage( + t('Exporting XLSX started. Please check your email.'), + ); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }} + > + {t('Export Xlsx')} + + )} + + + {t( + 'Template contains payment list with all targeted households', + )} + + + + + + + + + {paymentPlan?.importedFileName ? ( + + + + + + + {paymentPlan?.importedFileName} + + + + {paymentPlan?.importedFileDate ? ( + + {paymentPlan?.importedFileDate} + + ) : null} + + + ) : ( + + {t( + 'Uploaded file should contain entitlement for each household', + )} + + )} + + + + {paymentPlan.totalEntitledQuantityUsd ? ( + <> + + + + {`${paymentPlan.totalEntitledQuantity} ${paymentPlan.currency} (${paymentPlan.totalEntitledQuantityUsd} USD)`} + + + + ) : null} + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/__snapshots__/Entitlement.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/__snapshots__/Entitlement.test.tsx.snap new file mode 100644 index 0000000000..adbc5d0ea5 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/__snapshots__/Entitlement.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/Entitlement should render 1`] = `
`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/index.tsx new file mode 100644 index 0000000000..95bae78325 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/Entitlement/index.tsx @@ -0,0 +1 @@ +export { Entitlement } from './Entitlement'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/ExcludeSection.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/ExcludeSection.tsx new file mode 100644 index 0000000000..2b86536934 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/ExcludeSection.tsx @@ -0,0 +1,443 @@ +import { + Box, + Button, + Collapse, + FormHelperText, + Grid, + Typography, +} from '@mui/material'; +import { Field, Form, Formik } from 'formik'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import * as Yup from 'yup'; +import { + PaymentPlanDocument, + PaymentPlanQuery, + PaymentPlanStatus, + useExcludeHouseholdsPpMutation, +} from '@generated/graphql'; +import { PERMISSIONS, hasPermissions } from '../../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { FormikTextField } from '@shared/Formik/FormikTextField'; +import { StyledTextField } from '@shared/StyledTextField'; +import { ButtonTooltip } from '@core/ButtonTooltip'; +import { GreyText } from '@core/GreyText'; +import { PaperContainer } from '../../../targeting/PaperContainer'; +import { useProgramContext } from '../../../../programContext'; +import { ExcludedItem } from './ExcludedItem'; + +interface ExcludeSectionProps { + initialOpen?: boolean; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function ExcludeSection({ + initialOpen = false, + paymentPlan, +}: ExcludeSectionProps): React.ReactElement { + const { + status, + backgroundActionStatus, + exclusionReason, + excludeHouseholdError, + } = paymentPlan; + + const initialExcludedIds = paymentPlan?.excludedHouseholds?.map( + (el) => el.unicefId, + ); + const [isExclusionsOpen, setExclusionsOpen] = useState(initialOpen); + const [idsValue, setIdsValue] = useState(''); + const [excludedIds, setExcludedIds] = useState( + initialExcludedIds || [], + ); + const [deletedIds, setDeletedIds] = useState([]); + const { t } = useTranslation(); + const permissions = usePermissions(); + const { isActiveProgram } = useProgramContext(); + + const hasExcludePermission = hasPermissions( + PERMISSIONS.PM_EXCLUDE_BENEFICIARIES_FROM_FOLLOW_UP_PP, + permissions, + ); + const hasOpenOrLockedStatus = + status === PaymentPlanStatus.Locked || status === PaymentPlanStatus.Open; + + const getTooltipText = (): string => { + if (!hasOpenOrLockedStatus) { + return t( + 'Households can only be excluded from a Payment Plan in status open or locked', + ); + } + if (!hasExcludePermission) { + return t('Permission denied'); + } + return ''; + }; + + const { showMessage } = useSnackbar(); + const [errors, setErrors] = useState([]); + const [isEdit, setEdit] = useState(false); + + const [mutate, { error }] = useExcludeHouseholdsPpMutation(); + + const handleIdsChange = (event): void => { + if (event.target.value === '') { + setErrors([]); + } + setIdsValue(event.target.value); + }; + const initialValues = { + exclusionReason: paymentPlan.exclusionReason || '', + }; + const validationSchema = Yup.object().shape({ + exclusionReason: Yup.string().max(500, t('Too long')), + }); + + const handleSave = async (values): Promise => { + const idsToSave = excludedIds.filter((id) => !deletedIds.includes(id)); + try { + await mutate({ + variables: { + paymentPlanId: paymentPlan.id, + excludedHouseholdsIds: idsToSave, + exclusionReason: values.exclusionReason || null, + }, + refetchQueries: () => [ + { + query: PaymentPlanDocument, + variables: { id: paymentPlan.id }, + fetchPolicy: 'network-only', + }, + 'AllPaymentsForTable', + ], + awaitRefetchQueries: true, + }); + if (!error) { + showMessage(t('Households exclusion started')); + setExclusionsOpen(false); + } + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + const handleApply = (): void => { + const idRegex = + /^(\s*HH-\d{2}-\d{4}\.\d{4}\s*)(,\s*HH-\d{2}-\d{4}\.\d{4}\s*)*$/; + const ids = idsValue.trim().split(/,\s*|\s+/); + const invalidIds: string[] = []; + const alreadyExcludedIds: string[] = []; + const newExcludedIds: string[] = []; + + for (const id of ids) { + if (!idRegex.test(id)) { + invalidIds.push(id); + } else if (excludedIds.includes(id.trim())) { + alreadyExcludedIds.push(id); + } else { + newExcludedIds.push(id); + } + } + + const idErrors: string[] = []; + if (invalidIds.length > 0) { + idErrors.push(` Invalid IDs: ${invalidIds.join(', ')}`); + } + if (alreadyExcludedIds.length > 0) { + idErrors.push(` IDs already excluded: ${alreadyExcludedIds.join(', ')}`); + } + + if (idErrors.length > 0) { + setErrors(idErrors); + } else { + setErrors([]); + setExcludedIds([...excludedIds, ...newExcludedIds]); + setIdsValue(''); + } + }; + + const handleDelete = (id: string): void => { + if (!deletedIds.includes(id)) { + setDeletedIds([...deletedIds, id]); + } + }; + + const handleUndo = (id: string): void => { + if (deletedIds.includes(id)) { + setDeletedIds(deletedIds.filter((deletedId) => deletedId !== id)); + } + }; + + const handleCheckIfDeleted = (id: string): boolean => deletedIds.includes(id); + + const numberOfExcluded = excludedIds.length - deletedIds.length; + + const renderButtons = (submitForm, values, resetForm): React.ReactElement => { + const noExclusions = numberOfExcluded === 0; + const editMode = isExclusionsOpen && isEdit; + const previewMode = + (!isExclusionsOpen && numberOfExcluded > 0) || + (!isExclusionsOpen && deletedIds.length > 0); + + const resetExclusions = (): void => { + setExclusionsOpen(false); + setErrors([]); + setIdsValue(''); + resetForm(); + setEdit(false); + }; + + const saveExclusions = (): void => { + submitForm(); + }; + const saveExclusionsDisabled = + !hasExcludePermission || + !hasOpenOrLockedStatus || + excludedIds.length === 0 || + Boolean(backgroundActionStatus); + + const editExclusionsDisabled = + !hasExcludePermission || !hasOpenOrLockedStatus; + + if (editMode) { + return ( + + + + + + {t('Save')} + + + ); + } + + if (previewMode) { + return ( + + ); + } + + if (isExclusionsOpen) { + return ( + + + + + {hasExcludePermission && ( + setEdit(true)} + data-cy="button-edit-exclusions" + > + {t('Edit')} + + )} + + ); + } + + if (noExclusions && !deletedIds.length) { + return ( + + ); + } + + return null; + }; + + const renderInputAndApply = (): React.ReactElement => { + const applyDisabled = + !hasExcludePermission || + !hasOpenOrLockedStatus || + Boolean(backgroundActionStatus); + + if (isEdit || numberOfExcluded === 0) { + return ( + + + + + + + + 0} + /> + + + + { + handleApply(); + }} + > + {t('Apply')} + + + + + ); + } + return null; + }; + + const formatErrorToArray = (errorsString): string[] => { + // Remove brackets and quotes + const formattedError = errorsString.replace(/\[|\]|'|"/g, ''); + + // Split the formatted error into an array of strings + const errorArray = formattedError.split(', '); + + return errorArray; + }; + + return ( + handleSave(values)} + enableReinitialize + > + {({ submitForm, values, resetForm }) => ( +
+ + + {t('Exclude')} + {renderButtons(submitForm, values, resetForm)} + + {!isExclusionsOpen && numberOfExcluded > 0 ? ( + + + {`${numberOfExcluded} ${ + numberOfExcluded === 1 ? 'Household' : 'Households' + } excluded`} + + + ) : null} + + + {isExclusionsOpen && exclusionReason && !isEdit ? ( + + + + 100 + ? 'flex-start' + : 'center' + } + mt={4} + mb={2} + > + + {t('Reason')}: + + {exclusionReason} + + {excludeHouseholdError && ( + + {formatErrorToArray(excludeHouseholdError).map( + (el) => ( + + {el} + + ), + )} + + )} + + + + ) : null} + {renderInputAndApply()} + + {errors?.map((formError) => ( + + + {formError} + + + ))} + + + {excludedIds.map((id) => ( + + handleDelete(id)} + onUndo={() => handleUndo(id)} + isDeleted={handleCheckIfDeleted(id)} + isEdit={isEdit} + /> + + ))} + + + + +
+ )} +
+ ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/ExcludedItem.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/ExcludedItem.tsx new file mode 100644 index 0000000000..61c90a8a8a --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/ExcludedItem.tsx @@ -0,0 +1,62 @@ +import { Box, Button, IconButton } from '@mui/material'; +import { Delete } from '@mui/icons-material'; +import * as React from 'react'; +import styled from 'styled-components'; +import { useTranslation } from 'react-i18next'; + +const StyledBox = styled(Box)` + width: 100%; + height: 30px; + background-color: #f4f5f6; + color: '#404040'; +`; + +interface IdDivProps { + isDeleted: boolean; +} + +const IdDiv = styled.div` + text-decoration: ${({ isDeleted }) => (isDeleted ? 'line-through' : 'none')}; +`; +interface ExcludedItemProps { + id: string; + onDelete; + onUndo; + isDeleted: boolean; + isEdit: boolean; +} + +export function ExcludedItem({ + id, + onDelete, + onUndo, + isDeleted, + isEdit, +}: ExcludedItemProps): React.ReactElement { + const { t } = useTranslation(); + + return ( + + {id} + {isEdit && + (isDeleted ? ( + + ) : ( + + + + ))} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/index.tsx new file mode 100644 index 0000000000..1b6726c1f6 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ExcludeSection/index.tsx @@ -0,0 +1 @@ +export { ExcludeSection } from './ExcludeSection'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/FspSection.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/FspSection.test.tsx new file mode 100644 index 0000000000..4628bdc4b8 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/FspSection.test.tsx @@ -0,0 +1,24 @@ +import * as React from 'react'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { render } from '../../../../testUtils/testUtils'; +import { FspSection } from './FspSection'; +import { fakeBaseUrl } from '../../../../../fixtures/core/fakeBaseUrl'; + +describe('components/paymentmodule/PaymentPlanDetails/FspSection', () => { + it('should render Set Up FSP', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); + + it('should render Edit FSP', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/FspSection.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/FspSection.tsx new file mode 100644 index 0000000000..6c90ee58d9 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/FspSection.tsx @@ -0,0 +1,111 @@ +import { Box, Button, Grid, Typography } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Link, useParams } from 'react-router-dom'; +import { PaymentPlanQuery, PaymentPlanStatus } from '@generated/graphql'; +import { ContainerColumnWithBorder } from '@core/ContainerColumnWithBorder'; +import { DividerLine } from '@core/DividerLine'; +import { LabelizedField } from '@core/LabelizedField'; +import { useProgramContext } from '../../../../programContext'; +import { VolumeByDeliveryMechanismSection } from './VolumeByDeliveryMechanismSection'; + +interface FspSectionProps { + baseUrl: string; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function FspSection({ + baseUrl, + paymentPlan, +}: FspSectionProps): React.ReactElement { + const { t } = useTranslation(); + const { id } = useParams(); + const { isActiveProgram } = useProgramContext(); + + const { deliveryMechanisms, isFollowUp } = paymentPlan; + const showFspDisplay = deliveryMechanisms.length; + const shouldDisableSetUpFsp = (): boolean => { + if (paymentPlan.isFollowUp) { + return false; + } + if (!paymentPlan.totalEntitledQuantityUsd) { + return true; + } + if (!isActiveProgram) { + return true; + } + return false; + }; + + return showFspDisplay ? ( + + + + {t('FSPs')} + {paymentPlan.status === PaymentPlanStatus.Locked && ( + + )} + + + {deliveryMechanisms.map((el) => ( + <> + + + + {el.chosenConfiguration && ( + + + + )} + + ))} + + + + + + ) : ( + + + + {t('FSPs')} + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/VolumeByDeliveryMechanismSection.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/VolumeByDeliveryMechanismSection.test.tsx new file mode 100644 index 0000000000..c7da617d07 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/VolumeByDeliveryMechanismSection.test.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; +import { fakeApolloPaymentPlan } from '../../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { render } from '../../../../../testUtils/testUtils'; +import { VolumeByDeliveryMechanismSection } from './VolumeByDeliveryMechanismSection'; + +describe('components/paymentmodule/PaymentPlanDetails/VolumeByDeliveryMechanismSection', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/VolumeByDeliveryMechanismSection.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/VolumeByDeliveryMechanismSection.tsx new file mode 100644 index 0000000000..b8da6f6bb7 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/VolumeByDeliveryMechanismSection.tsx @@ -0,0 +1,135 @@ +import { Box, Grid, Typography } from '@mui/material'; +import * as React from 'react'; +import { Pie } from 'react-chartjs-2'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { LabelizedField } from '@core/LabelizedField'; +import { FieldBorder } from '@core/FieldBorder'; + +const Title = styled.div` + padding-bottom: ${({ theme }) => theme.spacing(2)}; +`; + +const ContentWrapper = styled.div` + display: flex; +`; + +const ChartContainer = styled.div` + width: 100px; + height: 100px; + margin: 0 auto; +`; + +interface VolumeByDeliveryMechanismSectionProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +const DeliveryMechanismsColorsMap = new Map([ + ['Cardless cash withdrawal', '#FC942A'], + ['Cash', '#D8E1EE'], + ['Cash by FSP', '#D8E1EE'], + ['Cheque', '#10CB16'], + ['Deposit to Card', '#4E606A'], + ['In Kind', ' #d8d8d8'], + ['Mobile Money', '#e4e4e4'], + ['Other', '#EF4343'], + ['Pre-paid card', '#D9D1CE'], + ['Referral', '#715247'], + ['Transfer', '#003C8F'], + ['Transfer to Account', '#003C8F'], + ['Voucher', '#00ADEF'], +]); + +export const getDeliveryMechanismColor = ( + deliveryMechanism: string, +): string => { + if (DeliveryMechanismsColorsMap.has(deliveryMechanism)) { + return DeliveryMechanismsColorsMap.get(deliveryMechanism); + } + return '#CCC'; +}; + +export const VolumeByDeliveryMechanismSection: React.FC< + VolumeByDeliveryMechanismSectionProps +> = ({ paymentPlan }) => { + const { t } = useTranslation(); + const { volumeByDeliveryMechanism } = paymentPlan; + + const mappedDeliveryMechanism = volumeByDeliveryMechanism.map( + (vdm, index) => ( + + + + + + ), + ); + + const chartLabels = volumeByDeliveryMechanism.map( + (el) => `${el.deliveryMechanism.name} (${el.deliveryMechanism.fsp?.name})`, + ); + + const chartData = volumeByDeliveryMechanism.map((el) => el.volumeUsd); + + const chartColors = (): string[] => { + const defaultColorsArray = volumeByDeliveryMechanism.map((el) => + getDeliveryMechanismColor(el.deliveryMechanism.name), + ); + + return defaultColorsArray; + }; + + const data = { + labels: chartLabels, + datasets: [ + { + data: chartData, + backgroundColor: chartColors(), + }, + ], + } as any; + + const options = { + legend: { + display: false, + }, + } as any; + + return ( + + + <Typography variant="h6"> + {t('Volume by Delivery Mechanism')} + </Typography>{' '} + + + + {mappedDeliveryMechanism} + + + + + + + + + + + ); +}; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/__snapshots__/VolumeByDeliveryMechanismSection.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/__snapshots__/VolumeByDeliveryMechanismSection.test.tsx.snap new file mode 100644 index 0000000000..1dac7d9f68 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/__snapshots__/VolumeByDeliveryMechanismSection.test.tsx.snap @@ -0,0 +1,127 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/VolumeByDeliveryMechanismSection should render 1`] = ` +
+
+
+
+ Volume by Delivery Mechanism +
+ +
+
+
+
+
+
+ + Cash (Miranda Ltd) + +
+ + 0 PLN (0 USD) + +
+
+
+
+
+
+
+ + In Kind (Frazier-Watson) + +
+ + 0 PLN (0 USD) + +
+
+
+
+
+
+
+ + Transfer (Bray Group) + +
+ + 0 PLN (0 USD) + +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/index.tsx new file mode 100644 index 0000000000..e24b4c32d9 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/VolumeByDeliveryMechanismSection/index.tsx @@ -0,0 +1 @@ +export { VolumeByDeliveryMechanismSection } from './VolumeByDeliveryMechanismSection'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/__snapshots__/FspSection.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/__snapshots__/FspSection.test.tsx.snap new file mode 100644 index 0000000000..2e2f368f76 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/__snapshots__/FspSection.test.tsx.snap @@ -0,0 +1,264 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/FspSection should render Edit FSP 1`] = ` +
+
+
+
+
+ FSPs +
+ + Edit FSP + + +
+
+
+
+ + Cash + +
+ + Miranda Ltd + +
+
+
+
+
+ + In Kind + +
+ + Frazier-Watson + +
+
+
+
+
+ + Transfer + +
+ + Bray Group + +
+
+
+
+
+
+
+
+
+
+ Volume by Delivery Mechanism +
+ +
+
+
+
+
+
+ + Cash (Miranda Ltd) + +
+ + 0 PLN (0 USD) + +
+
+
+
+
+
+
+ + In Kind (Frazier-Watson) + +
+ + 0 PLN (0 USD) + +
+
+
+
+
+
+
+ + Transfer (Bray Group) + +
+ + 0 PLN (0 USD) + +
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+`; + +exports[`components/paymentmodule/PaymentPlanDetails/FspSection should render Set Up FSP 1`] = ` +
+
+
+
+
+ FSPs +
+ + Set up FSP + + +
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/index.tsx new file mode 100644 index 0000000000..e5a99c5a4f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/FspSection/index.tsx @@ -0,0 +1 @@ +export { FspSection } from './FspSection'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/ImportXlsxPaymentPlanPaymentList.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/ImportXlsxPaymentPlanPaymentList.test.tsx new file mode 100644 index 0000000000..95ca714eb6 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/ImportXlsxPaymentPlanPaymentList.test.tsx @@ -0,0 +1,22 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeImportXlsxPpListMutation } from '../../../../../fixtures/paymentmodule/fakeImportXlsxPpListMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { ImportXlsxPaymentPlanPaymentList } from './ImportXlsxPaymentPlanPaymentList'; +import { PERMISSIONS } from '../../../../config/permissions'; + +describe('components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/ImportXlsxPaymentPlanPaymentList.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/ImportXlsxPaymentPlanPaymentList.tsx new file mode 100644 index 0000000000..d6fbc9ddbc --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/ImportXlsxPaymentPlanPaymentList.tsx @@ -0,0 +1,166 @@ +import { Box, Button, Dialog, DialogActions, DialogTitle } from '@mui/material'; +import { Publish } from '@mui/icons-material'; +import get from 'lodash/get'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { ImportErrors } from '@containers/tables/payments/VerificationRecordsTable/errors/ImportErrors'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { + ImportXlsxPpListMutation, + PaymentPlanDocument, + PaymentPlanQuery, + PaymentPlanStatus, + useImportXlsxPpListMutation, +} from '@generated/graphql'; +import { DropzoneField } from '@core/DropzoneField'; +import { useProgramContext } from '../../../../programContext'; +import { LoadingButton } from '@core/LoadingButton'; + +const Error = styled.div` + color: ${({ theme }) => theme.palette.error.dark}; + padding: 20px; +`; + +interface ImportXlsxPaymentPlanPaymentListProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + permissions: string[]; +} + +export function ImportXlsxPaymentPlanPaymentList({ + paymentPlan, + permissions, +}: ImportXlsxPaymentPlanPaymentListProps): React.ReactElement { + const { showMessage } = useSnackbar(); + const [open, setOpenImport] = useState(false); + const [fileToImport, setFileToImport] = useState(null); + const { isActiveProgram } = useProgramContext(); + const { t } = useTranslation(); + + const [mutate, { data: uploadData, loading: fileLoading, error }] = + useImportXlsxPpListMutation(); + + const xlsxErrors: ImportXlsxPpListMutation['importXlsxPaymentPlanPaymentList']['errors'] = + get(uploadData, 'importXlsxPaymentPlanPaymentList.errors'); + + const handleImport = async (): Promise => { + if (fileToImport) { + try { + const { data, errors } = await mutate({ + variables: { + paymentPlanId: paymentPlan.id, + file: fileToImport, + }, + refetchQueries: () => [ + { + query: PaymentPlanDocument, + variables: { + id: paymentPlan.id, + }, + }, + ], + }); + if (!errors && !data?.importXlsxPaymentPlanPaymentList.errors?.length) { + setOpenImport(false); + showMessage(t('Your import was successful!')); + } + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + } + }; + + const canUploadFile = hasPermissions( + PERMISSIONS.PM_IMPORT_XLSX_WITH_ENTITLEMENTS, + permissions, + ); + + const shouldDisableUpload = + paymentPlan.status !== PaymentPlanStatus.Locked || + !canUploadFile || + !isActiveProgram; + + return ( + <> + + + + setOpenImport(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + > + + {t('Select File to Import')} + <> + { + if (files.length === 0) { + return; + } + const file = files[0]; + const fileSizeMB = file.size / (1024 * 1024); + if (fileSizeMB > 200) { + showMessage( + `File size is too big. It should be under 200MB, File size is ${fileSizeMB}MB`, + ); + return; + } + + setFileToImport(file); + }} + /> + {fileToImport && + (error?.graphQLErrors?.length || xlsxErrors?.length) ? ( + +

Errors

+ {error + ? error.graphQLErrors.map((x) => ( +

{x.message}

+ )) + : null} + +
+ ) : null} + + + + handleImport()} + data-cy="button-import-entitlement" + > + {t('IMPORT')} + + +
+
+ + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/__snapshots__/ImportXlsxPaymentPlanPaymentList.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/__snapshots__/ImportXlsxPaymentPlanPaymentList.test.tsx.snap new file mode 100644 index 0000000000..8a98fe1402 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/__snapshots__/ImportXlsxPaymentPlanPaymentList.test.tsx.snap @@ -0,0 +1,36 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/index.ts b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/index.ts new file mode 100644 index 0000000000..dd9e53d522 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentList/index.ts @@ -0,0 +1 @@ +export { ImportXlsxPaymentPlanPaymentList } from './ImportXlsxPaymentPlanPaymentList'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx new file mode 100644 index 0000000000..1c2ad98944 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx @@ -0,0 +1,48 @@ +import * as React from 'react'; +import { MockedProvider } from '@apollo/react-testing'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeImportXlsxPpListPerFspMutation } from '../../../../../fixtures/paymentmodule/fakeImportXlsxPpListPerFspMutation'; +import { + fakeApolloPaymentPlan, + fakeApolloPaymentPlanWithWrongBackgroundActionStatus, +} from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { render } from '../../../../testUtils/testUtils'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { ImportXlsxPaymentPlanPaymentListPerFsp } from './ImportXlsxPaymentPlanPaymentListPerFsp'; + +describe('components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); + + it('should not render', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/ImportXlsxPaymentPlanPaymentListPerFsp.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/ImportXlsxPaymentPlanPaymentListPerFsp.tsx new file mode 100644 index 0000000000..699ee884af --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/ImportXlsxPaymentPlanPaymentListPerFsp.tsx @@ -0,0 +1,183 @@ +import { Box, Button, Dialog, DialogActions, DialogTitle } from '@mui/material'; +import { Publish } from '@mui/icons-material'; +import get from 'lodash/get'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { ImportErrors } from '@containers/tables/payments/VerificationRecordsTable/errors/ImportErrors'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { + ImportXlsxPpListPerFspMutation, + PaymentPlanBackgroundActionStatus, + PaymentPlanDocument, + PaymentPlanQuery, + useImportXlsxPpListPerFspMutation, +} from '@generated/graphql'; +import { DropzoneField } from '@core/DropzoneField'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { useProgramContext } from '../../../../programContext'; +import { LoadingButton } from '@core/LoadingButton'; + +const Error = styled.div` + color: ${({ theme }) => theme.palette.error.dark}; + padding: 20px; +`; + +const UploadIcon = styled(Publish)` + color: #043f91; +`; + +const DisabledUploadIcon = styled(Publish)` + color: #00000042; +`; + +interface ImportXlsxPaymentPlanPaymentListPerFspProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + permissions: string[]; +} + +const allowedState = [ + null, + PaymentPlanBackgroundActionStatus.XlsxExportError, + PaymentPlanBackgroundActionStatus.XlsxImportError, + PaymentPlanBackgroundActionStatus.RuleEngineError, +]; + +export function ImportXlsxPaymentPlanPaymentListPerFsp({ + paymentPlan, + permissions, +}: ImportXlsxPaymentPlanPaymentListPerFspProps): React.ReactElement { + const { showMessage } = useSnackbar(); + const [open, setOpenImport] = useState(false); + const [fileToImport, setFileToImport] = useState(null); + const { isActiveProgram } = useProgramContext(); + const { t } = useTranslation(); + + const [mutate, { data: uploadData, loading: fileLoading, error }] = + useImportXlsxPpListPerFspMutation(); + + const xlsxErrors: ImportXlsxPpListPerFspMutation['importXlsxPaymentPlanPaymentListPerFsp']['errors'] = + get(uploadData, 'importXlsxPaymentPlanPaymentListPerFsp.errors'); + const canUploadReconciliation = + hasPermissions( + PERMISSIONS.PM_IMPORT_XLSX_WITH_RECONCILIATION, + permissions, + ) && allowedState.includes(paymentPlan.backgroundActionStatus); + + const handleImport = async (): Promise => { + if (fileToImport) { + try { + const { data, errors } = await mutate({ + variables: { + paymentPlanId: paymentPlan.id, + file: fileToImport, + }, + refetchQueries: () => [ + { + query: PaymentPlanDocument, + variables: { + id: paymentPlan.id, + }, + }, + ], + }); + if ( + !errors && + !data?.importXlsxPaymentPlanPaymentListPerFsp.errors?.length + ) { + setOpenImport(false); + showMessage(t('Your import was successful!')); + } + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + } + }; + + return ( + <> + {canUploadReconciliation && ( + + + + )} + setOpenImport(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + > + + {t('Select File to Import')} + <> + { + if (files.length === 0) { + return; + } + const file = files[0]; + const fileSizeMB = file.size / (1024 * 1024); + if (fileSizeMB > 200) { + showMessage( + `File size is too big. It should be under 200MB, File size is ${fileSizeMB}MB`, + ); + return; + } + + setFileToImport(file); + }} + /> + {fileToImport && + (error?.graphQLErrors?.length || xlsxErrors?.length) ? ( + +

Errors

+ {error + ? error.graphQLErrors.map((x) => ( +

{x.message}

+ )) + : null} + +
+ ) : null} + + + + handleImport()} + data-cy="button-import-submit" + > + {t('IMPORT')} + + +
+
+ + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/__snapshots__/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/__snapshots__/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx.snap new file mode 100644 index 0000000000..23514352ac --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/__snapshots__/ImportXlsxPaymentPlanPaymentListPerFsp.test.tsx.snap @@ -0,0 +1,38 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp should not render 1`] = `
`; + +exports[`components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/index.ts b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/index.ts new file mode 100644 index 0000000000..b0cec4a3f6 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp/index.ts @@ -0,0 +1 @@ +export { ImportXlsxPaymentPlanPaymentListPerFsp } from './ImportXlsxPaymentPlanPaymentListPerFsp'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/PaymentPlanDetails.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/PaymentPlanDetails.test.tsx new file mode 100644 index 0000000000..ccd2f56e01 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/PaymentPlanDetails.test.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { render } from '../../../../testUtils/testUtils'; +import { PaymentPlanDetails } from './PaymentPlanDetails'; +import { fakeBaseUrl } from '../../../../../fixtures/core/fakeBaseUrl'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetails', () => { + it('should render', () => { + const { container } = render( + , + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/PaymentPlanDetails.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/PaymentPlanDetails.tsx new file mode 100644 index 0000000000..5d0c5ba1ad --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/PaymentPlanDetails.tsx @@ -0,0 +1,108 @@ +import { Grid, Typography } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { renderUserName } from '@utils/utils'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { BlackLink } from '@core/BlackLink'; +import { ContainerColumnWithBorder } from '@core/ContainerColumnWithBorder'; +import { LabelizedField } from '@core/LabelizedField'; +import { OverviewContainer } from '@core/OverviewContainer'; +import { Title } from '@core/Title'; +import { UniversalMoment } from '@core/UniversalMoment'; +import { FieldBorder } from '@core/FieldBorder'; +import { RelatedFollowUpPaymentPlans } from './RelatedFollowUpPaymentPlans'; + +interface PaymentPlanDetailsProps { + baseUrl: string; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export const PaymentPlanDetails = ({ + baseUrl, + paymentPlan, +}: PaymentPlanDetailsProps): React.ReactElement => { + const { t } = useTranslation(); + const { + createdBy, + program, + targetPopulation, + currency, + startDate, + endDate, + dispersionStartDate, + dispersionEndDate, + followUps, + } = paymentPlan; + + return ( + + + + <Typography variant="h6">{t('Details')}</Typography> + + + + + + + {renderUserName(createdBy)} + + + + + + {program.name} + + + + + + + {targetPopulation.name} + + + + + + {currency} + + + + + {startDate} + + + + + {endDate} + + + + + {dispersionStartDate} + + + + + {dispersionEndDate} + + + + + + + + + + + + + + + ); +}; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/RelatedFollowUpPaymentPlans.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/RelatedFollowUpPaymentPlans.tsx new file mode 100644 index 0000000000..1002958170 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/RelatedFollowUpPaymentPlans.tsx @@ -0,0 +1,58 @@ +import * as React from 'react'; +import { useState } from 'react'; +import Button from '@mui/material/Button'; +import { Box } from '@mui/material'; +import { useTranslation } from 'react-i18next'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { BlackLink } from '@core/BlackLink'; +import { LabelizedField } from '@core/LabelizedField'; + +interface RelatedFollowUpPaymentPlansProps { + baseUrl: string; + followUps: PaymentPlanQuery['paymentPlan']['followUps']; +} + +export function RelatedFollowUpPaymentPlans({ + followUps, + baseUrl, +}: RelatedFollowUpPaymentPlansProps): React.ReactElement { + const { t } = useTranslation(); + const [showAll, setShowAll] = useState(false); + + const handleButtonClick = (): void => { + setShowAll(!showAll); + }; + + let followUpLinks = null; + if (followUps?.edges?.length > 0) { + const truncatedFollowUps = showAll + ? followUps.edges + : followUps.edges.slice(0, 5); + followUpLinks = truncatedFollowUps.map((followUp) => ( + + {followUp?.node?.unicefId} +
+
+ )); + } + + return ( + + + {followUpLinks || '-'} + {followUps?.edges?.length > 5 && ( + + )} + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/__snapshots__/PaymentPlanDetails.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/__snapshots__/PaymentPlanDetails.test.tsx.snap new file mode 100644 index 0000000000..7439af2ea4 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/__snapshots__/PaymentPlanDetails.test.tsx.snap @@ -0,0 +1,272 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetails should render 1`] = ` +
+
+
+
+
+ Details +
+
+
+
+
+
+
+ + Created By + +
+ + Matthew Sosa + +
+
+
+ +
+
+ + Target Population + + +
+
+
+
+ + Currency + +
+ + PLN + +
+
+
+
+
+ + Start Date + +
+ + + +
+
+
+
+
+ + End Date + +
+ + + +
+
+
+
+
+ + Dispersion Start Date + +
+ + + +
+
+
+
+
+ + Dispersion End Date + +
+ + + +
+
+
+
+
+
+
+
+ + Related Follow-Up Payment Plans + +
+ +
+ - +
+
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/index.tsx new file mode 100644 index 0000000000..a33564d3b8 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetails/index.tsx @@ -0,0 +1 @@ +export { PaymentPlanDetails } from './PaymentPlanDetails'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/ApprovePaymentPlan.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/ApprovePaymentPlan.test.tsx new file mode 100644 index 0000000000..320632e959 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/ApprovePaymentPlan.test.tsx @@ -0,0 +1,22 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { ApprovePaymentPlan } from './ApprovePaymentPlan'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/ApprovePaymentPlan', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/ApprovePaymentPlan.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/ApprovePaymentPlan.tsx new file mode 100644 index 0000000000..3bab4929ee --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/ApprovePaymentPlan.tsx @@ -0,0 +1,145 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, +} from '@mui/material'; +import * as Yup from 'yup'; +import { Field, Form, Formik } from 'formik'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { FormikTextField } from '@shared/Formik/FormikTextField/FormikTextField'; +import { LoadingButton } from '@core/LoadingButton'; +import { GreyText } from '@core/GreyText'; +import { usePaymentPlanAction } from '@hooks/usePaymentPlanAction'; +import { Action, PaymentPlanQuery } from '@generated/graphql'; +import { AutoSubmitFormOnEnter } from '@core/AutoSubmitFormOnEnter'; +import { useProgramContext } from '../../../../programContext'; + +export interface ApprovePaymentPlanProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function ApprovePaymentPlan({ + paymentPlan, +}: ApprovePaymentPlanProps): React.ReactElement { + const { t } = useTranslation(); + const { isActiveProgram } = useProgramContext(); + + const [approveDialogOpen, setApproveDialogOpen] = useState(false); + const { showMessage } = useSnackbar(); + + const { mutatePaymentPlanAction: approve, loading: loadingApprove } = + usePaymentPlanAction( + Action.Approve, + paymentPlan.id, + () => showMessage(t('Payment Plan has been approved.')), + () => setApproveDialogOpen(false), + ); + const initialValues = { + comment: '', + }; + + const validationSchema = Yup.object().shape({ + comment: Yup.string().min(4, 'Too short').max(255, 'Too long'), + }); + + const shouldShowLastApproverMessage = (): boolean => { + const approvalNumberRequired = + paymentPlan.approvalProcess?.edges[0]?.node.approvalNumberRequired; + + const approvalsCount = + paymentPlan.approvalProcess?.edges[0]?.node.actions.approval.length; + + return approvalNumberRequired - 1 === approvalsCount; + }; + + return ( + { + approve(values.comment); + resetForm({}); + }} + validationSchema={validationSchema} + > + {({ submitForm }) => ( + <> + {approveDialogOpen && } + + + + setApproveDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Approve Payment Plan')} + + + + + {t('Are you sure you want to approve this Payment Plan?')} + + {shouldShowLastApproverMessage() && ( + + + {t( + 'Note: You are the last approver. Upon proceeding, this Payment Plan will be automatically moved to authorization stage.', + )} + + + )} +
+ + +
+
+ + + + + {t('Approve')} + + + +
+ + )} +
+ ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/AuthorizePaymentPlan.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/AuthorizePaymentPlan.test.tsx new file mode 100644 index 0000000000..1d6811b78b --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/AuthorizePaymentPlan.test.tsx @@ -0,0 +1,22 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { AuthorizePaymentPlan } from './AuthorizePaymentPlan'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/AuthorizePaymentPlan', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/AuthorizePaymentPlan.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/AuthorizePaymentPlan.tsx new file mode 100644 index 0000000000..c6eb505765 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/AuthorizePaymentPlan.tsx @@ -0,0 +1,144 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, +} from '@mui/material'; +import * as Yup from 'yup'; +import { Field, Form, Formik } from 'formik'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { FormikTextField } from '@shared/Formik/FormikTextField/FormikTextField'; +import { LoadingButton } from '@core/LoadingButton'; +import { GreyText } from '@core/GreyText'; +import { usePaymentPlanAction } from '@hooks/usePaymentPlanAction'; +import { Action, PaymentPlanQuery } from '@generated/graphql'; +import { AutoSubmitFormOnEnter } from '@core/AutoSubmitFormOnEnter'; +import { useProgramContext } from '../../../../programContext'; + +export interface AuthorizePaymentPlanProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function AuthorizePaymentPlan({ + paymentPlan, +}: AuthorizePaymentPlanProps): React.ReactElement { + const { t } = useTranslation(); + const [authorizeDialogOpen, setAuthorizeDialogOpen] = useState(false); + const { isActiveProgram } = useProgramContext(); + + const { showMessage } = useSnackbar(); + const { mutatePaymentPlanAction: authorize, loading: loadingAuthorize } = + usePaymentPlanAction( + Action.Authorize, + paymentPlan.id, + () => showMessage(t('Payment Plan has been authorized.')), + () => setAuthorizeDialogOpen(false), + ); + const initialValues = { + comment: '', + }; + + const validationSchema = Yup.object().shape({ + comment: Yup.string().min(4, 'Too short').max(255, 'Too long'), + }); + + const shouldShowLastAuthorizerMessage = (): boolean => { + const authorizationNumberRequired = + paymentPlan.approvalProcess?.edges[0]?.node.authorizationNumberRequired; + + const authorizationsCount = + paymentPlan.approvalProcess?.edges[0]?.node.actions.authorization.length; + + return authorizationNumberRequired - 1 === authorizationsCount; + }; + + return ( + { + authorize(values.comment); + resetForm({}); + }} + validationSchema={validationSchema} + > + {({ submitForm }) => ( + <> + {authorizeDialogOpen && } + + + + setAuthorizeDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Authorize')} + + + + + {t('Are you sure you want to authorize this Payment Plan?')} + + {shouldShowLastAuthorizerMessage() && ( + + + {t( + 'Note: Upon Proceeding, this Payment Plan will be automatically moved to Finance Release stage.', + )} + + + )} +
+ + +
+
+ + + + + {t('Authorize')} + + + +
+ + )} +
+ ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/DeletePaymentPlan.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/DeletePaymentPlan.test.tsx new file mode 100644 index 0000000000..90c5f77132 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/DeletePaymentPlan.test.tsx @@ -0,0 +1,22 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { DeletePaymentPlan } from './DeletePaymentPlan'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/DeletePaymentPlan', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/DeletePaymentPlan.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/DeletePaymentPlan.tsx new file mode 100644 index 0000000000..5a2f47d07a --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/DeletePaymentPlan.tsx @@ -0,0 +1,98 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, +} from '@mui/material'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Delete } from '@mui/icons-material'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { PaymentPlanQuery, useDeletePpMutation } from '@generated/graphql'; +import { LoadingButton } from '@core/LoadingButton'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { useProgramContext } from '../../../../programContext'; +import { useNavigate } from 'react-router-dom'; + +export interface DeletePaymentPlanProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function DeletePaymentPlan({ + paymentPlan, +}: DeletePaymentPlanProps): React.ReactElement { + const navigate = useNavigate(); + const { t } = useTranslation(); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const { baseUrl } = useBaseUrl(); + const { showMessage } = useSnackbar(); + const [mutate, { loading: loadingDelete }] = useDeletePpMutation(); + const { id } = paymentPlan; + const { isActiveProgram } = useProgramContext(); + + const handleDelete = async (): Promise => { + try { + await mutate({ + variables: { + paymentPlanId: id, + }, + }); + showMessage(t('Payment Plan Deleted')); + navigate(`/${baseUrl}/payment-module`); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + return ( + <> + + setDeleteDialogOpen(true)} + disabled={!isActiveProgram} + > + + + + setDeleteDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Delete Payment Plan')} + + + + + {t('Are you sure you want to remove this Payment Plan?')} + + + + + + + handleDelete()} + data-cy="button-submit" + > + {t('Delete')} + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons.test.tsx new file mode 100644 index 0000000000..7d498ef5ba --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons.test.tsx @@ -0,0 +1,50 @@ +import { MockedProvider } from "@apollo/react-testing"; +import { act } from "react-dom/test-utils"; +import wait from "waait"; +import * as React from "react"; +import { fakeApolloPaymentPlan } from "../../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan"; +import { fakeExportXlsxPpListPerFspMutation } from "../../../../../../fixtures/paymentmodule/fakeExportXlsxPpListPerFspMutation"; +import { render } from "../../../../../testUtils/testUtils"; +import { AcceptedPaymentPlanHeaderButtons } from "./AcceptedPaymentPlanHeaderButtons"; + +describe("components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons", () => { + it("should render disabled buttons", async () => { + const { container } = render( + + + + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); + + it("should render not disabled buttons", async () => { + const { container } = render( + + + + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons.tsx new file mode 100644 index 0000000000..1cb868b3b4 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons.tsx @@ -0,0 +1,130 @@ +import { Box, Button } from '@mui/material'; +import { GetApp } from '@mui/icons-material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { LoadingButton } from '../../../../core/LoadingButton'; +import { CreateFollowUpPaymentPlan } from '../../../CreateFollowUpPaymentPlan'; +import { useProgramContext } from '../../../../../programContext'; +import { usePaymentPlanAction } from '../../../../../hooks/usePaymentPlanAction'; +import { + Action, + PaymentPlanBackgroundActionStatus, + PaymentPlanQuery, + useExportXlsxPpListPerFspMutation, +} from '../../../../../__generated__/graphql'; +import { SplitIntoPaymentLists } from '../SplitIntoPaymentLists'; + +export interface AcceptedPaymentPlanHeaderButtonsProps { + canDownloadXlsx: boolean; + canExportXlsx: boolean; + canSendToPaymentGateway: boolean; + canSplit: boolean; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function AcceptedPaymentPlanHeaderButtons({ + canDownloadXlsx, + canExportXlsx, + canSendToPaymentGateway, + canSplit, + paymentPlan, +}: AcceptedPaymentPlanHeaderButtonsProps): React.ReactElement { + const { t } = useTranslation(); + const { showMessage } = useSnackbar(); + const { isActiveProgram } = useProgramContext(); + + const [mutateExport, { loading: loadingExport }] = + useExportXlsxPpListPerFspMutation(); + + const { + mutatePaymentPlanAction: sendToPaymentGateway, + loading: LoadingSendToPaymentGateway, + } = usePaymentPlanAction(Action.SendToPaymentGateway, paymentPlan.id, () => + showMessage(t('Sending to Payment Gateway started')), + ); + + const shouldDisableExportXlsx = + loadingExport || + !paymentPlan.hasFspDeliveryMechanismXlsxTemplate || + !canExportXlsx || + paymentPlan?.backgroundActionStatus === + PaymentPlanBackgroundActionStatus.XlsxExporting || + !isActiveProgram; + + return ( + + <> + {paymentPlan.canCreateFollowUp && ( + + + + )} + + + + {!paymentPlan.hasPaymentListExportFile && ( + + } + data-cy="button-export-xlsx" + onClick={async () => { + try { + await mutateExport({ + variables: { + paymentPlanId: paymentPlan.id, + }, + }); + showMessage(t('Exporting XLSX started')); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }} + > + {t('Export Xlsx')} + + + )} + {paymentPlan.hasPaymentListExportFile && ( + + + + )} + {canSendToPaymentGateway && ( + + + + )} + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons.test.tsx new file mode 100644 index 0000000000..26ed5e409e --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons.test.tsx @@ -0,0 +1,26 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../../testUtils/testUtils'; +import { InApprovalPaymentPlanHeaderButtons } from './InApprovalPaymentPlanHeaderButtons'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons', () => { + it('should render with buttons', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons.tsx new file mode 100644 index 0000000000..037f25eba3 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons.tsx @@ -0,0 +1,24 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { ApprovePaymentPlan } from '../ApprovePaymentPlan'; +import { RejectPaymentPlan } from '../RejectPaymentPlan'; + +export interface InApprovalPaymentPlanHeaderButtonsProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + canReject: boolean; + canApprove: boolean; +} + +export function InApprovalPaymentPlanHeaderButtons({ + paymentPlan, + canReject, + canApprove, +}: InApprovalPaymentPlanHeaderButtonsProps): React.ReactElement { + return ( + + {canReject && } + {canApprove && } + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons.test.tsx new file mode 100644 index 0000000000..832069b346 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons.test.tsx @@ -0,0 +1,26 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../../testUtils/testUtils'; +import { InAuthorizationPaymentPlanHeaderButtons } from './InAuthorizationPaymentPlanHeaderButtons'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons', () => { + it('should render with buttons', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons.tsx new file mode 100644 index 0000000000..353dd0cc63 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons.tsx @@ -0,0 +1,24 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { AuthorizePaymentPlan } from '../AuthorizePaymentPlan'; +import { RejectPaymentPlan } from '../RejectPaymentPlan'; + +export interface InAuthorizationPaymentPlanHeaderButtonsProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + canReject: boolean; + canAuthorize: boolean; +} + +export function InAuthorizationPaymentPlanHeaderButtons({ + paymentPlan, + canReject, + canAuthorize, +}: InAuthorizationPaymentPlanHeaderButtonsProps): React.ReactElement { + return ( + + {canReject && } + {canAuthorize && } + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons.test.tsx new file mode 100644 index 0000000000..e91bf0a023 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons.test.tsx @@ -0,0 +1,26 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../../testUtils/testUtils'; +import { InReviewPaymentPlanHeaderButtons } from './InReviewPaymentPlanHeaderButtons'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons', () => { + it('should render with buttons', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons.tsx new file mode 100644 index 0000000000..c1476cde3f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons.tsx @@ -0,0 +1,26 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { MarkAsReleasedPaymentPlan } from '../MarkAsReleasedPaymentPlan'; +import { RejectPaymentPlan } from '../RejectPaymentPlan'; + +export interface InReviewPaymentPlanHeaderButtonsProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + canReject: boolean; + canMarkAsReleased: boolean; +} + +export function InReviewPaymentPlanHeaderButtons({ + paymentPlan, + canReject, + canMarkAsReleased, +}: InReviewPaymentPlanHeaderButtonsProps): React.ReactElement { + return ( + + {canReject && } + {canMarkAsReleased && ( + + )} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedFspPaymentPlanHeaderButtons.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedFspPaymentPlanHeaderButtons.tsx new file mode 100644 index 0000000000..22a153564e --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedFspPaymentPlanHeaderButtons.tsx @@ -0,0 +1,68 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { usePaymentPlanAction } from '@hooks/usePaymentPlanAction'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { Action, PaymentPlanQuery } from '@generated/graphql'; +import { LoadingButton } from '@core/LoadingButton'; +import { useProgramContext } from '../../../../../programContext'; + +export interface LockedFspPaymentPlanHeaderButtonsProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + canUnlock: boolean; + canSendForApproval: boolean; +} + +export function LockedFspPaymentPlanHeaderButtons({ + paymentPlan, + canUnlock, + canSendForApproval, +}: LockedFspPaymentPlanHeaderButtonsProps): React.ReactElement { + const { t } = useTranslation(); + const { id } = paymentPlan; + const { showMessage } = useSnackbar(); + const { isActiveProgram } = useProgramContext(); + + const { mutatePaymentPlanAction: unlock, loading: loadingUnlock } = + usePaymentPlanAction(Action.UnlockFsp, id, () => + showMessage(t('Payment Plan FSPs have been unlocked.')), + ); + const { + mutatePaymentPlanAction: sendForApproval, + loading: loadingSendForApproval, + } = usePaymentPlanAction(Action.SendForApproval, id, () => + showMessage(t('Payment Plan has been sent for approval.')), + ); + + return ( + + {canUnlock && ( + + unlock()} + disabled={!isActiveProgram} + > + {t('Unlock FSP')} + + + )} + {canSendForApproval && ( + + sendForApproval()} + data-cy="button-send-for-approval" + disabled={!isActiveProgram} + > + {t('Send For Approval')} + + + )} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons.test.tsx new file mode 100644 index 0000000000..7e1f6f40a2 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons.test.tsx @@ -0,0 +1,27 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../../testUtils/testUtils'; +import { PERMISSIONS } from '../../../../../config/permissions'; +import { LockedPaymentPlanHeaderButtons } from './LockedPaymentPlanHeaderButtons'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons', () => { + it('should render with buttons', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons.tsx new file mode 100644 index 0000000000..1d7f0445ec --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons.tsx @@ -0,0 +1,50 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { usePaymentPlanAction } from '@hooks/usePaymentPlanAction'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { Action, PaymentPlanQuery } from '@generated/graphql'; +import { LoadingButton } from '@core/LoadingButton'; +import { LockFspPaymentPlan } from '../LockFspPaymentPlan'; +import { useProgramContext } from '../../../../../programContext'; + +export interface LockedPaymentPlanHeaderButtonsProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + canUnlock: boolean; + permissions: string[]; +} + +export function LockedPaymentPlanHeaderButtons({ + paymentPlan, + canUnlock, + permissions, +}: LockedPaymentPlanHeaderButtonsProps): React.ReactElement { + const { t } = useTranslation(); + const { id } = paymentPlan; + const { showMessage } = useSnackbar(); + const { isActiveProgram } = useProgramContext(); + + const { mutatePaymentPlanAction: unlock, loading: loadingUnlock } = + usePaymentPlanAction(Action.Unlock, id, () => + showMessage(t('Payment Plan has been unlocked.')), + ); + + return ( + + {canUnlock && ( + + unlock()} + disabled={!isActiveProgram} + > + {t('Unlock')} + + + )} + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons.test.tsx new file mode 100644 index 0000000000..440e60517a --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons.test.tsx @@ -0,0 +1,27 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../../testUtils/testUtils'; +import { OpenPaymentPlanHeaderButtons } from './OpenPaymentPlanHeaderButtons'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons', () => { + it('should render with buttons', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons.tsx new file mode 100644 index 0000000000..7927f5e2d1 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons.tsx @@ -0,0 +1,56 @@ +import { Box, Button } from '@mui/material'; +import { EditRounded } from '@mui/icons-material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Link } from 'react-router-dom'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { DeletePaymentPlan } from '../DeletePaymentPlan'; +import { LockPaymentPlan } from '../LockPaymentPlan'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { useProgramContext } from '../../../../../programContext'; + +export interface OpenPaymentPlanHeaderButtonsProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + canRemove: boolean; + canEdit: boolean; + canLock: boolean; +} + +export function OpenPaymentPlanHeaderButtons({ + paymentPlan, + canRemove, + canEdit, + canLock, +}: OpenPaymentPlanHeaderButtonsProps): React.ReactElement { + const { t } = useTranslation(); + const { baseUrl } = useBaseUrl(); + const { isActiveProgram } = useProgramContext(); + const { id, isFollowUp } = paymentPlan; + + return ( + + {canRemove && } + {canEdit && ( + + + + )} + {canLock && ( + + + + )} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/AcceptedPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/AcceptedPaymentPlanHeaderButtons.test.tsx.snap new file mode 100644 index 0000000000..5f30b8cb0e --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/AcceptedPaymentPlanHeaderButtons.test.tsx.snap @@ -0,0 +1,156 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons should render disabled buttons 1`] = ` +
+
+
+
+ +
+
+
+ +
+
+
+`; + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/AcceptedPaymentPlanHeaderButtons should render not disabled buttons 1`] = ` +
+
+
+
+ +
+
+
+ +
+
+ +
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InApprovalPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InApprovalPaymentPlanHeaderButtons.test.tsx.snap new file mode 100644 index 0000000000..22231e7d0f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InApprovalPaymentPlanHeaderButtons.test.tsx.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InApprovalPaymentPlanHeaderButtons should render with buttons 1`] = ` +
+
+
+ +
+
+ +
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InAuthorizationPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InAuthorizationPaymentPlanHeaderButtons.test.tsx.snap new file mode 100644 index 0000000000..c888f0a2cb --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InAuthorizationPaymentPlanHeaderButtons.test.tsx.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InAuthorizationPaymentPlanHeaderButtons should render with buttons 1`] = ` +
+
+
+ +
+
+ +
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InReviewPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InReviewPaymentPlanHeaderButtons.test.tsx.snap new file mode 100644 index 0000000000..dccbd8e964 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/InReviewPaymentPlanHeaderButtons.test.tsx.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/InReviewPaymentPlanHeaderButtons should render with buttons 1`] = ` +
+
+
+ +
+
+ +
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/LockedPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/LockedPaymentPlanHeaderButtons.test.tsx.snap new file mode 100644 index 0000000000..39fd92a70f --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/LockedPaymentPlanHeaderButtons.test.tsx.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/LockedPaymentPlanHeaderButtons should render with buttons 1`] = ` +
+
+
+ +
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/OpenPaymentPlanHeaderButtons.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/OpenPaymentPlanHeaderButtons.test.tsx.snap new file mode 100644 index 0000000000..2653fdf16b --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/__snapshots__/OpenPaymentPlanHeaderButtons.test.tsx.snap @@ -0,0 +1,82 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/HeaderButtons/OpenPaymentPlanHeaderButtons should render with buttons 1`] = ` +
+
+
+ +
+ +
+
+ +
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockFspPaymentPlan.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockFspPaymentPlan.tsx new file mode 100644 index 0000000000..4e0e554ba0 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockFspPaymentPlan.tsx @@ -0,0 +1,97 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, +} from '@mui/material'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { usePaymentPlanAction } from '@hooks/usePaymentPlanAction'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { Action, PaymentPlanQuery } from '@generated/graphql'; +import { LoadingButton } from '@core/LoadingButton'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { useProgramContext } from '../../../../programContext'; + +export interface LockFspPaymentPlanProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + permissions: string[]; +} + +export function LockFspPaymentPlan({ + paymentPlan, + permissions, +}: LockFspPaymentPlanProps): React.ReactElement { + const { t } = useTranslation(); + const { showMessage } = useSnackbar(); + const { isActiveProgram } = useProgramContext(); + const [lockDialogOpen, setLockDialogOpen] = useState(false); + const { mutatePaymentPlanAction: lock, loading: loadingLock } = + usePaymentPlanAction( + Action.LockFsp, + paymentPlan.id, + () => showMessage(t('Payment Plan FSPs are locked.')), + () => setLockDialogOpen(false), + ); + + const canLockFsp = + paymentPlan.deliveryMechanisms.length > 0 && + hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK_FSP, permissions); + + return ( + <> + + + + setLockDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Lock FSP')} + + + + + {t( + 'After you lock the FSP in this Payment Plan, you will be able to send the Payment Plan for approval.', + )} + + + + + + + lock()} + data-cy="button-submit" + > + {t('Lock FSP')} + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockPaymentPlan.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockPaymentPlan.test.tsx new file mode 100644 index 0000000000..f2a3718c76 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockPaymentPlan.test.tsx @@ -0,0 +1,22 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { LockPaymentPlan } from './LockPaymentPlan'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/LockPaymentPlan', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockPaymentPlan.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockPaymentPlan.tsx new file mode 100644 index 0000000000..9aaff57a92 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/LockPaymentPlan.tsx @@ -0,0 +1,103 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, +} from '@mui/material'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { usePaymentPlanAction } from '@hooks/usePaymentPlanAction'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { Action, PaymentPlanQuery } from '@generated/graphql'; +import { GreyText } from '@core/GreyText'; +import { LoadingButton } from '@core/LoadingButton'; + +export interface LockPaymentPlanProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function LockPaymentPlan({ + paymentPlan, +}: LockPaymentPlanProps): React.ReactElement { + const { t } = useTranslation(); + const { showMessage } = useSnackbar(); + const [lockDialogOpen, setLockDialogOpen] = useState(false); + const { mutatePaymentPlanAction: lock, loading: loadingLock } = + usePaymentPlanAction( + Action.Lock, + paymentPlan.id, + () => showMessage(t('Payment Plan has been locked.')), + () => setLockDialogOpen(false), + ); + + return ( + <> + + + + setLockDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Lock Payment Plan')} + + + + + {t( + 'After you lock this Payment Plan, you will be able to run entitlement formula for selected target population.', + )} + + {paymentPlan.paymentsConflictsCount > 0 && ( + + + {t('Note:')}{' '} + {paymentPlan.paymentsConflictsCount === 1 + ? t('There is') + : t('There are')}{' '} + {paymentPlan.paymentsConflictsCount}{' '} + {paymentPlan.paymentsConflictsCount === 1 + ? t('household') + : t('households')}{' '} + {t('that will be ignored in this Payment Plan.')} + + + )} + + + + + + lock()} + data-cy="button-submit" + > + {t('Lock')} + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan.test.tsx new file mode 100644 index 0000000000..51b4c41e26 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan.test.tsx @@ -0,0 +1,22 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { MarkAsReleasedPaymentPlan } from './MarkAsReleasedPaymentPlan'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan.tsx new file mode 100644 index 0000000000..f283692c21 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan.tsx @@ -0,0 +1,146 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, +} from '@mui/material'; +import { Field, Form, Formik } from 'formik'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import * as Yup from 'yup'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { usePaymentPlanAction } from '@hooks/usePaymentPlanAction'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { FormikTextField } from '@shared/Formik/FormikTextField/FormikTextField'; +import { Action, PaymentPlanQuery } from '@generated/graphql'; +import { AutoSubmitFormOnEnter } from '@core/AutoSubmitFormOnEnter'; +import { GreyText } from '@core/GreyText'; +import { LoadingButton } from '@core/LoadingButton'; +import { useProgramContext } from '../../../../programContext'; + +export interface MarkAsReleasedPaymentPlanProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function MarkAsReleasedPaymentPlan({ + paymentPlan, +}: MarkAsReleasedPaymentPlanProps): React.ReactElement { + const { t } = useTranslation(); + const { isActiveProgram } = useProgramContext(); + const [markAsReleasedDialogOpen, setMarkAsReleasedDialogOpen] = + useState(false); + const { showMessage } = useSnackbar(); + const { mutatePaymentPlanAction: review, loading: loadingReview } = + usePaymentPlanAction( + Action.Review, + paymentPlan.id, + () => showMessage(t('Payment Plan has been marked as reviewed.')), + () => setMarkAsReleasedDialogOpen(false), + ); + + const shouldShowLastReviewerMessage = (): boolean => { + const financeReleaseNumberRequired = + paymentPlan.approvalProcess?.edges[0]?.node.financeReleaseNumberRequired; + const financeReleasesCount = + paymentPlan.approvalProcess?.edges[0]?.node.actions.financeRelease.length; + + return financeReleaseNumberRequired - 1 === financeReleasesCount; + }; + + const initialValues = { + comment: '', + }; + + const validationSchema = Yup.object().shape({ + comment: Yup.string().min(4, 'Too short').max(255, 'Too long'), + }); + + return ( + { + review(values.comment); + resetForm({}); + }} + validationSchema={validationSchema} + > + {({ submitForm }) => ( + <> + {markAsReleasedDialogOpen && } + + + + setMarkAsReleasedDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Mark as Released')} + + + + + {t( + 'Are you sure you want to mark this Payment Plan as released?', + )} + + {shouldShowLastReviewerMessage() && ( + + + {t( + 'Note: You are the last reviewer. Upon proceeding, this Payment Plan will be automatically moved to accepted status', + )} + + + )} +
+ + +
+
+ + + + + {t('Mark as released')} + + + +
+ + )} +
+ ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/PaymentPlanDetailsHeader.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/PaymentPlanDetailsHeader.test.tsx new file mode 100644 index 0000000000..51b4c41e26 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/PaymentPlanDetailsHeader.test.tsx @@ -0,0 +1,22 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { MarkAsReleasedPaymentPlan } from './MarkAsReleasedPaymentPlan'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/PaymentPlanDetailsHeader.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/PaymentPlanDetailsHeader.tsx new file mode 100644 index 0000000000..6778ffd540 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/PaymentPlanDetailsHeader.tsx @@ -0,0 +1,203 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { hasPermissions, PERMISSIONS } from '../../../../config/permissions'; +import { + paymentPlanBackgroundActionStatusToColor, + paymentPlanStatusToColor, +} from '@utils/utils'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { BreadCrumbsItem } from '@core/BreadCrumbs'; +import { PageHeader } from '@core/PageHeader'; +import { StatusBox } from '@core/StatusBox'; +import { AcceptedPaymentPlanHeaderButtons } from './HeaderButtons/AcceptedPaymentPlanHeaderButtons'; +import { InApprovalPaymentPlanHeaderButtons } from './HeaderButtons/InApprovalPaymentPlanHeaderButtons'; +import { InAuthorizationPaymentPlanHeaderButtons } from './HeaderButtons/InAuthorizationPaymentPlanHeaderButtons'; +import { InReviewPaymentPlanHeaderButtons } from './HeaderButtons/InReviewPaymentPlanHeaderButtons'; +import { LockedFspPaymentPlanHeaderButtons } from './HeaderButtons/LockedFspPaymentPlanHeaderButtons'; +import { LockedPaymentPlanHeaderButtons } from './HeaderButtons/LockedPaymentPlanHeaderButtons'; +import { OpenPaymentPlanHeaderButtons } from './HeaderButtons/OpenPaymentPlanHeaderButtons'; +import { AdminButton } from '@core/AdminButton'; + +interface PaymentPlanDetailsHeaderProps { + baseUrl: string; + permissions: string[]; + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function PaymentPlanDetailsHeader({ + baseUrl, + permissions, + paymentPlan, +}: PaymentPlanDetailsHeaderProps): React.ReactElement { + const { t } = useTranslation(); + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/`, + }, + ]; + + const canRemove = hasPermissions(PERMISSIONS.PM_CREATE, permissions); + const canEdit = hasPermissions(PERMISSIONS.PM_CREATE, permissions); + const canLock = hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK, permissions); + const canUnlock = hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK, permissions); + const canSendForApproval = hasPermissions( + PERMISSIONS.PM_SEND_FOR_APPROVAL, + permissions, + ); + const canApprove = hasPermissions( + PERMISSIONS.PM_ACCEPTANCE_PROCESS_APPROVE, + permissions, + ); + const canAuthorize = hasPermissions( + PERMISSIONS.PM_ACCEPTANCE_PROCESS_AUTHORIZE, + permissions, + ); + const canMarkAsReleased = hasPermissions( + PERMISSIONS.PM_ACCEPTANCE_PROCESS_FINANCIAL_REVIEW, + permissions, + ); + const canDownloadXlsx = hasPermissions( + PERMISSIONS.PM_DOWNLOAD_XLSX_FOR_FSP, + permissions, + ); + const canExportXlsx = hasPermissions( + PERMISSIONS.PM_EXPORT_XLSX_FOR_FSP, + permissions, + ); + const canSendToPaymentGateway = + hasPermissions(PERMISSIONS.PM_SEND_TO_PAYMENT_GATEWAY, permissions) && + paymentPlan.canSendToPaymentGateway; + const canSplit = + hasPermissions(PERMISSIONS.PM_SPLIT, permissions) && paymentPlan.canSplit; + + let buttons: React.ReactElement | null = null; + switch (paymentPlan.status) { + case 'OPEN': + buttons = ( + + ); + break; + case 'LOCKED': + buttons = ( + + ); + break; + case 'LOCKED_FSP': + buttons = ( + + ); + break; + case 'IN_APPROVAL': + buttons = ( + + ); + break; + case 'IN_AUTHORIZATION': + buttons = ( + + ); + break; + case 'IN_REVIEW': + buttons = ( + + ); + break; + case 'ACCEPTED': + buttons = ( + + ); + break; + case 'FINISHED': // TODO: may create another one for that explicitly but good for now + buttons = ( + + ); + break; + default: + break; + } + + return ( + + + {t('Payment Plan')} ID: + + {paymentPlan.unicefId} + + + + + + {paymentPlan.backgroundActionStatus && ( + + + + )} + + } + breadCrumbs={ + hasPermissions(PERMISSIONS.PM_VIEW_DETAILS, permissions) + ? breadCrumbsItems + : null + } + flags={} + > + {buttons} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/RejectPaymentPlan.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/RejectPaymentPlan.test.tsx new file mode 100644 index 0000000000..5f3f121dcb --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/RejectPaymentPlan.test.tsx @@ -0,0 +1,22 @@ +import { MockedProvider } from '@apollo/react-testing'; +import * as React from 'react'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { RejectPaymentPlan } from './RejectPaymentPlan'; + +describe('components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/RejectPaymentPlan', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/RejectPaymentPlan.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/RejectPaymentPlan.tsx new file mode 100644 index 0000000000..8d164aeb44 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/RejectPaymentPlan.tsx @@ -0,0 +1,129 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, +} from '@mui/material'; +import { Field, Form, Formik } from 'formik'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import * as Yup from 'yup'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { usePaymentPlanAction } from '@hooks/usePaymentPlanAction'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { FormikTextField } from '@shared/Formik/FormikTextField/FormikTextField'; +import { Action } from '@generated/graphql'; +import { AutoSubmitFormOnEnter } from '@core/AutoSubmitFormOnEnter'; +import { ErrorButton } from '@core/ErrorButton'; +import { GreyText } from '@core/GreyText'; +import { LoadingButton } from '@core/LoadingButton'; +import { useProgramContext } from '../../../../programContext'; + +export interface RejectPaymentPlanProps { + paymentPlanId: string; +} + +export function RejectPaymentPlan({ + paymentPlanId, +}: RejectPaymentPlanProps): React.ReactElement { + const { t } = useTranslation(); + const [rejectDialogOpen, setRejectDialogOpen] = useState(false); + const { showMessage } = useSnackbar(); + const { isActiveProgram } = useProgramContext(); + const { mutatePaymentPlanAction: reject, loading: loadingReject } = + usePaymentPlanAction( + Action.Reject, + paymentPlanId, + () => showMessage(t('Payment Plan has been rejected.')), + () => setRejectDialogOpen(false), + ); + + const initialValues = { + comment: '', + }; + + const validationSchema = Yup.object().shape({ + comment: Yup.string().min(4, 'Too short').max(255, 'Too long'), + }); + + return ( + { + reject(values.comment); + setRejectDialogOpen(false); + resetForm({}); + }} + validationSchema={validationSchema} + > + {({ submitForm }) => ( + <> + {rejectDialogOpen && } + + setRejectDialogOpen(true)}> + {t('Reject')} + + + setRejectDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Reject Payment Plan')} + + + + + {t('Are you sure you want to reject this payment plan?')} + + + + {t( + 'Note: Upon proceeding this payment plan will be automatically moved to locked status.', + )} + + +
+ + +
+
+ + + + + {t('Reject')} + + + +
+ + )} +
+ ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/SplitIntoPaymentLists.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/SplitIntoPaymentLists.tsx new file mode 100644 index 0000000000..338c2b6e34 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/SplitIntoPaymentLists.tsx @@ -0,0 +1,164 @@ +import { Field, Form, Formik } from 'formik'; +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import * as Yup from 'yup'; +import { FormikSelectField } from '@shared/Formik/FormikSelectField'; +import { DialogContainer } from '@containers/dialogs/DialogContainer'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { PaymentPlanQuery, useSplitPpMutation } from '@generated/graphql'; +import { LoadingButton } from '@core/LoadingButton'; +import { FormikTextField } from '@shared/Formik/FormikTextField'; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Grid, +} from '@mui/material'; +import ReorderIcon from '@mui/icons-material/Reorder'; + +interface FormValues { + splitType: string; + paymentsNo: number; +} + +const initialValues: FormValues = { + splitType: '', + paymentsNo: 0, +}; + +interface SplitIntoPaymentListsProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + canSplit: boolean; +} + +export const SplitIntoPaymentLists = ({ + paymentPlan, + canSplit, +}: SplitIntoPaymentListsProps): React.ReactElement => { + const [dialogOpen, setDialogOpen] = useState(false); + const { t } = useTranslation(); + const [mutate, { loading }] = useSplitPpMutation(); + const { showMessage } = useSnackbar(); + + let minPaymentsNoMessage = 'Payments Number must be greater than 10'; + let maxPaymentsNoMessage = `Payments Number must be less than ${paymentPlan.paymentItems.totalCount}`; + + if (paymentPlan.paymentItems.totalCount <= 10) { + const msg = `There are too few payments (${paymentPlan.paymentItems.totalCount}) to split`; + minPaymentsNoMessage = msg; + maxPaymentsNoMessage = msg; + } + + const validationSchema = Yup.object().shape({ + splitType: Yup.string().required('Split Type is required'), + paymentsNo: Yup.number().when('splitType', { + is: 'BY_RECORDS', + then: (schema) => + schema + .required('Payments Number is required') + .min(10, minPaymentsNoMessage) + .max( + paymentPlan.paymentItems.totalCount, + maxPaymentsNoMessage, + ), + }), + }); + + const handleSplit = async (values): Promise => { + try { + const { errors } = await mutate({ + variables: { + paymentPlanId: paymentPlan.id, + splitType: values.splitType, + paymentsNo: values.paymentsNo, + }, + }); + if (!errors) { + setDialogOpen(false); + showMessage(t('Split was successful!')); + } + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + return ( + { + await handleSplit(values); + }} + > + {({ values, submitForm }) => ( +
+ + setDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Split into Payment Lists')} + + + + + + + + + {values.splitType === 'BY_RECORDS' && ( + + )} + + + + + + + + + {t('Split')} + + + + +
+ )} +
+ ); +}; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/ApprovePaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/ApprovePaymentPlan.test.tsx.snap new file mode 100644 index 0000000000..f6385c55fe --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/ApprovePaymentPlan.test.tsx.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/ApprovePaymentPlan should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/AuthorizePaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/AuthorizePaymentPlan.test.tsx.snap new file mode 100644 index 0000000000..37fd359063 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/AuthorizePaymentPlan.test.tsx.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/AuthorizePaymentPlan should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/DeletePaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/DeletePaymentPlan.test.tsx.snap new file mode 100644 index 0000000000..11626906a4 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/DeletePaymentPlan.test.tsx.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/DeletePaymentPlan should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/LockPaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/LockPaymentPlan.test.tsx.snap new file mode 100644 index 0000000000..ef53d3dbe4 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/LockPaymentPlan.test.tsx.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/LockPaymentPlan should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/MarkAsReleasedPaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/MarkAsReleasedPaymentPlan.test.tsx.snap new file mode 100644 index 0000000000..1e7d743b4c --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/MarkAsReleasedPaymentPlan.test.tsx.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/PaymentPlanDetailsHeader.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/PaymentPlanDetailsHeader.test.tsx.snap new file mode 100644 index 0000000000..1e7d743b4c --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/PaymentPlanDetailsHeader.test.tsx.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/MarkAsReleasedPaymentPlan should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/RejectPaymentPlan.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/RejectPaymentPlan.test.tsx.snap new file mode 100644 index 0000000000..6e10334a9d --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/__snapshots__/RejectPaymentPlan.test.tsx.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader/RejectPaymentPlan should render 1`] = ` +
+
+ +
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/index.tsx new file mode 100644 index 0000000000..0e269627f2 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PaymentPlanDetailsHeader/index.tsx @@ -0,0 +1 @@ +export { PaymentPlanDetailsHeader } from './PaymentPlanDetailsHeader'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/PeoplePaymentPlanDetailsResults.test.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/PeoplePaymentPlanDetailsResults.test.tsx new file mode 100644 index 0000000000..dea943a00c --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/PeoplePaymentPlanDetailsResults.test.tsx @@ -0,0 +1,21 @@ +import { MockedProvider } from '@apollo/react-testing'; +import { act } from 'react-dom/test-utils'; +import wait from 'waait'; +import { fakeApolloPaymentPlan } from '../../../../../fixtures/paymentmodule/fakeApolloPaymentPlan'; +import { fakeActionPpMutation } from '../../../../../fixtures/paymentmodule/fakeApolloActionPaymentPlanMutation'; +import { render } from '../../../../testUtils/testUtils'; +import { PeoplePaymentPlanDetailsResults } from './PeoplePaymentPlanDetailsResults'; + +describe('components/paymentmodule/PaymentPlanDetails/PeoplePaymentPlanDetailsHeader/PaymentPlanDetailsResults', () => { + it('should render', async () => { + const { container } = render( + + + , + ); + + await act(() => wait(0)); // wait for the mutation to complete + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/PeoplePaymentPlanDetailsResults.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/PeoplePaymentPlanDetailsResults.tsx new file mode 100644 index 0000000000..ac4e6a8e70 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/PeoplePaymentPlanDetailsResults.tsx @@ -0,0 +1,173 @@ +import { Grid, Typography } from '@mui/material'; +import * as React from 'react'; +import { Pie } from 'react-chartjs-2'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { MiśTheme } from '../../../../theme'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { LabelizedField } from '@core/LabelizedField'; +import { PaperContainer } from '../../../targeting/PaperContainer'; +import { FieldBorder } from '@core/FieldBorder'; + +const colors = { + femaleChildren: '#5F02CF', + maleChildren: '#1D6A64', + femaleAdult: '#DFCCF5', + maleAdult: '#B1E3E0', +}; + +const Title = styled.div` + padding-bottom: ${({ theme }) => theme.spacing(2)}; +`; + +const ContentWrapper = styled.div` + display: flex; +`; + +const SummaryBorder = styled.div` + padding: ${({ theme }) => theme.spacing(4)}; + border-color: #b1b1b5; + border-left-width: 1px; + border-left-style: solid; +`; + +const SummaryValue = styled.div` + font-family: ${({ theme }: { theme: MiśTheme }) => + theme.hctTypography.fontFamily}; + color: #253b46; + font-size: 36px; + line-height: 32px; + margin-top: ${({ theme }) => theme.spacing(2)}; +`; + +const ChartContainer = styled.div` + width: 100px; + height: 100px; + margin: 0 auto; +`; + +interface PeoplePaymentPlanDetailsResultsProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export const PeoplePaymentPlanDetailsResults = ({ + paymentPlan, +}: PeoplePaymentPlanDetailsResultsProps): React.ReactElement => { + const { t } = useTranslation(); + const { + femaleChildrenCount, + maleChildrenCount, + femaleAdultsCount, + maleAdultsCount, + totalIndividualsCount, + } = paymentPlan; + + return ( + + + <Typography variant="h6">{t('Results')}</Typography> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {totalIndividualsCount || '0'} + + + + + + + + + ); +}; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/__snapshots__/PeoplePaymentPlanDetailsResults.test.tsx.snap b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/__snapshots__/PeoplePaymentPlanDetailsResults.test.tsx.snap new file mode 100644 index 0000000000..21b1e61c2a --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/__snapshots__/PeoplePaymentPlanDetailsResults.test.tsx.snap @@ -0,0 +1,204 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/PaymentPlanDetails/PeoplePaymentPlanDetailsHeader/PaymentPlanDetailsResults should render 1`] = ` +
+
+
+
+ Results +
+
+
+
+
+
+
+
+
+ + Female Children + +
+ + 0 + +
+
+
+
+
+
+
+ + Female Adults + +
+ + 1 + +
+
+
+
+
+
+
+ + Male Children + +
+ + 0 + +
+
+
+
+
+
+
+ + Male Adults + +
+ + 2 + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + Total Number of People + +
+ +
+ 3 +
+
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/index.tsx new file mode 100644 index 0000000000..cc6c0fdb81 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults/index.tsx @@ -0,0 +1 @@ +export { PeoplePaymentPlanDetailsResults } from './PeoplePaymentPlanDetailsResults'; diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ReconciliationSummary/ReconciliationSummary.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ReconciliationSummary/ReconciliationSummary.tsx new file mode 100644 index 0000000000..fd5e28c081 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ReconciliationSummary/ReconciliationSummary.tsx @@ -0,0 +1,153 @@ +import * as React from 'react'; +import { Grid, Typography } from '@mui/material'; +import { Pie } from 'react-chartjs-2'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { PaperContainer } from '../../../targeting/PaperContainer'; +import { LabelizedField } from '@core/LabelizedField'; +import { FieldBorder } from '@core/FieldBorder'; + +const Title = styled.div` + padding-bottom: ${({ theme }) => theme.spacing(2)}; +`; + +const ContentWrapper = styled.div` + display: flex; +`; + +const ChartContainer = styled.div` + width: 100px; + height: 100px; + margin: 0 auto; +`; + +const ReconciliationWrapUp = styled.div` + padding-bottom: 8px; +`; + +interface ReconciliationSummaryProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; +} + +export function ReconciliationSummary({ + paymentPlan, +}: ReconciliationSummaryProps): React.ReactElement { + const { t } = useTranslation(); + + const { + reconciliationSummary: { + deliveredFully, + deliveredPartially, + unsuccessful, + notDelivered, + numberOfPayments, + pending, + reconciled, + }, + } = paymentPlan; + + const datasets = [ + { + label: t('Delivered fully'), + value: deliveredFully, + color: '#10CB16', + }, + { + label: t('Delivered partially'), + value: deliveredPartially, + color: '#FC942A', + }, + { + label: t('Not delivered'), + value: notDelivered, + color: '#EF4343', + }, + { + label: t('Unsuccessful'), + value: unsuccessful, + color: '#EF4343', + }, + { + label: t('Pending'), + value: pending, + color: '#4E606A', + }, + ]; + + const reconciledInPercent = ((reconciled / numberOfPayments) * 100).toFixed( + 0, + ); + return ( + + + <Typography variant="h6">{t('Reconciliation Summary')}</Typography> + + + + + + + {datasets.map(({ color, label, value }) => ( + + + + + + ))} + + + label), + datasets: [ + { + data: datasets.map(({ value }) => value), + backgroundColor: datasets.map(({ color }) => color), + }, + ], + }} + /> + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ReconciliationSummary/index.tsx b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ReconciliationSummary/index.tsx new file mode 100644 index 0000000000..a6fbc19b96 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/PaymentPlanDetails/ReconciliationSummary/index.tsx @@ -0,0 +1 @@ +export { ReconciliationSummary } from './ReconciliationSummary'; diff --git a/frontend/src/components/paymentmodulepeople/RevertForceFailedButton.tsx b/frontend/src/components/paymentmodulepeople/RevertForceFailedButton.tsx new file mode 100644 index 0000000000..ed4def1b43 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/RevertForceFailedButton.tsx @@ -0,0 +1,134 @@ +import { Box, Button, DialogContent, DialogTitle } from '@mui/material'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Field, Form, Formik } from 'formik'; +import * as Yup from 'yup'; +import CalendarTodayRoundedIcon from '@mui/icons-material/CalendarTodayRounded'; +import { Dialog } from '@containers/dialogs/Dialog'; +import { DialogActions } from '@containers/dialogs/DialogActions'; +import { DialogFooter } from '@containers/dialogs/DialogFooter'; +import { DialogTitleWrapper } from '@containers/dialogs/DialogTitleWrapper'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { FormikTextField } from '@shared/Formik/FormikTextField'; +import { FormikDateField } from '@shared/Formik/FormikDateField'; +import { useRevertMarkPayAsFailedMutation } from '@generated/graphql'; + +export interface RevertForceFailedButtonProps { + paymentId: string; + disabled?: boolean; +} +export function RevertForceFailedButton({ + paymentId, + disabled = false, +}: RevertForceFailedButtonProps): React.ReactElement { + const { t } = useTranslation(); + const [isOpenModal, setOpenModal] = useState(false); + const { showMessage } = useSnackbar(); + const [mutate, { loading }] = useRevertMarkPayAsFailedMutation(); + + const validationSchema = Yup.object().shape({ + deliveredQuantity: Yup.number() + .min(0) + .max(99999999, t('Number is too big')), + deliveryDate: Yup.date().required(t('Delivery date is required')), + }); + + const submit = async (values, { resetForm }): Promise => { + try { + await mutate({ + variables: { + paymentId, + deliveredQuantity: values.deliveredQuantity, + deliveryDate: values.deliveryDate, + }, + }); + setOpenModal(false); + showMessage(t('Force failed has been reverted.')); + resetForm(); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + return ( + + + + + + {({ submitForm, resetForm }) => ( + setOpenModal(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Revert mark as failed')} + + +
+ + } + /> + +
+ + + + + + +
+ )} +
+
+ ); +} diff --git a/frontend/src/components/paymentmodulepeople/WarningMissingAmount.test.tsx b/frontend/src/components/paymentmodulepeople/WarningMissingAmount.test.tsx new file mode 100644 index 0000000000..2f625ad645 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/WarningMissingAmount.test.tsx @@ -0,0 +1,13 @@ +import * as React from 'react'; +import { render } from '../../testUtils/testUtils'; +import { WarningMissingAmount } from './WarningMissingAmount'; + +describe('components/paymentmodule/WarningMissingAmount', () => { + it('should render', () => { + const { container } = render( + , + ); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/components/paymentmodulepeople/WarningMissingAmount.tsx b/frontend/src/components/paymentmodulepeople/WarningMissingAmount.tsx new file mode 100644 index 0000000000..16dc9fa3f7 --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/WarningMissingAmount.tsx @@ -0,0 +1,28 @@ +import { Box } from '@mui/material'; +import WarningIcon from '@mui/icons-material/Warning'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +const WarnIcon = styled(WarningIcon)` + color: ${({ theme }) => theme.hctPalette.orange}; +`; + +interface WarningMissingAmountProps { + amount: number; + currency: string; +} + +export function WarningMissingAmount({ + amount, + currency, +}: WarningMissingAmountProps): React.ReactElement { + const { t } = useTranslation(); + + return ( + + + {t('Missing')} {amount} {currency} + + ); +} diff --git a/frontend/src/components/paymentmodulepeople/__snapshots__/WarningMissingAmount.test.tsx.snap b/frontend/src/components/paymentmodulepeople/__snapshots__/WarningMissingAmount.test.tsx.snap new file mode 100644 index 0000000000..d5eea3e5db --- /dev/null +++ b/frontend/src/components/paymentmodulepeople/__snapshots__/WarningMissingAmount.test.tsx.snap @@ -0,0 +1,26 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`components/paymentmodule/WarningMissingAmount should render 1`] = ` +
+
+ + Missing + + 100000 + + USD +
+
+`; diff --git a/frontend/src/components/payments/HouseholdDetails.tsx b/frontend/src/components/payments/HouseholdDetails.tsx new file mode 100644 index 0000000000..445da74a01 --- /dev/null +++ b/frontend/src/components/payments/HouseholdDetails.tsx @@ -0,0 +1,56 @@ +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Overview } from '@components/payments/Overview'; +import { Title } from '@core/Title'; +import { Grid, Typography } from '@mui/material'; +import { LabelizedField } from '@core/LabelizedField'; +import { getPhoneNoLabel } from '@utils/utils'; + +export const HouseholdDetails = ({ household }): React.ReactElement => { + const { t } = useTranslation(); + return ( + + + <Typography variant="h6">{t('Household')}</Typography> + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/frontend/src/components/payments/IndividualDetails.tsx b/frontend/src/components/payments/IndividualDetails.tsx new file mode 100644 index 0000000000..d4d250dced --- /dev/null +++ b/frontend/src/components/payments/IndividualDetails.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Overview } from '@components/payments/Overview'; +import { Title } from '@core/Title'; +import { Grid, Typography } from '@mui/material'; +import { LabelizedField } from '@core/LabelizedField'; +import { getPhoneNoLabel } from '@utils/utils'; + +export const IndividualDetails = ({ individual }): React.ReactElement => { + const { t } = useTranslation(); + return ( + + + <Typography variant="h6">{t('Individual')}</Typography> + + + + + + + + + + + + + + + + + ); +}; diff --git a/frontend/src/components/payments/Overview.tsx b/frontend/src/components/payments/Overview.tsx new file mode 100644 index 0000000000..6275e48e31 --- /dev/null +++ b/frontend/src/components/payments/Overview.tsx @@ -0,0 +1,8 @@ +import styled from 'styled-components'; +import { Paper } from '@mui/material'; + +export const Overview = styled(Paper)` + margin: 20px; + padding: ${({ theme }) => theme.spacing(8)} + ${({ theme }) => theme.spacing(11)}; +`; diff --git a/frontend/src/components/payments/VerificationPaymentDetails.tsx b/frontend/src/components/payments/VerificationPaymentDetails.tsx index 38618b3c67..cdcaf12807 100644 --- a/frontend/src/components/payments/VerificationPaymentDetails.tsx +++ b/frontend/src/components/payments/VerificationPaymentDetails.tsx @@ -1,12 +1,10 @@ -import { Grid, Paper, Typography } from '@mui/material'; +import { Grid, Typography } from '@mui/material'; import * as React from 'react'; import { useTranslation } from 'react-i18next'; -import styled from 'styled-components'; import { UniversalActivityLogTable } from '@containers/tables/UniversalActivityLogTable'; import { choicesToDict, formatCurrencyWithSymbol, - getPhoneNoLabel, paymentStatusDisplayMap, paymentStatusToColor, verificationRecordsStatusToColor, @@ -17,12 +15,10 @@ import { LabelizedField } from '@core/LabelizedField'; import { StatusBox } from '@core/StatusBox'; import { UniversalMoment } from '@core/UniversalMoment'; import { Title } from '@core/Title'; - -const Overview = styled(Paper)` - margin: 20px; - padding: ${({ theme }) => theme.spacing(8)} - ${({ theme }) => theme.spacing(11)}; -`; +import { Overview } from '@components/payments/Overview'; +import { HouseholdDetails } from '@components/payments/HouseholdDetails'; +import { useProgramContext } from '../../programContext'; +import { IndividualDetails } from '@components/payments/IndividualDetails'; interface VerificationPaymentDetailsProps { payment: PaymentQuery['payment']; @@ -36,6 +32,7 @@ export function VerificationPaymentDetails({ choicesData, }: VerificationPaymentDetailsProps): React.ReactElement { const { t } = useTranslation(); + const { isSocialDctType } = useProgramContext(); const deliveryTypeDict = choicesToDict( choicesData.paymentRecordDeliveryTypeChoices, ); @@ -94,49 +91,11 @@ export function VerificationPaymentDetails({ - - - <Typography variant="h6">{t('Household')}</Typography> - - - - - - - - - - - - - - - - - - - + {isSocialDctType ? ( + + ) : ( + + )} <Typography variant="h6">{t('Entitlement Details')}</Typography> diff --git a/frontend/src/components/payments/VerificationPaymentRecordDetails.tsx b/frontend/src/components/payments/VerificationPaymentRecordDetails.tsx index 6963b740b7..284f59beef 100644 --- a/frontend/src/components/payments/VerificationPaymentRecordDetails.tsx +++ b/frontend/src/components/payments/VerificationPaymentRecordDetails.tsx @@ -1,12 +1,10 @@ -import { Grid, Paper, Typography } from '@mui/material'; +import { Grid, Typography } from '@mui/material'; import * as React from 'react'; import { useTranslation } from 'react-i18next'; -import styled from 'styled-components'; import { UniversalActivityLogTable } from '@containers/tables/UniversalActivityLogTable'; import { choicesToDict, formatCurrencyWithSymbol, - getPhoneNoLabel, paymentRecordStatusToColor, paymentStatusDisplayMap, verificationRecordsStatusToColor, @@ -19,12 +17,10 @@ import { UniversalMoment } from '@core/UniversalMoment'; import { BlackLink } from '@core/BlackLink'; import { Title } from '@core/Title'; import { useBaseUrl } from '@hooks/useBaseUrl'; - -const Overview = styled(Paper)` - margin: 20px; - padding: ${({ theme }) => theme.spacing(8)} - ${({ theme }) => theme.spacing(11)}; -`; +import { Overview } from '@components/payments/Overview'; +import { HouseholdDetails } from '@components/payments/HouseholdDetails'; +import { useProgramContext } from '../../programContext'; +import { IndividualDetails } from '@components/payments/IndividualDetails'; interface VerificationPaymentRecordDetailsProps { paymentRecord: PaymentRecordQuery['paymentRecord']; @@ -39,6 +35,7 @@ export function VerificationPaymentRecordDetails({ }: VerificationPaymentRecordDetailsProps): React.ReactElement { const { t } = useTranslation(); const { baseUrl } = useBaseUrl(); + const { isSocialDctType } = useProgramContext(); const deliveryTypeDict = choicesToDict( choicesData.paymentRecordDeliveryTypeChoices, ); @@ -106,49 +103,13 @@ export function VerificationPaymentRecordDetails({ </Grid> </Grid> </ContainerColumnWithBorder> - <Overview> - <Title> - <Typography variant="h6">{t('Household')}</Typography> - - - - - - - - - - - - - - - - - - - + {isSocialDctType ? ( + + ) : ( + + )} <Typography variant="h6">{t('Entitlement Details')}</Typography> diff --git a/frontend/src/components/people/PeopleBioData/PeopleBioData.tsx b/frontend/src/components/people/PeopleBioData/PeopleBioData.tsx index 8a215dda8d..3ca73b34a7 100644 --- a/frontend/src/components/people/PeopleBioData/PeopleBioData.tsx +++ b/frontend/src/components/people/PeopleBioData/PeopleBioData.tsx @@ -20,6 +20,7 @@ import { Title } from '@core/Title'; import { UniversalMoment } from '@core/UniversalMoment'; import { DocumentPopulationPhotoModal } from '../../population/DocumentPopulationPhotoModal'; import { LinkedGrievancesModal } from '../../population/LinkedGrievancesModal/LinkedGrievancesModal'; +import { useProgramContext } from '../../../programContext'; const Overview = styled(Paper)` padding: ${({ theme }) => theme.spacing(8)} @@ -37,15 +38,15 @@ interface PeopleBioDataProps { choicesData: HouseholdChoiceDataQuery; grievancesChoices: GrievancesChoiceDataQuery; } -export function PeopleBioData({ +export const PeopleBioData = ({ individual, baseUrl, businessArea, choicesData, grievancesChoices, -}: PeopleBioDataProps): React.ReactElement { +}: PeopleBioDataProps): React.ReactElement => { const { t } = useTranslation(); - + const { selectedProgram } = useProgramContext(); const maritalStatusChoicesDict = choicesToDict( choicesData.maritalStatusChoices, ); @@ -58,6 +59,10 @@ export function PeopleBioData({ choicesData.severityOfDisabilityChoices, ); + const residenceChoicesDict = choicesToDict( + choicesData.residenceStatusChoices, + ); + const mappedIndividualDocuments = individual?.documents?.edges?.map( (edge) => ( <Grid item xs={3} key={edge.node.id}> @@ -127,6 +132,77 @@ export function PeopleBioData({ ); }; + let peopleFromHouseholdData = null; + if (individual?.household) { + const household = individual.household; + peopleFromHouseholdData = ( + <> + <Grid item xs={3}> + <LabelizedField label={t('Residence Status')}> + {residenceChoicesDict[household?.residenceStatus]} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Country')}> + {household?.country} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Country of Origin')}> + {household.countryOrigin} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Address')}> + {household.address} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Vilage')}> + {household.village} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Zip Code')}> + {household.zipCode} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Administrative Level 1')}> + {household?.admin1?.name} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Administrative Level 2')}> + {household?.admin2?.name} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Administrative Level 3')}> + {household?.admin3?.name} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Administrative Level 4')}> + {household?.admin4?.name} + </LabelizedField> + </Grid> + <Grid item xs={6}> + <LabelizedField label={t('Geolocation')}> + {household?.geopoint + ? `${household?.geopoint?.coordinates[0]}, ${household?.geopoint?.coordinates[1]}` + : '-'} + </LabelizedField> + </Grid> + <Grid item xs={3}> + <LabelizedField label={t('Data Collecting Type')}> + {selectedProgram?.dataCollectingType?.label} + </LabelizedField> + </Grid> + </> + ); + } + return ( <Overview> <Title> @@ -198,6 +274,7 @@ export function PeopleBioData({ {individual?.preferredLanguage} </LabelizedField> </Grid> + {peopleFromHouseholdData} <Grid item xs={12}> <BorderBox /> </Grid> @@ -302,4 +379,4 @@ export function PeopleBioData({ </Grid> </Overview> ); -} +}; diff --git a/frontend/src/components/people/PeopleBioData/__snapshots__/PeopleBioData.test.tsx.snap b/frontend/src/components/people/PeopleBioData/__snapshots__/PeopleBioData.test.tsx.snap index 48379da029..c5fc519143 100644 --- a/frontend/src/components/people/PeopleBioData/__snapshots__/PeopleBioData.test.tsx.snap +++ b/frontend/src/components/people/PeopleBioData/__snapshots__/PeopleBioData.test.tsx.snap @@ -297,6 +297,241 @@ exports[`components/population/IndividualBioData should render 1`] = ` </div> </div> </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Residence Status + </span> + <div + data-cy="label-Residence Status" + > + - + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Country + </span> + <div + data-cy="label-Country" + > + - + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Country of Origin + </span> + <div + data-cy="label-Country of Origin" + > + <span + class="sc-guDLey cyWTlF" + color="textSecondary" + > + San Marino + </span> + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Address + </span> + <div + data-cy="label-Address" + > + <span + class="sc-guDLey cyWTlF" + color="textSecondary" + > + 938 Luna Cliffs Apt. 551 +Jameschester, SC 24934 + </span> + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Vilage + </span> + <div + data-cy="label-Vilage" + > + - + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Zip Code + </span> + <div + data-cy="label-Zip Code" + > + - + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Administrative Level 1 + </span> + <div + data-cy="label-Administrative Level 1" + > + <span + class="sc-guDLey cyWTlF" + color="textSecondary" + > + Ghazni + </span> + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Administrative Level 2 + </span> + <div + data-cy="label-Administrative Level 2" + > + <span + class="sc-guDLey cyWTlF" + color="textSecondary" + > + Abband + </span> + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Administrative Level 3 + </span> + <div + data-cy="label-Administrative Level 3" + > + - + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Administrative Level 4 + </span> + <div + data-cy="label-Administrative Level 4" + > + - + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-6 css-1osj8n2-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Geolocation + </span> + <div + data-cy="label-Geolocation" + > + <span + class="sc-guDLey cyWTlF" + color="textSecondary" + > + - + </span> + </div> + </div> + </div> + <div + class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-3 css-1equabv-MuiGrid-root" + > + <div> + <span + class="sc-beySPh gbuZtJ" + color="textSecondary" + > + Data Collecting Type + </span> + <div + data-cy="label-Data Collecting Type" + > + <span + class="sc-guDLey cyWTlF" + color="textSecondary" + > + data collecting type + </span> + </div> + </div> + </div> <div class="MuiGrid-root MuiGrid-item MuiGrid-grid-xs-12 css-1idn90j-MuiGrid-root" > diff --git a/frontend/src/components/people/PeopleFilter.tsx b/frontend/src/components/people/PeopleFilter.tsx new file mode 100644 index 0000000000..8088a41099 --- /dev/null +++ b/frontend/src/components/people/PeopleFilter.tsx @@ -0,0 +1,285 @@ +import { Grid, MenuItem } from '@mui/material'; +import CakeIcon from '@mui/icons-material/Cake'; +import FlashOnIcon from '@mui/icons-material/FlashOn'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { + DataCollectingTypeType, + IndividualChoiceDataQuery, + ProgramNode, +} from '@generated/graphql'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { AdminAreaAutocomplete } from '@shared/autocompletes/AdminAreaAutocomplete'; +import { individualTableOrderOptions } from '@utils/constants'; +import { createHandleApplyFilterChange } from '@utils/utils'; +import { DatePickerFilter } from '@core/DatePickerFilter'; +import { FiltersSection } from '@core/FiltersSection'; +import { NumberTextField } from '@core/NumberTextField'; +import { SearchTextField } from '@core/SearchTextField'; +import { SelectFilter } from '@core/SelectFilter'; +import { useProgramContext } from '../../programContext'; + +interface PeopleFilterProps { + filter; + programs?: ProgramNode[]; + choicesData: IndividualChoiceDataQuery; + setFilter: (filter) => void; + initialFilter; + appliedFilter; + setAppliedFilter: (filter) => void; + isOnPaper?: boolean; +} + +export function PeopleFilter({ + filter, + programs, + choicesData, + setFilter, + initialFilter, + appliedFilter, + setAppliedFilter, + isOnPaper = true, +}: PeopleFilterProps): React.ReactElement { + const { t } = useTranslation(); + const navigate = useNavigate(); + const location = useLocation(); + const { isAllPrograms } = useBaseUrl(); + const { selectedProgram } = useProgramContext(); + + const { handleFilterChange, applyFilterChanges, clearFilter } = + createHandleApplyFilterChange( + initialFilter, + navigate, + location, + filter, + setFilter, + appliedFilter, + setAppliedFilter, + ); + const handleApplyFilter = (): void => { + applyFilterChanges(); + }; + + const handleClearFilter = (): void => { + clearFilter(); + }; + + // Show admin area filter only for social programs + const showAdminAreaFilter = + selectedProgram?.dataCollectingType?.type?.toUpperCase() === + DataCollectingTypeType.Social; + + return ( + <FiltersSection + clearHandler={handleClearFilter} + applyHandler={handleApplyFilter} + isOnPaper={isOnPaper} + > + <Grid container alignItems="flex-end" spacing={3}> + <Grid item xs={3}> + <SearchTextField + label={t('Search')} + value={filter.search} + onChange={(e) => handleFilterChange('search', e.target.value)} + data-cy="ind-filters-search" + /> + </Grid> + <Grid container item xs={6} spacing={3}> + <Grid item xs={6}> + <SelectFilter + onChange={(e) => + handleFilterChange('documentType', e.target.value) + } + label={t('Document Type')} + value={filter.documentType} + borderRadius="0px 4px 4px 0px" + data-cy="filters-document-type" + fullWidth + disableClearable + > + {choicesData?.documentTypeChoices.map(({ name, value }) => ( + <MenuItem key={value} value={value}> + {name} + </MenuItem> + ))} + </SelectFilter> + </Grid> + <Grid item xs={6}> + <SearchTextField + label={t('Document number')} + value={filter.documentNumber} + onChange={(e) => + handleFilterChange('documentNumber', e.target.value) + } + data-cy="filters-document-number" + /> + </Grid> + </Grid> + {isAllPrograms && ( + <Grid item xs={2}> + <SelectFilter + onChange={(e) => handleFilterChange('program', e.target.value)} + label={t('Programme')} + value={filter.program} + fullWidth + icon={<FlashOnIcon />} + data-cy="filters-program" + > + {programs.map((program) => ( + <MenuItem key={program.id} value={program.id}> + {program.name} + </MenuItem> + ))} + </SelectFilter> + </Grid> + )} + {showAdminAreaFilter && ( + <Grid item xs={2}> + <AdminAreaAutocomplete + name="admin2" + value={filter.admin2} + setFilter={setFilter} + filter={filter} + initialFilter={initialFilter} + appliedFilter={appliedFilter} + setAppliedFilter={setAppliedFilter} + dataCy="ind-filters-admin2" + /> + </Grid> + )} + <Grid item xs={2}> + <SelectFilter + onChange={(e) => handleFilterChange('sex', e.target.value)} + value={filter.sex} + label={t('Gender')} + data-cy="ind-filters-gender" + fullWidth + > + <MenuItem value="FEMALE">{t('Female')}</MenuItem> + <MenuItem value="MALE">{t('Male')}</MenuItem> + </SelectFilter> + </Grid> + <Grid item xs={2}> + <NumberTextField + fullWidth + topLabel={t('Age')} + placeholder={t('From')} + value={filter.ageMin} + data-cy="ind-filters-age-from" + onChange={(e) => { + if (e.target.value < 0 || e.target.value > 120) return; + handleFilterChange('ageMin', e.target.value); + }} + icon={<CakeIcon />} + /> + </Grid> + <Grid item xs={2}> + <NumberTextField + fullWidth + placeholder={t('To')} + value={filter.ageMax} + data-cy="ind-filters-age-to" + onChange={(e) => { + if (e.target.value < 0 || e.target.value > 120) return; + handleFilterChange('ageMax', e.target.value); + }} + icon={<CakeIcon />} + /> + </Grid> + <Grid item xs={3}> + <SelectFilter + onChange={(e) => handleFilterChange('flags', e.target.value)} + label={t('Flags')} + multiple + fullWidth + value={filter.flags} + data-cy="ind-filters-flags" + > + {choicesData?.flagChoices.map((each, index) => ( + <MenuItem + key={each.value} + value={each.value} + data-cy={`select-option-${index}`} + > + {each.name} + </MenuItem> + ))} + </SelectFilter> + </Grid> + <Grid item xs={3}> + <SelectFilter + onChange={(e) => handleFilterChange('orderBy', e.target.value)} + label={t('Sort by')} + value={filter.orderBy} + fullWidth + data-cy="ind-filters-order-by" + disableClearable + > + {individualTableOrderOptions.map((order) => ( + <MenuItem key={order.value} value={order.value}> + {order.name} + </MenuItem> + ))} + </SelectFilter> + </Grid> + <Grid item xs={2}> + <SelectFilter + onChange={(e) => handleFilterChange('status', e.target.value)} + label={t('Status')} + value={filter.status} + data-cy="ind-filters-status" + > + <MenuItem key="active" value="ACTIVE"> + Active + </MenuItem> + <MenuItem key="duplicate" value="DUPLICATE"> + Duplicate + </MenuItem> + <MenuItem key="withdrawn" value="WITHDRAWN"> + Withdrawn + </MenuItem> + </SelectFilter> + </Grid> + <Grid item xs={2}> + <DatePickerFilter + topLabel={t('Registration Date')} + placeholder={t('From')} + onChange={(date) => + handleFilterChange('lastRegistrationDateMin', date) + } + value={filter.lastRegistrationDateMin} + data-cy="ind-filters-reg-date-from" + /> + </Grid> + <Grid item xs={2}> + <DatePickerFilter + placeholder={t('To')} + onChange={(date) => + handleFilterChange('lastRegistrationDateMax', date) + } + value={filter.lastRegistrationDateMax} + data-cy="ind-filters-reg-date-to" + /> + </Grid> + {isAllPrograms && ( + <Grid item xs={2}> + <SelectFilter + onChange={(e) => + handleFilterChange('programState', e.target.value) + } + label={t('Programme State')} + value={filter.programState} + fullWidth + disableClearable + data-cy="filters-program-state" + > + <MenuItem value="active">{t('Active Programmes')}</MenuItem> + <MenuItem value="all">{t('All Programmes')}</MenuItem> + </SelectFilter> + </Grid> + )} + </Grid> + </FiltersSection> + ); +} diff --git a/frontend/src/components/population/HouseholdDetails/__snapshots__/HouseholdDetails.test.tsx.snap b/frontend/src/components/population/HouseholdDetails/__snapshots__/HouseholdDetails.test.tsx.snap index be06704955..aaeb48050b 100644 --- a/frontend/src/components/population/HouseholdDetails/__snapshots__/HouseholdDetails.test.tsx.snap +++ b/frontend/src/components/population/HouseholdDetails/__snapshots__/HouseholdDetails.test.tsx.snap @@ -425,7 +425,12 @@ exports[`components/population/HouseholdDetails should render 1`] = ` <div data-cy="label-Data Collecting Type" > - - + <span + class="sc-dmyCSP bGPBYf" + color="textSecondary" + > + data collecting type + </span> </div> </div> </div> diff --git a/frontend/src/components/population/IndividualVulnerabilities/IndividualVunerabilities.tsx b/frontend/src/components/population/IndividualVulnerabilities/IndividualVunerabilities.tsx index d5923854bd..2ab4e02f7f 100644 --- a/frontend/src/components/population/IndividualVulnerabilities/IndividualVunerabilities.tsx +++ b/frontend/src/components/population/IndividualVulnerabilities/IndividualVunerabilities.tsx @@ -17,7 +17,7 @@ const Overview = styled(Paper)` padding: ${({ theme }) => theme.spacing(8)} ${({ theme }) => theme.spacing(11)}; margin-top: ${({ theme }) => theme.spacing(6)}; - margin-bottom: ${({ theme }) => theme.spacing(6)}; + margin-bottom: ${({ theme }) => theme.spacing(4)}; `; interface IndividualVulnerabilitesProps { individual: IndividualNode; diff --git a/frontend/src/components/population/IndividualVulnerabilities/__snapshots__/IndividualVulnerabilities.test.tsx.snap b/frontend/src/components/population/IndividualVulnerabilities/__snapshots__/IndividualVulnerabilities.test.tsx.snap index 4c371be04f..590139aec1 100644 --- a/frontend/src/components/population/IndividualVulnerabilities/__snapshots__/IndividualVulnerabilities.test.tsx.snap +++ b/frontend/src/components/population/IndividualVulnerabilities/__snapshots__/IndividualVulnerabilities.test.tsx.snap @@ -4,7 +4,7 @@ exports[`components/population/IndividualVulnerabilities should render 1`] = ` <div> <div> <div - class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 sc-fsYfdN ctvplS css-1ps6pg7-MuiPaper-root" + class="MuiPaper-root MuiPaper-elevation MuiPaper-rounded MuiPaper-elevation1 sc-fsYfdN ctuPcH css-1ps6pg7-MuiPaper-root" > <div class="sc-dmyCSP ljiJAm" diff --git a/frontend/src/components/programs/ProgramDetails/ProgramDetails.test.tsx b/frontend/src/components/programs/ProgramDetails/ProgramDetails.test.tsx index 680e118a44..81d8d32fec 100644 --- a/frontend/src/components/programs/ProgramDetails/ProgramDetails.test.tsx +++ b/frontend/src/components/programs/ProgramDetails/ProgramDetails.test.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { render } from '../../../testUtils/testUtils'; import { ProgramDetails } from './ProgramDetails'; import { fakeProgram } from '../../../../fixtures/programs/fakeProgram'; diff --git a/frontend/src/components/rdi/create/xlsx/CreateImportFromXlsxForm.tsx b/frontend/src/components/rdi/create/xlsx/CreateImportFromXlsxForm.tsx index 89ba9d536c..000de1d4ae 100644 --- a/frontend/src/components/rdi/create/xlsx/CreateImportFromXlsxForm.tsx +++ b/frontend/src/components/rdi/create/xlsx/CreateImportFromXlsxForm.tsx @@ -9,7 +9,6 @@ import * as Yup from 'yup'; import { ImportDataStatus, useCreateRegistrationXlsxImportMutation, - useProgramQuery, } from '@generated/graphql'; import { useBaseUrl } from '@hooks/useBaseUrl'; import { useSnackbar } from '@hooks/useSnackBar'; @@ -43,14 +42,11 @@ export function CreateImportFromXlsxForm({ loading: saveXlsxLoading, xlsxImportData, } = useSaveXlsxImportDataAndCheckStatus(); - const { baseUrl, businessArea, programId } = useBaseUrl(); + const { baseUrl, businessArea } = useBaseUrl(); const { showMessage } = useSnackbar(); const { t } = useTranslation(); const navigate = useNavigate(); const [createImport] = useCreateRegistrationXlsxImportMutation(); - const { data: programData } = useProgramQuery({ - variables: { id: programId }, - }); const onSubmit = async (values): Promise<void> => { setSubmitDisabled(true); @@ -65,15 +61,9 @@ export function CreateImportFromXlsxForm({ }, }, }); - if (programData.program.isSocialWorkerProgram) { - navigate( - `/${baseUrl}/registration-data-import-for-people/${data.data.registrationXlsxImport.registrationDataImport.id}`, - ); - } else { - navigate( - `/${baseUrl}/registration-data-import/${data.data.registrationXlsxImport.registrationDataImport.id}`, - ); - } + navigate( + `/${baseUrl}/registration-data-import/${data.data.registrationXlsxImport.registrationDataImport.id}`, + ); } catch (e) { e.graphQLErrors.map((x) => showMessage(x.message)); setSubmitDisabled(false); diff --git a/frontend/src/components/rdi/details/RegistrationDataImportDetailsPageHeader.tsx b/frontend/src/components/rdi/details/RegistrationDataImportDetailsPageHeader.tsx index 1f05f7dfad..e5bcfaff6b 100644 --- a/frontend/src/components/rdi/details/RegistrationDataImportDetailsPageHeader.tsx +++ b/frontend/src/components/rdi/details/RegistrationDataImportDetailsPageHeader.tsx @@ -135,7 +135,7 @@ export const RegistrationDataImportDetailsPageHeader = ({ const breadCrumbsItems: BreadCrumbsItem[] = [ { title: t('Registration Data import'), - to: `/${baseUrl}/registration-data-import/`, + to: '..', }, ]; @@ -144,7 +144,7 @@ export const RegistrationDataImportDetailsPageHeader = ({ <PageHeader title={registration.name} breadCrumbs={canViewList ? breadCrumbsItems : null} - handleBack={() => navigate(`/${baseUrl}/registration-data-import/`)} + handleBack={() => navigate('..')} flags={<AdminButton adminUrl={registration.adminUrl} />} > {registration.erased ? null : buttons} diff --git a/frontend/src/components/rdi/details/households/HouseholdDetails/__snapshots__/HouseholdDetails.test.tsx.snap b/frontend/src/components/rdi/details/households/HouseholdDetails/__snapshots__/HouseholdDetails.test.tsx.snap index 94617c6478..c155affb71 100644 --- a/frontend/src/components/rdi/details/households/HouseholdDetails/__snapshots__/HouseholdDetails.test.tsx.snap +++ b/frontend/src/components/rdi/details/households/HouseholdDetails/__snapshots__/HouseholdDetails.test.tsx.snap @@ -236,7 +236,12 @@ exports[`components/rdi/details/households/HouseholdDetails should render 1`] = <div data-cy="label-Data Collecting Type" > - - + <span + class="sc-hLQSwg hXyiIZ" + color="textSecondary" + > + data collecting type + </span> </div> </div> </div> diff --git a/frontend/src/components/targeting/Results.tsx b/frontend/src/components/targeting/ResultsForHouseholds.tsx similarity index 99% rename from frontend/src/components/targeting/Results.tsx rename to frontend/src/components/targeting/ResultsForHouseholds.tsx index c8db483d5a..9183f8a1d5 100644 --- a/frontend/src/components/targeting/Results.tsx +++ b/frontend/src/components/targeting/ResultsForHouseholds.tsx @@ -53,7 +53,7 @@ interface ResultsProps { targetPopulation: TargetPopulationQuery['targetPopulation']; } -export function Results({ +export function ResultsForHouseholds({ targetPopulation, }: ResultsProps): React.ReactElement { const { t } = useTranslation(); diff --git a/frontend/src/components/targeting/ResultsForPeople.tsx b/frontend/src/components/targeting/ResultsForPeople.tsx new file mode 100644 index 0000000000..86bad362b8 --- /dev/null +++ b/frontend/src/components/targeting/ResultsForPeople.tsx @@ -0,0 +1,76 @@ +import { Grid, Typography } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { + TargetPopulationBuildStatus, + TargetPopulationQuery, +} from '@generated/graphql'; +import { MiśTheme } from '../../theme'; +import { LabelizedField } from '@core/LabelizedField'; +import { PaperContainer } from './PaperContainer'; + +const Title = styled.div` + padding-bottom: ${({ theme }) => theme.spacing(2)}; +`; + +const ContentWrapper = styled.div` + display: flex; +`; + +const SummaryBorder = styled.div` + padding: ${({ theme }) => theme.spacing(4)}; + border-color: #b1b1b5; + border-left-width: 1px; + border-left-style: solid; +`; + +const SummaryValue = styled.div` + font-family: ${({ theme }: { theme: MiśTheme }) => + theme.hctTypography.fontFamily}; + color: #253b46; + font-size: 36px; + line-height: 32px; + margin-top: ${({ theme }) => theme.spacing(2)}; +`; + +interface ResultsProps { + targetPopulation: TargetPopulationQuery['targetPopulation']; +} + +export function ResultsForPeople({ + targetPopulation, +}: ResultsProps): React.ReactElement { + const { t } = useTranslation(); + if (targetPopulation.buildStatus !== TargetPopulationBuildStatus.Ok) { + return null; + } + return ( + <div> + <PaperContainer> + <Title> + <Typography variant="h6">{t('Results')}</Typography> + + + + + + + + + + + + {targetPopulation.totalHouseholdsCount || '0'} + + + + + + + + + +
+ ); +} diff --git a/frontend/src/components/targeting/SubField.tsx b/frontend/src/components/targeting/SubField.tsx index d5ea2c0e33..eaca95ca9d 100644 --- a/frontend/src/components/targeting/SubField.tsx +++ b/frontend/src/components/targeting/SubField.tsx @@ -17,7 +17,12 @@ const InlineField = styled.div` width: 48%; `; -export function SubField({ field, index, baseName }): React.ReactElement { +export function SubField({ + field, + index, + baseName, + choicesDict, +}): React.ReactElement { const { t } = useTranslation(); switch (field.fieldAttribute.type) { case 'DECIMAL': @@ -104,7 +109,7 @@ export function SubField({ field, index, baseName }): React.ReactElement { ) : null} - + {recordInfo} {hasPermissions(PERMISSIONS.ACTIVITY_LOG_VIEW, permissions) && ( diff --git a/frontend/src/components/targeting/TargetPopulationForPeopleFilters.tsx b/frontend/src/components/targeting/TargetPopulationForPeopleFilters.tsx new file mode 100644 index 0000000000..7ba9a203dc --- /dev/null +++ b/frontend/src/components/targeting/TargetPopulationForPeopleFilters.tsx @@ -0,0 +1,130 @@ +import { Grid, MenuItem } from '@mui/material'; +import { Group, Person } from '@mui/icons-material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useLocation, useNavigate } from 'react-router-dom'; +import { TargetPopulationStatus } from '@generated/graphql'; +import { + createHandleApplyFilterChange, + targetPopulationStatusMapping, +} from '@utils/utils'; +import { DatePickerFilter } from '@core/DatePickerFilter'; +import { NumberTextField } from '@core/NumberTextField'; +import { SearchTextField } from '@core/SearchTextField'; +import { SelectFilter } from '@core/SelectFilter'; +import { FiltersSection } from '@core/FiltersSection'; + +interface TargetPopulationFiltersProps { + filter; + setFilter: (filter) => void; + initialFilter; + appliedFilter; + setAppliedFilter: (filter) => void; +} +export const TargetPopulationForPeopleFilters = ({ + filter, + setFilter, + initialFilter, + appliedFilter, + setAppliedFilter, +}: TargetPopulationFiltersProps): React.ReactElement => { + const { t } = useTranslation(); + const navigate = useNavigate(); + const location = useLocation(); + const isAccountability = location.pathname.includes('accountability'); + + const { handleFilterChange, applyFilterChanges, clearFilter } = + createHandleApplyFilterChange( + initialFilter, + navigate, + location, + filter, + setFilter, + appliedFilter, + setAppliedFilter, + ); + const handleApplyFilter = (): void => { + applyFilterChanges(); + }; + + const handleClearFilter = (): void => { + clearFilter(); + }; + + const preparedStatusChoices = isAccountability + ? Object.values(TargetPopulationStatus).filter((key) => key !== 'OPEN') + : Object.values(TargetPopulationStatus); + + return ( + + + + handleFilterChange('name', e.target.value)} + data-cy="filters-search" + fullWidth + /> + + + handleFilterChange('status', e.target.value)} + value={filter.status} + label={t('Status')} + icon={} + fullWidth + data-cy="filters-status" + > + {preparedStatusChoices.sort().map((key) => ( + + {targetPopulationStatusMapping(key)} + + ))} + + + + + handleFilterChange('totalHouseholdsCountMin', e.target.value) + } + icon={} + data-cy="filters-total-households-count-min" + /> + + + + handleFilterChange('totalHouseholdsCountMax', e.target.value) + } + icon={} + data-cy="filters-total-households-count-max" + /> + + + handleFilterChange('createdAtRangeMin', date)} + value={filter.createdAtRangeMin} + /> + + + handleFilterChange('createdAtRangeMax', date)} + value={filter.createdAtRangeMax} + /> + + + + ); +}; diff --git a/frontend/src/components/targeting/TargetingCriteria/Criteria.tsx b/frontend/src/components/targeting/TargetingCriteria/Criteria.tsx index 3e29df9c2c..dc775e9ac7 100644 --- a/frontend/src/components/targeting/TargetingCriteria/Criteria.tsx +++ b/frontend/src/components/targeting/TargetingCriteria/Criteria.tsx @@ -60,7 +60,16 @@ const CriteriaSetBox = styled.div` margin: ${({ theme }) => theme.spacing(2)} 0; `; -const CriteriaField = ({ field }): React.ReactElement => { +const CriteriaField = ({ field, choicesDict }): React.ReactElement => { + const extractChoiceLabel = (choiceField, argument) => { + let choices = choicesDict?.[choiceField.fieldName]; + if (!choices) { + choices = choiceField.fieldAttribute.choices; + } + return choices?.length + ? choices.find((each) => each.value === argument)?.labelEn + : argument; + }; const { t } = useTranslation(); let fieldElement; switch (field.comparisonMethod) { @@ -89,13 +98,7 @@ const CriteriaField = ({ field }): React.ReactElement => { {field.fieldAttribute.type === 'BOOL' ? ( {field.arguments[0] === 'True' ? t('Yes') : t('No')} ) : ( - - {field.fieldAttribute.choices?.length - ? field.fieldAttribute.choices.find( - (each) => each.value === field.arguments[0], - )?.labelEn - : field.arguments[0]} - + {extractChoiceLabel(field, field.arguments[0])} )}

); @@ -119,35 +122,17 @@ const CriteriaField = ({ field }): React.ReactElement => { ); break; case 'CONTAINS': - fieldElement = - field.arguments.length > 1 ? ( -

- {field.fieldAttribute.labelEn || field.fieldName}:{' '} - {field.arguments.map((argument, index) => ( - <> - - {field.fieldAttribute.choices?.length - ? field.fieldAttribute.choices.find( - (each) => each.value === argument, - )?.labelEn - : field.arguments[0]} - - {index !== field.arguments.length - 1 && ', '} - - ))} -

- ) : ( -

- {field.fieldAttribute.labelEn || field.fieldName}:{' '} - - {field.fieldAttribute.choices?.length - ? field.fieldAttribute.choices.find( - (each) => each.value === field.arguments[0], - )?.labelEn - : field.arguments[0]} - -

- ); + fieldElement = ( +

+ {field.fieldAttribute.labelEn || field.fieldName}:{' '} + {field.arguments.map((argument, index) => ( + <> + {extractChoiceLabel(field, argument)} + {index !== field.arguments.length - 1 && ', '} + + ))} +

+ ); break; default: fieldElement = ( @@ -168,6 +153,7 @@ interface CriteriaProps { isEdit: boolean; canRemove: boolean; alternative?: boolean; + choicesDict; } export function Criteria({ @@ -176,6 +162,7 @@ export function Criteria({ editFunction = () => null, isEdit, canRemove, + choicesDict, alternative = null, individualsFiltersBlocks, }: CriteriaProps): React.ReactElement { @@ -183,14 +170,14 @@ export function Criteria({ {rules.map((each, index) => ( // eslint-disable-next-line - + ))} {individualsFiltersBlocks.map((item) => ( // eslint-disable-next-line {item.individualBlockFilters.map((filter) => ( // eslint-disable-next-line - + ))} ))} diff --git a/frontend/src/components/targeting/TargetingCriteria/CriteriaAutocomplete.tsx b/frontend/src/components/targeting/TargetingCriteria/CriteriaAutocomplete.tsx index 3a366cfa27..dc8422ce6d 100644 --- a/frontend/src/components/targeting/TargetingCriteria/CriteriaAutocomplete.tsx +++ b/frontend/src/components/targeting/TargetingCriteria/CriteriaAutocomplete.tsx @@ -18,12 +18,20 @@ export function CriteriaAutocomplete({ }): React.ReactElement { const [open, setOpen] = useState(false); const [newValue, setNewValue] = useState(null); + const [choicesWithoutDuplicates, setChoicesWithoutDuplicates] = useState(); + useEffect(() => { const optionValue = otherProps.choices.find((choice) => choice.name === field.value) || null; setNewValue(optionValue); }, [field.value, otherProps.choices]); - + useEffect(() => { + const uniqueChoices = otherProps.choices.filter( + (choice, index, self) => + index === self.findIndex((t) => t.name === choice.name), + ); + setChoicesWithoutDuplicates(uniqueChoices); + }, [ otherProps.choices]); const isInvalid = get(otherProps.form.errors, field.name) && get(otherProps.form.touched, field.name); @@ -39,7 +47,7 @@ export function CriteriaAutocomplete({ onClose={() => { setOpen(false); }} - options={otherProps.choices} + options={choicesWithoutDuplicates || []} value={newValue} getOptionLabel={(option) => { if (option) { diff --git a/frontend/src/components/targeting/TargetingCriteria/TargetingCriteria.tsx b/frontend/src/components/targeting/TargetingCriteria/TargetingCriteria.tsx index c4eea0a51d..3c38817b39 100644 --- a/frontend/src/components/targeting/TargetingCriteria/TargetingCriteria.tsx +++ b/frontend/src/components/targeting/TargetingCriteria/TargetingCriteria.tsx @@ -1,11 +1,14 @@ import { TargetCriteriaForm } from '@containers/forms/TargetCriteriaForm'; -import { TargetPopulationQuery } from '@generated/graphql'; +import { + DataCollectingTypeType, + TargetPopulationQuery, +} from '@generated/graphql'; import { AddCircleOutline } from '@mui/icons-material'; import { Box, Button, Checkbox, FormControlLabel, Grid } from '@mui/material'; import { FormikCheckboxField } from '@shared/Formik/FormikCheckboxField'; import { Field } from 'formik'; import * as React from 'react'; -import { Fragment, useState } from 'react'; +import { Fragment, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom'; import styled from 'styled-components'; @@ -16,6 +19,8 @@ import { } from './TargetingCriteriaDisabled'; import { VulnerabilityScoreComponent } from './VulnerabilityScoreComponent'; import { useProgramContext } from 'src/programContext'; +import { useCachedImportedIndividualFieldsQuery } from '@hooks/useCachedImportedIndividualFields'; +import { useBaseUrl } from '@hooks/useBaseUrl'; const Title = styled.div` padding: ${({ theme }) => theme.spacing(3)} ${({ theme }) => theme.spacing(4)}; @@ -92,9 +97,22 @@ export const TargetingCriteria = ({ const { t } = useTranslation(); const location = useLocation(); const { selectedProgram } = useProgramContext(); + const { businessArea, programId } = useBaseUrl(); + const { data: allCoreFieldsAttributesData, loading } = + useCachedImportedIndividualFieldsQuery(businessArea, programId); const [isOpen, setOpen] = useState(false); const [criteriaIndex, setIndex] = useState(null); const [criteriaObject, setCriteria] = useState({}); + const [allDataChoicesDict, setAllDataChoicesDict] = useState(null); + useEffect(() => { + if (loading) return; + const allDataChoicesDictTmp = + allCoreFieldsAttributesData?.allFieldsAttributes?.reduce((acc, item) => { + acc[item.name] = item.choices; + return acc; + }, {}); + setAllDataChoicesDict(allDataChoicesDictTmp); + }, [allCoreFieldsAttributesData, loading]); const regex = /(create|edit-tp)/; const isDetailsPage = !regex.test(location.pathname); const openModal = (criteria): void => { @@ -128,7 +146,8 @@ export const TargetingCriteria = ({ selectedProgram?.dataCollectingType?.individualFiltersAvailable; let householdFiltersAvailable = selectedProgram?.dataCollectingType?.householdFiltersAvailable; - + const isSocialWorkingProgram = + selectedProgram?.dataCollectingType?.type === DataCollectingTypeType.Social; // Allow use filters on non-migrated programs if (individualFiltersAvailable === undefined) { individualFiltersAvailable = true; @@ -168,6 +187,7 @@ export const TargetingCriteria = ({ open={isOpen} onClose={() => closeModal()} addCriteria={addCriteria} + isSocialWorkingProgram={isSocialWorkingProgram} individualFiltersAvailable={individualFiltersAvailable} householdFiltersAvailable={householdFiltersAvailable} /> @@ -180,6 +200,7 @@ export const TargetingCriteria = ({ 1} rules={criteria.filters} individualsFiltersBlocks={ diff --git a/frontend/src/containers/forms/TargetCriteriaBlockFilter.tsx b/frontend/src/containers/forms/TargetCriteriaBlockFilter.tsx index a89c3f5430..0c9af6e230 100644 --- a/frontend/src/containers/forms/TargetCriteriaBlockFilter.tsx +++ b/frontend/src/containers/forms/TargetCriteriaBlockFilter.tsx @@ -10,11 +10,13 @@ export function TargetCriteriaBlockFilter({ each, onChange, onDelete, + choicesDict, }: { blockIndex: number; index: number; data: ImportedIndividualFieldsQuery; each; + choicesDict; onChange: (e, object) => void; onDelete: () => void; }): React.ReactElement { @@ -34,6 +36,7 @@ export function TargetCriteriaBlockFilter({
diff --git a/frontend/src/containers/forms/TargetCriteriaFilter.tsx b/frontend/src/containers/forms/TargetCriteriaFilter.tsx index 6b00cbe23d..c7da1004c9 100644 --- a/frontend/src/containers/forms/TargetCriteriaFilter.tsx +++ b/frontend/src/containers/forms/TargetCriteriaFilter.tsx @@ -37,6 +37,7 @@ export function TargetingCriteriaFilter({ onChange, values, onClick, + choicesDict, }: { index: number; data: ImportedIndividualFieldsQuery; @@ -44,6 +45,7 @@ export function TargetingCriteriaFilter({ onChange: (e, object) => void; values; onClick: () => void; + choicesDict; }): React.ReactElement { const { t } = useTranslation(); const shouldShowDivider = index + 1 < values.filters.length; @@ -60,7 +62,12 @@ export function TargetingCriteriaFilter({ /> {each.fieldName && (
- +
)} {shouldShowDivider && ( diff --git a/frontend/src/containers/forms/TargetCriteriaFilterBlocks.tsx b/frontend/src/containers/forms/TargetCriteriaFilterBlocks.tsx index 63ce4e7a95..9b8cbeaa2f 100644 --- a/frontend/src/containers/forms/TargetCriteriaFilterBlocks.tsx +++ b/frontend/src/containers/forms/TargetCriteriaFilterBlocks.tsx @@ -71,11 +71,13 @@ export function TargetCriteriaFilterBlocks({ blockIndex, data, values, + choicesToDict, onDelete, }: { blockIndex: number; data: ImportedIndividualFieldsQuery; values; + choicesToDict; onDelete: () => void; }): React.ReactElement { const { t } = useTranslation(); @@ -104,6 +106,7 @@ export function TargetCriteriaFilterBlocks({ index={index} data={data} each={each} + choicesDict={choicesToDict} onChange={(e, object) => { if (object) { return chooseFieldType(object, arrayHelpers, index); diff --git a/frontend/src/containers/forms/TargetCriteriaForm.tsx b/frontend/src/containers/forms/TargetCriteriaForm.tsx index f82486591e..5aac059286 100644 --- a/frontend/src/containers/forms/TargetCriteriaForm.tsx +++ b/frontend/src/containers/forms/TargetCriteriaForm.tsx @@ -84,6 +84,7 @@ interface TargetCriteriaFormPropTypes { onClose: () => void; individualFiltersAvailable: boolean; householdFiltersAvailable: boolean; + isSocialWorkingProgram: boolean; } const associatedWith = (type) => (item) => item.associatedWith === type; @@ -96,6 +97,7 @@ export const TargetCriteriaForm = ({ onClose, individualFiltersAvailable, householdFiltersAvailable, + isSocialWorkingProgram, }: TargetCriteriaFormPropTypes): React.ReactElement => { const { t } = useTranslation(); const { businessArea, programId } = useBaseUrl(); @@ -110,6 +112,7 @@ export const TargetCriteriaForm = ({ const initialValue = mapCriteriaToInitialValues(criteria); const [individualData, setIndividualData] = useState(null); const [householdData, setHouseholdData] = useState(null); + const [allDataChoicesDict, setAllDataChoicesDict] = useState(null); useEffect(() => { if (loading) return; const filteredIndividualData = { @@ -125,10 +128,17 @@ export const TargetCriteriaForm = ({ ), }; setHouseholdData(filteredHouseholdData); + const allDataChoicesDictTmp = data?.allFieldsAttributes?.reduce( + (acc, item) => { + acc[item.name] = item.choices; + return acc; + }, + {}, + ); + setAllDataChoicesDict(allDataChoicesDictTmp); }, [data, loading]); if (!data) return null; - const validate = ({ filters, individualsFiltersBlocks, @@ -256,7 +266,8 @@ export const TargetCriteriaForm = ({ // eslint-disable-next-line key={index} index={index} - data={householdData} + data={isSocialWorkingProgram ? data : householdData} + choicesDict={allDataChoicesDict} each={each} onChange={(e, object) => { if (object) { @@ -271,7 +282,7 @@ export const TargetCriteriaForm = ({ )} /> - {householdFiltersAvailable ? ( + {householdFiltersAvailable || isSocialWorkingProgram ? ( ) : null} - {individualFiltersAvailable ? ( + {individualFiltersAvailable && !isSocialWorkingProgram ? ( <> {householdFiltersAvailable ? ( @@ -310,6 +321,7 @@ export const TargetCriteriaForm = ({ blockIndex={index} data={individualData} values={values} + choicesToDict={allDataChoicesDict} onDelete={() => arrayHelpers.remove(index)} /> ))} diff --git a/frontend/src/containers/pages/accountability/feedback/FeedbackPage.tsx b/frontend/src/containers/pages/accountability/feedback/FeedbackPage.tsx index 9a6855437e..3ba476b7fc 100644 --- a/frontend/src/containers/pages/accountability/feedback/FeedbackPage.tsx +++ b/frontend/src/containers/pages/accountability/feedback/FeedbackPage.tsx @@ -9,7 +9,7 @@ import { import { usePermissions } from '@hooks/usePermissions'; import { PageHeader } from '@components/core/PageHeader'; import { PermissionDenied } from '@components/core/PermissionDenied'; -import { FeedbackTable } from '../../../tables/Feedback/FeedbackTable'; +import { FeedbackTable } from '@containers/tables/Feedback'; import { FeedbackFilters } from '@components/accountability/Feedback/FeedbackTable/FeedbackFilters'; import { getFilterFromQueryParams } from '@utils/utils'; import { useBaseUrl } from '@hooks/useBaseUrl'; @@ -17,11 +17,11 @@ import { ButtonTooltip } from '@components/core/ButtonTooltip'; import { useProgramContext } from '../../../../programContext'; export function FeedbackPage(): React.ReactElement { - const { baseUrl } = useBaseUrl(); + const { baseUrl, isAllPrograms } = useBaseUrl(); const permissions = usePermissions(); const { t } = useTranslation(); const location = useLocation(); - const { isActiveProgram, isAllPrograms } = useProgramContext(); + const { isActiveProgram } = useProgramContext(); const initialFilter = { feedbackId: '', diff --git a/frontend/src/containers/pages/paymentmodulepeople/CreatePeoplePaymentPlanPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/CreatePeoplePaymentPlanPage.tsx new file mode 100644 index 0000000000..10b95d608d --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/CreatePeoplePaymentPlanPage.tsx @@ -0,0 +1,151 @@ +import { Form, Formik } from 'formik'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { format, parseISO } from 'date-fns'; +import * as Yup from 'yup'; +import { LoadingComponent } from '@components/core/LoadingComponent'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { CreatePaymentPlanHeader } from '@components/paymentmodule/CreatePaymentPlan/CreatePaymentPlanHeader/CreatePaymentPlanHeader'; +import { PaymentPlanParameters } from '@components/paymentmodule/CreatePaymentPlan/PaymentPlanParameters'; +import { PaymentPlanTargeting } from '@components/paymentmodule/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { + useAllTargetPopulationsQuery, + useCreatePpMutation, +} from '@generated/graphql'; +import { AutoSubmitFormOnEnter } from '@components/core/AutoSubmitFormOnEnter'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { useNavigate } from 'react-router-dom'; + +export const CreatePeoplePaymentPlanPage = (): React.ReactElement => { + const navigate = useNavigate(); + const { t } = useTranslation(); + const [mutate, { loading: loadingCreate }] = useCreatePpMutation(); + const { showMessage } = useSnackbar(); + const { baseUrl, businessArea, programId } = useBaseUrl(); + const permissions = usePermissions(); + + const { data: allTargetPopulationsData, loading: loadingTargetPopulations } = + useAllTargetPopulationsQuery({ + variables: { + businessArea, + paymentPlanApplicable: true, + program: [programId], + }, + fetchPolicy: 'network-only', + }); + + if (loadingTargetPopulations) return ; + if (!allTargetPopulationsData) return null; + if (permissions === null) return null; + if (!hasPermissions(PERMISSIONS.PM_CREATE, permissions)) + return ; + + const validationSchema = Yup.object().shape({ + targetingId: Yup.string().required(t('Target Population is required')), + startDate: Yup.date().required(t('Start Date is required')), + endDate: Yup.date() + .required(t('End Date is required')) + .when('startDate', (startDate: any, schema: Yup.DateSchema) => + startDate && typeof startDate === 'string' + ? schema.min( + parseISO(startDate), + `${t('End date has to be greater than')} ${format(parseISO(startDate), 'yyyy-MM-dd')}`, + ) + : schema, + ), + currency: Yup.string().nullable().required(t('Currency is required')), + dispersionStartDate: Yup.date().required( + t('Dispersion Start Date is required'), + ), + dispersionEndDate: Yup.date() + .required(t('Dispersion End Date is required')) + .min(new Date(), t('Dispersion End Date cannot be in the past')) + .when( + 'dispersionStartDate', + (dispersionStartDate: any, schema: Yup.DateSchema) => + dispersionStartDate && typeof dispersionStartDate === 'string' + ? schema.min( + parseISO(dispersionStartDate), + `${t('Dispersion End Date has to be greater than')} ${format(parseISO(dispersionStartDate), 'yyyy-MM-dd')}`, + ) + : schema, + ), + }); + + type FormValues = Yup.InferType; + const initialValues: FormValues = { + targetingId: '', + startDate: null, + endDate: null, + currency: null, + dispersionStartDate: null, + dispersionEndDate: null, + }; + + const handleSubmit = async (values: FormValues): Promise => { + try { + const startDate = values.startDate + ? format(new Date(values.startDate), 'yyyy-MM-dd') + : null; + const endDate = values.endDate + ? format(new Date(values.endDate), 'yyyy-MM-dd') + : null; + const dispersionStartDate = values.dispersionStartDate + ? format(new Date(values.dispersionStartDate), 'yyyy-MM-dd') + : null; + const dispersionEndDate = values.dispersionEndDate + ? format(new Date(values.dispersionEndDate), 'yyyy-MM-dd') + : null; + + const res = await mutate({ + variables: { + //@ts-ignore + input: { + businessAreaSlug: businessArea, + ...values, + startDate, + endDate, + dispersionStartDate, + dispersionEndDate, + }, + }, + }); + showMessage(t('Payment Plan Created')); + navigate( + `/${baseUrl}/payment-module/payment-plans/${res.data.createPaymentPlan.paymentPlan.id}`, + ); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + return ( + + {({ submitForm, values }) => ( +
+ + + + + + )} +
+ ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/EditPeopleFollowUpPaymentPlanPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/EditPeopleFollowUpPaymentPlanPage.tsx new file mode 100644 index 0000000000..4fa43891d3 --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/EditPeopleFollowUpPaymentPlanPage.tsx @@ -0,0 +1,157 @@ +import { Form, Formik } from 'formik'; +import moment from 'moment'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import * as Yup from 'yup'; +import { + useAllTargetPopulationsQuery, + usePaymentPlanQuery, + useUpdatePpMutation, +} from '@generated/graphql'; +import { AutoSubmitFormOnEnter } from '@components/core/AutoSubmitFormOnEnter'; +import { LoadingComponent } from '@components/core/LoadingComponent'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { PaymentPlanParameters } from '@components/paymentmodule/CreatePaymentPlan/PaymentPlanParameters'; +import { PaymentPlanTargeting } from '@components/paymentmodule/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting'; +import { EditPaymentPlanHeader } from '@components/paymentmodule/EditPaymentPlan/EditPaymentPlanHeader'; +import { PERMISSIONS, hasPermissions } from '../../../config/permissions'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { usePermissions } from '@hooks/usePermissions'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { today } from '@utils/utils'; + +export const EditPeopleFollowUpPaymentPlanPage = (): React.ReactElement => { + const navigate = useNavigate(); + const { id } = useParams(); + const { t } = useTranslation(); + const { data: paymentPlanData, loading: loadingPaymentPlan } = + usePaymentPlanQuery({ + variables: { + id, + }, + fetchPolicy: 'cache-and-network', + }); + + const [mutate] = useUpdatePpMutation(); + const { showMessage } = useSnackbar(); + const { baseUrl, businessArea, programId } = useBaseUrl(); + const permissions = usePermissions(); + + const { data: allTargetPopulationsData, loading: loadingTargetPopulations } = + useAllTargetPopulationsQuery({ + variables: { + businessArea, + paymentPlanApplicable: false, + program: [programId], + }, + }); + if (loadingTargetPopulations || loadingPaymentPlan) + return ; + if (!allTargetPopulationsData || !paymentPlanData) return null; + if (permissions === null) return null; + if (!hasPermissions(PERMISSIONS.PM_CREATE, permissions)) + return ; + + const { paymentPlan } = paymentPlanData; + + const initialValues = { + targetingId: paymentPlan.targetPopulation.id, + startDate: paymentPlan.startDate, + endDate: paymentPlan.endDate, + currency: { + name: paymentPlan.currencyName, + value: paymentPlan.currency, + }, + dispersionStartDate: paymentPlan.dispersionStartDate, + dispersionEndDate: paymentPlan.dispersionEndDate, + }; + + const validationSchema = Yup.object().shape({ + targetingId: Yup.string().required(t('Target Population is required')), + currency: Yup.string().nullable().required(t('Currency is required')), + startDate: Yup.date().required(t('Start Date is required')), + endDate: Yup.date() + .required(t('End Date is required')) + .when('startDate', (startDate: any, schema: Yup.DateSchema) => + startDate + ? schema.min( + startDate, + `${t('End date has to be greater than')} ${moment( + startDate, + ).format('YYYY-MM-DD')}`, + ) + : schema, + ), + dispersionStartDate: Yup.date().required( + t('Dispersion Start Date is required'), + ), + dispersionEndDate: Yup.date() + .required(t('Dispersion End Date is required')) + .min(today, t('Dispersion End Date cannot be in the past')) + .when( + 'dispersionStartDate', + (dispersionStartDate: any, schema: Yup.DateSchema) => + dispersionStartDate + ? schema.min( + dispersionStartDate, + `${t('Dispersion End Date has to be greater than')} ${moment( + dispersionStartDate, + ).format('YYYY-MM-DD')}`, + ) + : schema, + ), + }); + + const handleSubmit = async (values): Promise => { + try { + const res = await mutate({ + variables: { + input: { + paymentPlanId: id, + targetingId: values.targetingId, + startDate: values.startDate, + endDate: values.endDate, + dispersionStartDate: values.dispersionStartDate, + dispersionEndDate: values.dispersionEndDate, + currency: values.currency?.value + ? values.currency.value + : values.currency, + }, + }, + }); + showMessage(t('Follow-up Payment Plan Edited')); + navigate( + `/${baseUrl}/payment-module/followup-payment-plans/${res.data.updatePaymentPlan.paymentPlan.id}`, + ); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + return ( + + {({ submitForm, values }) => ( +
+ + + + + + )} +
+ ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/EditPeopleFollowUpSetUpFspPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/EditPeopleFollowUpSetUpFspPage.tsx new file mode 100644 index 0000000000..c235845f8a --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/EditPeopleFollowUpSetUpFspPage.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import { useParams } from 'react-router-dom'; +import { LoadingComponent } from '@components/core/LoadingComponent'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { SetUpFspCore } from '@components/paymentmodule/CreateSetUpFsp/SetUpFspCore/SetUpFspCore'; +import { EditSetUpFspHeader } from '@components/paymentmodule/EditSetUpFsp/EditSetUpFspHeader'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { usePaymentPlanQuery } from '@generated/graphql'; + +export const EditPeopleFollowUpSetUpFspPage = (): React.ReactElement => { + const { id } = useParams(); + + const { data: paymentPlanData, loading: paymentPlanLoading } = + usePaymentPlanQuery({ + variables: { + id, + }, + fetchPolicy: 'cache-and-network', + }); + + const permissions = usePermissions(); + + if (permissions === null) return null; + if (!hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK_FSP, permissions)) + return ; + if (!paymentPlanData) return null; + if (paymentPlanLoading) return ; + + const mappedInitialDeliveryMechanisms = + paymentPlanData.paymentPlan.deliveryMechanisms.map((el) => ({ + deliveryMechanism: el.name, + fsp: el.fsp?.id || '', + chosenConfiguration: el.chosenConfiguration || '', + })); + + const initialValues = { + deliveryMechanisms: mappedInitialDeliveryMechanisms, + }; + + return ( + <> + + + + ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/EditPeoplePaymentPlanPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/EditPeoplePaymentPlanPage.tsx new file mode 100644 index 0000000000..c7cda427bc --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/EditPeoplePaymentPlanPage.tsx @@ -0,0 +1,155 @@ +import { Form, Formik } from 'formik'; +import * as React from 'react'; +import { useNavigate, useParams } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import moment from 'moment'; +import * as Yup from 'yup'; +import { LoadingComponent } from '@components/core/LoadingComponent'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { PaymentPlanParameters } from '@components/paymentmodule/CreatePaymentPlan/PaymentPlanParameters'; +import { PaymentPlanTargeting } from '@components/paymentmodule/CreatePaymentPlan/PaymentPlanTargeting/PaymentPlanTargeting'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { useSnackbar } from '@hooks/useSnackBar'; +import { today } from '@utils/utils'; +import { + useAllTargetPopulationsQuery, + usePaymentPlanQuery, + useUpdatePpMutation, +} from '@generated/graphql'; +import { EditPaymentPlanHeader } from '@components/paymentmodule/EditPaymentPlan/EditPaymentPlanHeader'; +import { AutoSubmitFormOnEnter } from '@components/core/AutoSubmitFormOnEnter'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +export const EditPeoplePaymentPlanPage = (): React.ReactElement => { + const navigate = useNavigate(); + const { id } = useParams(); + const { t } = useTranslation(); + const { data: paymentPlanData, loading: loadingPaymentPlan } = + usePaymentPlanQuery({ + variables: { + id, + }, + fetchPolicy: 'cache-and-network', + }); + + const [mutate] = useUpdatePpMutation(); + const { showMessage } = useSnackbar(); + const { baseUrl, businessArea, programId } = useBaseUrl(); + const permissions = usePermissions(); + + const { data: allTargetPopulationsData, loading: loadingTargetPopulations } = + useAllTargetPopulationsQuery({ + variables: { + businessArea, + paymentPlanApplicable: false, + program: [programId], + }, + }); + if (loadingTargetPopulations || loadingPaymentPlan) + return ; + if (!allTargetPopulationsData || !paymentPlanData) return null; + if (permissions === null) return null; + if (!hasPermissions(PERMISSIONS.PM_CREATE, permissions)) + return ; + const { paymentPlan } = paymentPlanData; + + const initialValues = { + targetingId: paymentPlan.targetPopulation.id, + startDate: paymentPlan.startDate, + endDate: paymentPlan.endDate, + currency: { + name: paymentPlan.currencyName, + value: paymentPlan.currency, + }, + dispersionStartDate: paymentPlan.dispersionStartDate, + dispersionEndDate: paymentPlan.dispersionEndDate, + }; + + const validationSchema = Yup.object().shape({ + targetingId: Yup.string().required(t('Target Population is required')), + startDate: Yup.date(), + endDate: Yup.date() + .required(t('End Date is required')) + .when('startDate', (startDate: any, schema: Yup.DateSchema) => + startDate + ? schema.min( + startDate as Date, + `${t('End date has to be greater than')} ${moment( + startDate, + ).format('YYYY-MM-DD')}`, + ) + : schema, + ), + dispersionStartDate: Yup.date().required( + t('Dispersion Start Date is required'), + ), + dispersionEndDate: Yup.date() + .required(t('Dispersion End Date is required')) + .min(today, t('Dispersion End Date cannot be in the past')) + .when( + 'dispersionStartDate', + (dispersionStartDate: any, schema: Yup.DateSchema) => + dispersionStartDate + ? schema.min( + dispersionStartDate as Date, + `${t('Dispersion End Date has to be greater than')} ${moment( + dispersionStartDate, + ).format('YYYY-MM-DD')}`, + ) + : schema, + ), + }); + + const handleSubmit = async (values): Promise => { + try { + const res = await mutate({ + variables: { + input: { + paymentPlanId: id, + targetingId: values.targetingId, + startDate: values.startDate, + endDate: values.endDate, + dispersionStartDate: values.dispersionStartDate, + dispersionEndDate: values.dispersionEndDate, + currency: values.currency?.value + ? values.currency.value + : values.currency, + }, + }, + }); + showMessage(t('Payment Plan Edited')); + navigate( + `/${baseUrl}/payment-module/payment-plans/${res.data.updatePaymentPlan.paymentPlan.id}`, + ); + } catch (e) { + e.graphQLErrors.map((x) => showMessage(x.message)); + } + }; + + return ( + + {({ submitForm, values }) => ( +
+ + + + + + )} +
+ ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/EditPeopleSetUpFspPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/EditPeopleSetUpFspPage.tsx new file mode 100644 index 0000000000..2e7d505514 --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/EditPeopleSetUpFspPage.tsx @@ -0,0 +1,47 @@ +import * as React from 'react'; +import { useParams } from 'react-router-dom'; +import { LoadingComponent } from '@components/core/LoadingComponent'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { SetUpFspCore } from '@components/paymentmodule/CreateSetUpFsp/SetUpFspCore/SetUpFspCore'; +import { EditSetUpFspHeader } from '@components/paymentmodule/EditSetUpFsp/EditSetUpFspHeader'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { usePaymentPlanQuery } from '@generated/graphql'; + +export const EditPeopleSetUpFspPage = (): React.ReactElement => { + const { id } = useParams(); + + const { data: paymentPlanData, loading: paymentPlanLoading } = + usePaymentPlanQuery({ + variables: { + id, + }, + fetchPolicy: 'cache-and-network', + }); + + const permissions = usePermissions(); + + if (permissions === null) return null; + if (!hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK_FSP, permissions)) + return ; + if (!paymentPlanData) return null; + if (paymentPlanLoading) return ; + + const mappedInitialDeliveryMechanisms = + paymentPlanData.paymentPlan.deliveryMechanisms.map((el) => ({ + deliveryMechanism: el.name, + fsp: el.fsp?.id || '', + chosenConfiguration: el.chosenConfiguration || '', + })); + + const initialValues = { + deliveryMechanisms: mappedInitialDeliveryMechanisms, + }; + + return ( + <> + + + + ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/PeopleFollowUpPaymentPlanDetailsPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/PeopleFollowUpPaymentPlanDetailsPage.tsx new file mode 100644 index 0000000000..e926bf6b35 --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/PeopleFollowUpPaymentPlanDetailsPage.tsx @@ -0,0 +1,94 @@ +import * as React from 'react'; +import { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import { PaymentPlanStatus, usePaymentPlanQuery } from '@generated/graphql'; +import { LoadingComponent } from '@components/core/LoadingComponent'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { FollowUpPaymentPlanDetails } from '@components/paymentmodule/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetails'; +import { FollowUpPaymentPlanDetailsHeader } from '@components/paymentmodule/FollowUpPaymentPlanDetails/FollowUpPaymentPlanDetailsHeader'; +import { AcceptanceProcess } from '@components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcess'; +import { Entitlement } from '@components/paymentmodule/PaymentPlanDetails/Entitlement/Entitlement'; +import { FspSection } from '@components/paymentmodule/PaymentPlanDetails/FspSection'; +import { PaymentPlanDetailsResults } from '@components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsResults'; +import { ReconciliationSummary } from '@components/paymentmodule/PaymentPlanDetails/ReconciliationSummary'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { isPermissionDeniedError } from '@utils/utils'; +import { PaymentsTable } from '../../tables/paymentmodule/PaymentsTable'; +import { UniversalActivityLogTable } from '../../tables/UniversalActivityLogTable'; +import { ExcludeSection } from '@components/paymentmodule/PaymentPlanDetails/ExcludeSection'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +export const PeopleFollowUpPaymentPlanDetailsPage = (): React.ReactElement => { + const { id } = useParams(); + const permissions = usePermissions(); + const { baseUrl, businessArea } = useBaseUrl(); + const { data, loading, startPolling, stopPolling, error } = + usePaymentPlanQuery({ + variables: { + id, + }, + fetchPolicy: 'cache-and-network', + }); + + const status = data?.paymentPlan?.status; + + useEffect(() => { + if (PaymentPlanStatus.Preparing === status) { + startPolling(3000); + } else { + stopPolling(); + } + return stopPolling; + }, [status, startPolling, stopPolling]); + + if (loading && !data) return ; + if (permissions === null || !data) return null; + + if ( + !hasPermissions(PERMISSIONS.PM_VIEW_DETAILS, permissions) || + isPermissionDeniedError(error) + ) + return ; + + const shouldDisplayEntitlement = + status !== PaymentPlanStatus.Open && status !== PaymentPlanStatus.Accepted; + + const shouldDisplayFsp = status !== PaymentPlanStatus.Open; + const shouldDisplayReconciliationSummary = + status === PaymentPlanStatus.Accepted || + status === PaymentPlanStatus.Finished; + + const { paymentPlan } = data; + return ( + <> + + + + {shouldDisplayEntitlement && ( + + )} + {shouldDisplayFsp && ( + + )} + + + + {shouldDisplayReconciliationSummary && ( + + )} + {hasPermissions(PERMISSIONS.ACTIVITY_LOG_VIEW, permissions) && ( + + )} + + ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentDetailsPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentDetailsPage.tsx new file mode 100644 index 0000000000..cb818aa86a --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentDetailsPage.tsx @@ -0,0 +1,100 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import { useParams } from 'react-router-dom'; +import { BreadCrumbsItem } from '@components/core/BreadCrumbs'; +import { LoadingComponent } from '@components/core/LoadingComponent'; +import { PageHeader } from '@components/core/PageHeader'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { + PaymentPlanStatus, + PaymentStatus, + useCashAssistUrlPrefixQuery, + usePaymentQuery, +} from '@generated/graphql'; +import { PaymentDetails } from '@components/paymentmodule/PaymentDetails'; +import { RevertForceFailedButton } from '@components/paymentmodule/RevertForceFailedButton'; +import { ForceFailedButton } from '@components/paymentmodule/ForceFailedButton'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { AdminButton } from '@core/AdminButton'; + +export const PeoplePaymentDetailsPage = (): React.ReactElement => { + const { t } = useTranslation(); + const { id } = useParams(); + const { data: caData, loading: caLoading } = useCashAssistUrlPrefixQuery({ + fetchPolicy: 'cache-first', + }); + const { data, loading } = usePaymentQuery({ + variables: { id }, + fetchPolicy: 'cache-and-network', + }); + const paymentPlanStatus = data?.payment?.parent?.status; + const paymentPlanIsFollowUp = data?.payment?.parent?.isFollowUp; + const permissions = usePermissions(); + const { baseUrl } = useBaseUrl(); + if (loading || caLoading) return ; + if (permissions === null) return null; + if (!hasPermissions(PERMISSIONS.PM_VIEW_DETAILS, permissions)) + return ; + + if (!data || !caData) return null; + const { payment } = data; + const breadCrumbsItems: BreadCrumbsItem[] = [ + { + title: t('Payment Module'), + to: `/${baseUrl}/payment-module/`, + }, + { + title: ` ${paymentPlanIsFollowUp ? 'Follow-up ' : ''} Payment Plan ${ + payment.parent.unicefId + }`, + to: `/${baseUrl}/payment-module/${ + paymentPlanIsFollowUp ? 'followup-payment-plans' : 'payment-plans' + }/${data.payment.parent.id}/`, + }, + ]; + + const renderButton = (): React.ReactElement | null => { + if ( + (hasPermissions(PERMISSIONS.PM_MARK_PAYMENT_AS_FAILED, permissions) && + paymentPlanStatus === PaymentPlanStatus.Accepted) || + paymentPlanStatus === PaymentPlanStatus.Finished + ) { + const ButtonComponent = + payment.status === PaymentStatus.ForceFailed + ? RevertForceFailedButton + : ForceFailedButton; + return ; + } + return null; + }; + + const canViewHouseholdDetails = hasPermissions( + PERMISSIONS.POPULATION_VIEW_HOUSEHOLDS_DETAILS, + permissions, + ); + + return ( + <> + } + > + {renderButton()} + + + + + + ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentModulePage.tsx b/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentModulePage.tsx new file mode 100644 index 0000000000..82cc700cbd --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentModulePage.tsx @@ -0,0 +1,81 @@ +import * as React from 'react'; +import { useState } from 'react'; +import { Link, useLocation } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { PageHeader } from '@components/core/PageHeader'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { TableWrapper } from '@components/core/TableWrapper'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { getFilterFromQueryParams } from '@utils/utils'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { ButtonTooltip } from '@components/core/ButtonTooltip'; +import { useProgramContext } from '../../../programContext'; +import { PeoplePaymentPlansTable } from '@containers/tables/paymentmodulePeople/PeoplePaymentPlansTable'; +import { PeoplePaymentPlansFilters } from '@containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansFilters'; + +const initialFilter = { + search: '', + dispersionStartDate: '', + dispersionEndDate: '', + status: [], + totalEntitledQuantityFrom: '', + totalEntitledQuantityTo: '', + isFollowUp: '', +}; + +export const PeoplePaymentModulePage = (): React.ReactElement => { + const { t } = useTranslation(); + const { baseUrl } = useBaseUrl(); + const permissions = usePermissions(); + const location = useLocation(); + const { isActiveProgram } = useProgramContext(); + + const [filter, setFilter] = useState( + getFilterFromQueryParams(location, initialFilter), + ); + const [appliedFilter, setAppliedFilter] = useState( + getFilterFromQueryParams(location, initialFilter), + ); + + if (permissions === null) return null; + + if (!hasPermissions(PERMISSIONS.PM_VIEW_LIST, permissions)) + return ; + + return ( + <> + + {hasPermissions(PERMISSIONS.PM_CREATE, permissions) && ( + + {t('NEW PAYMENT PLAN')} + + )} + + + + + + + ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentPlanDetailsPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentPlanDetailsPage.tsx new file mode 100644 index 0000000000..7378cb691d --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/PeoplePaymentPlanDetailsPage.tsx @@ -0,0 +1,110 @@ +import { Box } from '@mui/material'; +import * as React from 'react'; +import { useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import { + PaymentPlanBackgroundActionStatus, + PaymentPlanStatus, + usePaymentPlanQuery, +} from '@generated/graphql'; +import { LoadingComponent } from '@components/core/LoadingComponent'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { AcceptanceProcess } from '@components/paymentmodule/PaymentPlanDetails/AcceptanceProcess/AcceptanceProcess'; +import { Entitlement } from '@components/paymentmodule/PaymentPlanDetails/Entitlement/Entitlement'; +import { ExcludeSection } from '@components/paymentmodule/PaymentPlanDetails/ExcludeSection'; +import { FspSection } from '@components/paymentmodule/PaymentPlanDetails/FspSection'; +import { PaymentPlanDetails } from '@components/paymentmodule/PaymentPlanDetails/PaymentPlanDetails'; +import { PaymentPlanDetailsHeader } from '@components/paymentmodule/PaymentPlanDetails/PaymentPlanDetailsHeader'; +import { ReconciliationSummary } from '@components/paymentmodule/PaymentPlanDetails/ReconciliationSummary'; +import { PERMISSIONS, hasPermissions } from '../../../config/permissions'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { usePermissions } from '@hooks/usePermissions'; +import { isPermissionDeniedError } from '@utils/utils'; +import { UniversalActivityLogTable } from '../../tables/UniversalActivityLogTable'; +import { PeoplePaymentPlanDetailsResults } from '@components/paymentmodulepeople/PaymentPlanDetails/PeoplePaymentPlanDetailsResults'; +import { PeoplePaymentsTable } from '@containers/tables/paymentmodulePeople/PeoplePaymentsTable'; + +export const PeoplePaymentPlanDetailsPage = (): React.ReactElement => { + const { id } = useParams(); + const permissions = usePermissions(); + const { baseUrl, businessArea } = useBaseUrl(); + const { data, loading, startPolling, stopPolling, error } = + usePaymentPlanQuery({ + variables: { + id, + }, + fetchPolicy: 'cache-and-network', + }); + + const status = data?.paymentPlan?.status; + const backgroundActionStatus = data?.paymentPlan?.backgroundActionStatus; + + useEffect(() => { + if ( + PaymentPlanStatus.Preparing === status || + (backgroundActionStatus !== null && + backgroundActionStatus !== + PaymentPlanBackgroundActionStatus.ExcludeBeneficiariesError) + ) { + startPolling(3000); + } else { + stopPolling(); + } + return stopPolling; + }, [status, backgroundActionStatus, startPolling, stopPolling]); + + if (loading && !data) return ; + if (permissions === null || !data) return null; + + if ( + !hasPermissions(PERMISSIONS.PM_VIEW_DETAILS, permissions) || + isPermissionDeniedError(error) + ) + return ; + + const shouldDisplayEntitlement = + status !== PaymentPlanStatus.Open && status !== PaymentPlanStatus.Accepted; + + const shouldDisplayFsp = status !== PaymentPlanStatus.Open; + const shouldDisplayReconciliationSummary = + status === PaymentPlanStatus.Accepted || + status === PaymentPlanStatus.Finished; + + const { paymentPlan } = data; + + return ( + + + + {status !== PaymentPlanStatus.Preparing && ( + <> + + {shouldDisplayEntitlement && ( + + )} + {shouldDisplayFsp && ( + + )} + + + + {shouldDisplayReconciliationSummary && ( + + )} + {hasPermissions(PERMISSIONS.ACTIVITY_LOG_VIEW, permissions) && ( + + )} + + )} + + ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/SetUpPeopleFollowUpFspPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/SetUpPeopleFollowUpFspPage.tsx new file mode 100644 index 0000000000..44b10b4c93 --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/SetUpPeopleFollowUpFspPage.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { CreateSetUpFspHeader } from '@components/paymentmodule/CreateSetUpFsp/CreateSetUpFspHeader'; +import { SetUpFspCore } from '@components/paymentmodule/CreateSetUpFsp/SetUpFspCore/SetUpFspCore'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +export const SetUpPeopleFollowUpFspPage = (): React.ReactElement => { + const { baseUrl } = useBaseUrl(); + const permissions = usePermissions(); + + if (permissions === null) return null; + if (!hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK_FSP, permissions)) + return ; + + const initialValues = { + deliveryMechanisms: [ + { + deliveryMechanism: '', + fsp: '', + chosenConfiguration: '', + }, + ], + }; + + return ( + <> + + + + ); +}; diff --git a/frontend/src/containers/pages/paymentmodulepeople/SetUpPeopleFspPage.tsx b/frontend/src/containers/pages/paymentmodulepeople/SetUpPeopleFspPage.tsx new file mode 100644 index 0000000000..0be8ddca47 --- /dev/null +++ b/frontend/src/containers/pages/paymentmodulepeople/SetUpPeopleFspPage.tsx @@ -0,0 +1,33 @@ +import * as React from 'react'; +import { PermissionDenied } from '@components/core/PermissionDenied'; +import { CreateSetUpFspHeader } from '@components/paymentmodule/CreateSetUpFsp/CreateSetUpFspHeader'; +import { SetUpFspCore } from '@components/paymentmodule/CreateSetUpFsp/SetUpFspCore/SetUpFspCore'; +import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; +import { usePermissions } from '@hooks/usePermissions'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +export const SetUpPeopleFspPage = (): React.ReactElement => { + const { baseUrl } = useBaseUrl(); + const permissions = usePermissions(); + + if (permissions === null) return null; + if (!hasPermissions(PERMISSIONS.PM_LOCK_AND_UNLOCK_FSP, permissions)) + return ; + + const initialValues = { + deliveryMechanisms: [ + { + deliveryMechanism: '', + fsp: '', + chosenConfiguration: '', + }, + ], + }; + + return ( + <> + + + + ); +}; diff --git a/frontend/src/containers/pages/payments/CashPlanVerificationDetailsPage.tsx b/frontend/src/containers/pages/payments/CashPlanVerificationDetailsPage.tsx index 4bb6c0d389..57cd225cf5 100644 --- a/frontend/src/containers/pages/payments/CashPlanVerificationDetailsPage.tsx +++ b/frontend/src/containers/pages/payments/CashPlanVerificationDetailsPage.tsx @@ -30,6 +30,8 @@ import { import { UniversalActivityLogTablePaymentVerification } from '../../tables/UniversalActivityLogTablePaymentVerification'; import { VerificationRecordsTable } from '../../tables/payments/VerificationRecordsTable'; import { VerificationRecordsFilters } from '../../tables/payments/VerificationRecordsTable/VerificationRecordsFilters'; +import { useProgramContext } from '../../../programContext'; +import { PeopleVerificationRecordsTable } from '@containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTable'; const Container = styled.div` display: flex; @@ -60,6 +62,7 @@ const initialFilter = { export function CashPlanVerificationDetailsPage(): React.ReactElement { const { t } = useTranslation(); + const { isSocialDctType } = useProgramContext(); const permissions = usePermissions(); const { baseUrl, businessArea, isAllPrograms } = useBaseUrl(); @@ -159,6 +162,33 @@ export function CashPlanVerificationDetailsPage(): React.ReactElement { ); + const renderVerificationRecordsTable = () => { + if (isSocialDctType) { + return ( + + ); + } + return ( + + ); + }; + return ( <> {toolbar} @@ -190,17 +220,7 @@ export function CashPlanVerificationDetailsPage(): React.ReactElement { verifications={cashPlan.verificationPlans} /> - - - + {renderVerificationRecordsTable()} ) : null} {canSeeActivationMessage() ? ( diff --git a/frontend/src/containers/pages/payments/PaymentPlanVerificationDetailsPage.tsx b/frontend/src/containers/pages/payments/PaymentPlanVerificationDetailsPage.tsx index 0660796c0e..e2951d8b1c 100644 --- a/frontend/src/containers/pages/payments/PaymentPlanVerificationDetailsPage.tsx +++ b/frontend/src/containers/pages/payments/PaymentPlanVerificationDetailsPage.tsx @@ -29,6 +29,8 @@ import { import { UniversalActivityLogTablePaymentVerification } from '../../tables/UniversalActivityLogTablePaymentVerification'; import { VerificationsTable } from '../../tables/payments/VerificationRecordsTable'; import { VerificationRecordsFilters } from '../../tables/payments/VerificationRecordsTable/VerificationRecordsFilters'; +import { useProgramContext } from '../../../programContext'; +import { PeopleVerificationsTable } from '@containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationsTable'; const Container = styled.div` display: flex; @@ -76,6 +78,7 @@ export function PaymentPlanVerificationDetailsPage(): React.ReactElement { }); const { data: choicesData, loading: choicesLoading } = useCashPlanVerificationSamplingChoicesQuery(); + const { isSocialDctType } = useProgramContext(); if (loading || choicesLoading) return ; @@ -166,6 +169,33 @@ export function PaymentPlanVerificationDetailsPage(): React.ReactElement { ); + const renderVerificationsTable = () => { + if (isSocialDctType) { + return ( + + ); + } + return ( + + ); + }; + return ( <> {toolbar} @@ -195,17 +225,7 @@ export function PaymentPlanVerificationDetailsPage(): React.ReactElement { setAppliedFilter={setAppliedFilter} verifications={paymentPlan.verificationPlans} /> - - - + {renderVerificationsTable()} ) : null} {canSeeActivationMessage() ? ( diff --git a/frontend/src/containers/pages/people/PeopleDetailsPage.tsx b/frontend/src/containers/pages/people/PeopleDetailsPage.tsx index f84701f236..19d2fdbed6 100644 --- a/frontend/src/containers/pages/people/PeopleDetailsPage.tsx +++ b/frontend/src/containers/pages/people/PeopleDetailsPage.tsx @@ -1,9 +1,10 @@ -import { Box } from '@mui/material'; +import { Box, Grid, Paper, Typography } from '@mui/material'; import * as React from 'react'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; import styled from 'styled-components'; import { + HouseholdNode, IndividualNode, useAllIndividualsFlexFieldsAttributesQuery, useGrievancesChoiceDataQuery, @@ -20,19 +21,43 @@ import { IndividualVulnerabilities } from '@components/population/IndividualVuln import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; import { useBaseUrl } from '@hooks/useBaseUrl'; import { usePermissions } from '@hooks/usePermissions'; -import { isPermissionDeniedError } from '@utils/utils'; +import { + formatCurrencyWithSymbol, + isPermissionDeniedError, +} from '@utils/utils'; import { UniversalActivityLogTable } from '../../tables/UniversalActivityLogTable'; import { AdminButton } from '@core/AdminButton'; import { PeopleBioData } from '@components/people/PeopleBioData/PeopleBioData'; +import { Title } from '@core/Title'; +import { LabelizedField } from '@core/LabelizedField'; +import { + BigValue, + BigValueContainer, +} from '@components/rdi/details/RegistrationDetails/RegistrationDetails'; +import { UniversalMoment } from '@core/UniversalMoment'; +import { PaymentRecordAndPaymentPeopleTable } from '@containers/tables/payments/PaymentRecordAndPaymentPeopleTable'; const Container = styled.div` - padding: 20px; + padding: 20px 20px 00px 20px; && { display: flex; flex-direction: column; width: 100%; } `; +const OverviewPaper = styled(Paper)` + margin: 0px 0px 20px 0px; + padding: 20px ${({ theme }) => theme.spacing(11)}; +`; +const Overview = styled(Paper)` + margin: 15px 0px 20px 0px; + padding: 20px ${({ theme }) => theme.spacing(11)}; +`; +const SubTitle = styled(Typography)` + && { + font-size: 16px; + } +`; export function PeopleDetailsPage(): React.ReactElement { const { t } = useTranslation(); @@ -83,6 +108,7 @@ export function PeopleDetailsPage(): React.ReactElement { ]; const { individual } = data; + const household = individual?.household; return ( <> @@ -122,10 +148,132 @@ export function PeopleDetailsPage(): React.ReactElement { flexFieldsData={flexFieldsData} individual={individual as IndividualNode} /> - {hasPermissions(PERMISSIONS.ACTIVITY_LOG_VIEW, permissions) && ( - + + + <Typography variant="h6">{t('Benefits')}</Typography> + + + + + {household?.deliveredQuantities?.length ? ( + + + + + {household?.deliveredQuantities?.map((item) => ( + + {item.currency === 'USD' + ? formatCurrencyWithSymbol( + item.totalDeliveredQuantity, + item.currency, + ) + : `(${formatCurrencyWithSymbol( + item.totalDeliveredQuantity, + item.currency, + )})`} + + ))} + + + + + ) : ( + <>- + )} + + + + + + + {formatCurrencyWithSymbol( + household?.totalCashReceivedUsd, + 'USD', + )} + + + + + + + {hasPermissions( + PERMISSIONS.PROGRAMME_VIEW_LIST_AND_DETAILS, + permissions, + ) && ( + )} + + + + <Typography variant="h6">{t('Registration Details')}</Typography> + + + + +
{household?.registrationDataImport?.dataSource}
+
+
+ + +
{household?.registrationDataImport?.name}
+
+
+ + +
+ + {household?.lastRegistrationDate} + +
+
+
+ + + {household?.registrationDataImport?.importedBy?.email} + + +
+ {household?.registrationDataImport?.dataSource === 'XLS' ? null : ( + <> +
+ {t('Data Collection')} + + + + {household?.start} + + + + + + {household?.firstRegistrationDate} + + + + + + {/* //TODO: Figure it out. deviceId removed from the model? */} + {/* {household?.deviceid} */} - + + + + + )} +
+ {hasPermissions(PERMISSIONS.ACTIVITY_LOG_VIEW, permissions) && ( + + )} ); } diff --git a/frontend/src/containers/pages/people/PeoplePage.tsx b/frontend/src/containers/pages/people/PeoplePage.tsx index 29007793f2..c42442d5b1 100644 --- a/frontend/src/containers/pages/people/PeoplePage.tsx +++ b/frontend/src/containers/pages/people/PeoplePage.tsx @@ -10,14 +10,14 @@ import { import { LoadingComponent } from '@components/core/LoadingComponent'; import { PageHeader } from '@components/core/PageHeader'; import { PermissionDenied } from '@components/core/PermissionDenied'; -import { IndividualsFilter } from '@components/population/IndividualsFilter'; import { hasPermissions, PERMISSIONS } from '../../../config/permissions'; import { useBaseUrl } from '@hooks/useBaseUrl'; import { usePermissions } from '@hooks/usePermissions'; import { getFilterFromQueryParams } from '@utils/utils'; import { PeopleListTable } from '@containers/tables/people/PeopleListTable'; +import { PeopleFilter } from '@components/people/PeopleFilter'; -export function PeoplePage(): React.ReactElement { +export const PeoplePage = (): React.ReactElement => { const { t } = useTranslation(); const location = useLocation(); const { businessArea } = useBaseUrl(); @@ -64,7 +64,7 @@ export function PeoplePage(): React.ReactElement { return ( <> - ); -} +}; diff --git a/frontend/src/containers/pages/program/CreateProgramPage.tsx b/frontend/src/containers/pages/program/CreateProgramPage.tsx index 09e8525dd3..2b2e5038ba 100644 --- a/frontend/src/containers/pages/program/CreateProgramPage.tsx +++ b/frontend/src/containers/pages/program/CreateProgramPage.tsx @@ -17,14 +17,10 @@ import { PartnersStep } from '@components/programs/CreateProgram/PartnersStep'; import { programValidationSchema } from '@components/programs/CreateProgram/programValidationSchema'; import { useBaseUrl } from '@hooks/useBaseUrl'; import { useSnackbar } from '@hooks/useSnackBar'; -import { - hasPermissionInModule, - PERMISSIONS, -} from '../../../config/permissions'; +import { hasPermissionInModule } from '../../../config/permissions'; import { usePermissions } from '@hooks/usePermissions'; import { BreadCrumbsItem } from '@components/core/BreadCrumbs'; import { useNavigate } from 'react-router-dom'; -import { decodeIdString } from '@utils/utils'; export const CreateProgramPage = (): ReactElement => { const navigate = useNavigate(); diff --git a/frontend/src/containers/pages/program/DuplicateProgramPage.tsx b/frontend/src/containers/pages/program/DuplicateProgramPage.tsx index a1ab3cbcd9..b7c62acc96 100644 --- a/frontend/src/containers/pages/program/DuplicateProgramPage.tsx +++ b/frontend/src/containers/pages/program/DuplicateProgramPage.tsx @@ -19,10 +19,7 @@ import { programValidationSchema } from '@components/programs/CreateProgram/prog import { useBaseUrl } from '@hooks/useBaseUrl'; import { useSnackbar } from '@hooks/useSnackBar'; import { BreadCrumbsItem } from '@components/core/BreadCrumbs'; -import { - hasPermissionInModule, - PERMISSIONS, -} from '../../../config/permissions'; +import { hasPermissionInModule } from '../../../config/permissions'; import { usePermissions } from '@hooks/usePermissions'; import { decodeIdString } from '@utils/utils'; @@ -53,8 +50,8 @@ export const DuplicateProgramPage = (): ReactElement => { : 0; const partnersToSet = values.partnerAccess === ProgramPartnerAccess.SelectedPartnersAccess - ? values.partners.map(({ id, areas, areaAccess }) => ({ - partner: id, + ? values.partners.map(({ id: partnerId, areas, areaAccess }) => ({ + partner: partnerId, areas: areaAccess === 'ADMIN_AREA' ? areas : [], areaAccess, })) diff --git a/frontend/src/containers/pages/program/EditProgramPage.tsx b/frontend/src/containers/pages/program/EditProgramPage.tsx index 255d021898..1222ddfe72 100644 --- a/frontend/src/containers/pages/program/EditProgramPage.tsx +++ b/frontend/src/containers/pages/program/EditProgramPage.tsx @@ -21,10 +21,7 @@ import { useBaseUrl } from '@hooks/useBaseUrl'; import { useSnackbar } from '@hooks/useSnackBar'; import { decodeIdString } from '@utils/utils'; import { BreadCrumbsItem } from '@components/core/BreadCrumbs'; -import { - hasPermissionInModule, - PERMISSIONS, -} from '../../../config/permissions'; +import { hasPermissionInModule } from '../../../config/permissions'; import { usePermissions } from '@hooks/usePermissions'; export const EditProgramPage = (): ReactElement => { @@ -98,8 +95,8 @@ export const EditProgramPage = (): ReactElement => { : 0; const partnersToSet = values.partnerAccess === ProgramPartnerAccess.SelectedPartnersAccess - ? values.partners.map(({ id, areas, areaAccess }) => ({ - partner: id, + ? values.partners.map(({ id: partnerId, areas, areaAccess }) => ({ + partner: partnerId, areas: areaAccess === 'ADMIN_AREA' ? areas : [], areaAccess, })) diff --git a/frontend/src/containers/pages/rdi/people/RegistrationDataImportForPeopleDetailsPage.tsx b/frontend/src/containers/pages/rdi/people/PeopleRegistrationDataImportDetailsPage.tsx similarity index 98% rename from frontend/src/containers/pages/rdi/people/RegistrationDataImportForPeopleDetailsPage.tsx rename to frontend/src/containers/pages/rdi/people/PeopleRegistrationDataImportDetailsPage.tsx index cb5e46fd2e..4792203fc8 100644 --- a/frontend/src/containers/pages/rdi/people/RegistrationDataImportForPeopleDetailsPage.tsx +++ b/frontend/src/containers/pages/rdi/people/PeopleRegistrationDataImportDetailsPage.tsx @@ -57,7 +57,7 @@ const TabPanel = ({ ); }; -export const RegistrationDataImportForPeopleDetailsPage = +export const PeopleRegistrationDataImportDetailsPage = (): React.ReactElement => { const { t } = useTranslation(); const { id } = useParams(); diff --git a/frontend/src/containers/pages/rdi/people/RegistrationDataForPeopleImportPage.tsx b/frontend/src/containers/pages/rdi/people/PeopleRegistrationDataImportPage.tsx similarity index 96% rename from frontend/src/containers/pages/rdi/people/RegistrationDataForPeopleImportPage.tsx rename to frontend/src/containers/pages/rdi/people/PeopleRegistrationDataImportPage.tsx index 7da7c8c6e2..ba709eacaf 100644 --- a/frontend/src/containers/pages/rdi/people/RegistrationDataForPeopleImportPage.tsx +++ b/frontend/src/containers/pages/rdi/people/PeopleRegistrationDataImportPage.tsx @@ -21,7 +21,7 @@ const initialFilter = { importDateRangeMax: '', }; -export function RegistrationDataForPeopleImportPage(): React.ReactElement { +export function PeopleRegistrationDataImportPage(): React.ReactElement { const location = useLocation(); const permissions = usePermissions(); const { t } = useTranslation(); diff --git a/frontend/src/containers/pages/rdi/people/RegistrationPeopleDetailsPage.tsx b/frontend/src/containers/pages/rdi/people/PeopleRegistrationDetailsPage.tsx similarity index 81% rename from frontend/src/containers/pages/rdi/people/RegistrationPeopleDetailsPage.tsx rename to frontend/src/containers/pages/rdi/people/PeopleRegistrationDetailsPage.tsx index 4ae9fe69c1..01d3fc17af 100644 --- a/frontend/src/containers/pages/rdi/people/RegistrationPeopleDetailsPage.tsx +++ b/frontend/src/containers/pages/rdi/people/PeopleRegistrationDetailsPage.tsx @@ -18,7 +18,6 @@ import { useHouseholdChoiceDataQuery, useImportedIndividualQuery, } from '@generated/graphql'; -import { useBaseUrl } from '@hooks/useBaseUrl'; const Container = styled.div` padding: 20px; @@ -29,10 +28,9 @@ const Container = styled.div` } `; -export function RegistrationPeopleDetailsPage(): React.ReactElement { +export function PeopleRegistrationDetailsPage(): React.ReactElement { const { t } = useTranslation(); const { id } = useParams(); - const { baseUrl } = useBaseUrl(); const permissions = usePermissions(); const { data: flexFieldsData, loading: flexFieldsDataLoading } = useAllIndividualsFlexFieldsAttributesQuery(); @@ -55,27 +53,18 @@ export function RegistrationPeopleDetailsPage(): React.ReactElement { const breadCrumbsItems: BreadCrumbsItem[] = [ ...(hasPermissions(PERMISSIONS.RDI_VIEW_LIST, permissions) ? [ - { - title: t('Registration Data import'), - to: `/${baseUrl}/registration-data-import/`, - }, - ] + { + title: t('Registration Data import'), + to: '../..', + }, + ] : []), { title: importedIndividual.registrationDataImport.name, - to: `/${baseUrl}/registration-data-import/${btoa( - `RegistrationDataImportNode:${importedIndividual.registrationDataImport.hctId}`, - )}`, + to: '..', }, ]; - if (importedIndividual?.household?.id) { - breadCrumbsItems.push({ - title: `${t('HOUSEHOLD ID')}: ${importedIndividual?.household.importId}`, - to: `/${baseUrl}/registration-data-import/household/${importedIndividual?.household?.id}`, - }); - } - return (
{ const location = useLocation(); const { t } = useTranslation(); const permissions = usePermissions(); - + const { programId } = useBaseUrl(); + const { data: programData } = useProgramQuery({ + variables: { id: programId }, + }); const [filter, setFilter] = useState( getFilterFromQueryParams(location, initialFilter), ); @@ -42,7 +49,13 @@ export const TargetPopulationsPage = (): React.ReactElement => { if (!hasPermissions(PERMISSIONS.TARGETING_VIEW_LIST, permissions)) return ; - + if (!programData) return null; + let Table = TargetPopulationTable; + let Filters = TargetPopulationFilters; + if (programData.program.isSocialWorkerProgram) { + Table = TargetPopulationForPeopleTable; + Filters = TargetPopulationForPeopleFilters; + } return ( <> @@ -59,14 +72,14 @@ export const TargetPopulationsPage = (): React.ReactElement => { {canCreate && } - - { - const paymentModuleRoutes = [ - { - path: 'payment-module/new-plan', - element: , - }, + const { isSocialDctType } = useProgramContext(); + let children = []; + + if (isSocialDctType) { + children = [ + { + path: '', + element: , + }, + { + path: 'new-plan', + element: , + }, + { + path: 'followup-payment-plans/:id', + children: [ + { + path: '', + element: , + }, + { + path: 'edit', + element: , + }, + { + path: 'setup-fsp/edit', + element: , + }, + { + path: 'setup-fsp/create', + element: , + }, + ], + }, + { + path: 'payment-plans/:id', + children: [ + { + path: '', + element: , + }, + { + path: 'edit', + element: , + }, + { + path: 'setup-fsp/edit', + element: , + }, + { + path: 'setup-fsp/create', + element: , + }, + ], + }, + { + path: 'payments/:id', + element: , + }, + ]; + } else { + children = [ + { + path: '', + element: , + }, + { + path: 'new-plan', + element: , + }, + { + path: 'followup-payment-plans/:id', + children: [ + { + path: '', + element: , + }, + { + path: 'edit', + element: , + }, + { + path: 'setup-fsp/edit', + element: , + }, + { + path: 'setup-fsp/create', + element: , + }, + ], + }, + { + path: 'payment-plans/:id', + children: [ + { + path: '', + element: , + }, + { + path: 'edit', + element: , + }, + { + path: 'setup-fsp/edit', + element: , + }, + { + path: 'setup-fsp/create', + element: , + }, + ], + }, + { + path: 'payments/:id', + element: , + }, + ]; + } + + return useRoutes([ { path: 'payment-module', - element: , - }, - { - path: 'payment-module/followup-payment-plans/:id/edit', - element: , - }, - { - path: 'payment-module/followup-payment-plans/:id/setup-fsp/edit', - element: , - }, - { - path: 'payment-module/followup-payment-plans/:id/setup-fsp/create', - element: , - }, - { - path: 'payment-module/payment-plans/:id/setup-fsp/edit', - element: , + children, }, - { - path: 'payment-module/payment-plans/:id/edit', - element: , - }, - { - path: 'payment-module/payments/:id', - element: , - }, - { - path: 'payment-module/payment-plans/:id/setup-fsp/create', - element: , - }, - { - path: 'payment-module/payment-plans/:id', - element: , - }, - { - path: 'payment-module/followup-payment-plans/:id', - element: , - }, - ]; - - return useRoutes(paymentModuleRoutes); + ]); }; diff --git a/frontend/src/containers/routers/RegistrationRoutes.tsx b/frontend/src/containers/routers/RegistrationRoutes.tsx index a2caa0967c..32d63b4947 100644 --- a/frontend/src/containers/routers/RegistrationRoutes.tsx +++ b/frontend/src/containers/routers/RegistrationRoutes.tsx @@ -4,41 +4,56 @@ import { RegistrationDataImportDetailsPage } from '../pages/rdi/RegistrationData import { RegistrationDataImportPage } from '../pages/rdi/RegistrationDataImportPage'; import { RegistrationHouseholdDetailsPage } from '../pages/rdi/RegistrationHouseholdDetailsPage'; import { RegistrationIndividualDetailsPage } from '../pages/rdi/RegistrationIndividualDetailsPage'; -import { RegistrationPeopleDetailsPage } from '@containers/pages/rdi/people/RegistrationPeopleDetailsPage'; -import { - RegistrationDataImportForPeopleDetailsPage, -} from '@containers/pages/rdi/people/RegistrationDataImportForPeopleDetailsPage'; -import { RegistrationDataForPeopleImportPage } from '@containers/pages/rdi/people/RegistrationDataForPeopleImportPage'; +import { useProgramContext } from '../../programContext'; +import { PeopleRegistrationDataImportPage } from '@containers/pages/rdi/people/PeopleRegistrationDataImportPage'; +import { PeopleRegistrationDetailsPage } from '@containers/pages/rdi/people/PeopleRegistrationDetailsPage'; +import { PeopleRegistrationDataImportDetailsPage } from '@containers/pages/rdi/people/PeopleRegistrationDataImportDetailsPage'; export const RegistrationRoutes = (): React.ReactElement => { + const { isSocialDctType } = useProgramContext(); + + let children = []; + + if (isSocialDctType) { + children = [ + { + path: '', + element: , + }, + { + path: 'people/:id', + element: , + }, + { + path: ':id', + element: , + }, + ]; + } else { + children = [ + { + path: '', + element: , + }, + { + path: 'household/:id', + element: , + }, + { + path: 'individual/:id', + element: , + }, + { + path: ':id', + element: , + }, + ]; + } + const registrationRoutes = [ - { - path: 'registration-data-import/household/:id', - element: , - }, - { - path: 'registration-data-import/individual/:id', - element: , - }, - { - path: 'registration-data-import-for-people/people/:id', - element: , - }, - { - path: 'registration-data-import-for-people/:id', - element: , - }, - { - path: 'registration-data-import-for-people', - element: , - }, - { - path: 'registration-data-import/:id', - element: , - }, { path: 'registration-data-import', - element: , + children, }, ]; diff --git a/frontend/src/containers/tables/Communication/CommunicationTable/__snapshots__/CommunicationTable.test.tsx.snap b/frontend/src/containers/tables/Communication/CommunicationTable/__snapshots__/CommunicationTable.test.tsx.snap index 499fe17899..d890db0ec5 100644 --- a/frontend/src/containers/tables/Communication/CommunicationTable/__snapshots__/CommunicationTable.test.tsx.snap +++ b/frontend/src/containers/tables/Communication/CommunicationTable/__snapshots__/CommunicationTable.test.tsx.snap @@ -9,7 +9,7 @@ exports[`containers/tables//Communication/CommunicationTable should render loadi class="sc-fsYfdN iJWUfq" >
diff --git a/frontend/src/containers/tables/ProgrammesTable/ProgrammesHeadCells.tsx b/frontend/src/containers/tables/ProgrammesTable/ProgrammesHeadCells.tsx index f2d67837d0..d64076c10f 100644 --- a/frontend/src/containers/tables/ProgrammesTable/ProgrammesHeadCells.tsx +++ b/frontend/src/containers/tables/ProgrammesTable/ProgrammesHeadCells.tsx @@ -30,7 +30,7 @@ AllProgramsQuery['allPrograms']['edges'][number]['node'] }, { disablePadding: false, - label: 'Num. of Households', + label: 'Program Size', // disabled because number_of_households is not a field in the program model id: 'number_of_households', numeric: true, diff --git a/frontend/src/containers/tables/ProgrammesTable/__snapshots__/ProgrammesTable.test.tsx.snap b/frontend/src/containers/tables/ProgrammesTable/__snapshots__/ProgrammesTable.test.tsx.snap index 5d38693d0d..793ebb6572 100644 --- a/frontend/src/containers/tables/ProgrammesTable/__snapshots__/ProgrammesTable.test.tsx.snap +++ b/frontend/src/containers/tables/ProgrammesTable/__snapshots__/ProgrammesTable.test.tsx.snap @@ -9,7 +9,7 @@ exports[`containers/tables/ProgrammesTable should render loading 1`] = ` class="sc-fsYfdN iJWUfq" >
- Num. of Households + Program Size
- Num. of Households + Program Size
(); const initialVariables: AllPaymentsForTableQueryVariables = { businessArea, @@ -61,8 +61,8 @@ export function PaymentsTable({ )} isOnPaper={false} headCells={headCells} diff --git a/frontend/src/containers/tables/paymentmodule/PaymentsTable/PaymentsTableHeadCells.tsx b/frontend/src/containers/tables/paymentmodule/PaymentsTable/PaymentsTableHeadCells.tsx index 549a06db09..18ea482670 100644 --- a/frontend/src/containers/tables/paymentmodule/PaymentsTable/PaymentsTableHeadCells.tsx +++ b/frontend/src/containers/tables/paymentmodule/PaymentsTable/PaymentsTableHeadCells.tsx @@ -2,7 +2,7 @@ import { AllPaymentsForTableQuery } from '@generated/graphql'; import { HeadCell } from '@components/core/Table/EnhancedTableHead'; export const headCells: HeadCell< -AllPaymentsForTableQuery['allPayments']['edges'][number]['node'] + AllPaymentsForTableQuery['allPayments']['edges'][number]['node'] >[] = [ { disablePadding: false, @@ -12,13 +12,13 @@ AllPaymentsForTableQuery['allPayments']['edges'][number]['node'] }, { disablePadding: false, - label: 'Payment Id', + label: 'Payment ID', id: 'unicef_id', numeric: false, }, { disablePadding: false, - label: 'Household Id', + label: 'Household ID', id: 'household__unicef_id', numeric: false, }, diff --git a/frontend/src/containers/tables/paymentmodule/PaymentsTable/__snapshots__/PaymentsTable.test.tsx.snap b/frontend/src/containers/tables/paymentmodule/PaymentsTable/__snapshots__/PaymentsTable.test.tsx.snap index f9eac8ed53..871a2b57fd 100644 --- a/frontend/src/containers/tables/paymentmodule/PaymentsTable/__snapshots__/PaymentsTable.test.tsx.snap +++ b/frontend/src/containers/tables/paymentmodule/PaymentsTable/__snapshots__/PaymentsTable.test.tsx.snap @@ -73,7 +73,7 @@ exports[`containers/tables/paymentmodule/PaymentsTable should render loading 1`] role="button" tabindex="0" > - Payment Id + Payment ID } + /> + + + + { + if (e.target.checked) { + handleFilterChange('isFollowUp', true); + } else { + handleFilterChange('isFollowUp', false); + } + }} + /> + } + label={t('Show only Follow-up plans')} + /> + + + + + ); +}; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansHeadCells.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansHeadCells.tsx new file mode 100644 index 0000000000..573e86eaef --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansHeadCells.tsx @@ -0,0 +1,68 @@ +export const headCells = [ + { + disablePadding: false, + label: 'Payment Plan ID', + id: 'id', + numeric: false, + }, + { + disablePadding: false, + label: 'Status', + id: 'status', + numeric: false, + }, + { + disablePadding: false, + label: 'Target Population', + id: 'targetPopulation', + numeric: false, + }, + { + disablePadding: false, + label: 'Num. of People', + id: 'totalIndividualsCount', + numeric: false, + }, + { + disablePadding: false, + label: 'Currency', + id: 'currency', + numeric: false, + }, + { + disablePadding: false, + label: 'Total Entitled Quantity', + id: 'totalEntitledQuantity', + numeric: true, + }, + { + disablePadding: false, + label: 'Total Delivered Quantity', + id: 'totalDeliveredQuantity', + numeric: true, + }, + { + disablePadding: false, + label: 'Total Undelivered Quantity', + id: 'totalUndeliveredQuantity', + numeric: true, + }, + { + disablePadding: false, + label: 'Dispersion Start Date', + id: 'dispersionStartDate', + numeric: false, + }, + { + disablePadding: false, + label: 'Dispersion End Date', + id: 'dispersionEndDate', + numeric: false, + }, + { + disablePadding: false, + label: 'Follow-up Payment Plans', + id: 'followup-id', + numeric: false, + }, +]; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansTable.test.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansTable.test.tsx new file mode 100644 index 0000000000..23c61fe29a --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansTable.test.tsx @@ -0,0 +1,58 @@ +import { MockedProvider } from '@apollo/react-testing'; +import { act } from '@testing-library/react'; +import wait from 'waait'; +import { fakeApolloAllPaymentPlansForTable } from '../../../../../fixtures/payments/fakeApolloAllPaymentPlansForTable'; +import { render } from '../../../../testUtils/testUtils'; +import { PeoplePaymentPlansTable } from './PeoplePaymentPlansTable'; + +describe('containers/tables/payments/PeoplePaymentPlansTable', () => { + it('should render with data', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); + + it('should render loading', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansTable.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansTable.tsx new file mode 100644 index 0000000000..a1b9cff5e3 --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/PeoplePaymentPlansTable.tsx @@ -0,0 +1,53 @@ +import { ReactElement } from 'react'; +import { useTranslation } from 'react-i18next'; +import { + AllPaymentPlansForTableQueryVariables, + PaymentPlanNode, + useAllPaymentPlansForTableQuery, +} from '@generated/graphql'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { UniversalTable } from '../../UniversalTable'; +import { PeoplePaymentPlanTableRow } from './PeoplePaymentPlanTableRow'; +import { headCells } from './PeoplePaymentPlansHeadCells'; + +interface PeoplePaymentPlansTableProps { + filter; + canViewDetails: boolean; +} + +export const PeoplePaymentPlansTable = ({ + filter, + canViewDetails, +}: PeoplePaymentPlansTableProps): ReactElement => { + const { t } = useTranslation(); + const { programId, businessArea } = useBaseUrl(); + const initialVariables: AllPaymentPlansForTableQueryVariables = { + businessArea, + search: filter.search, + status: filter.status, + totalEntitledQuantityFrom: filter.totalEntitledQuantityFrom || null, + totalEntitledQuantityTo: filter.totalEntitledQuantityTo || null, + dispersionStartDate: filter.dispersionStartDate || null, + dispersionEndDate: filter.dispersionEndDate || null, + isFollowUp: filter.isFollowUp ? true : null, + program: programId, + }; + + return ( + + defaultOrderBy="-createdAt" + title={t('Payment Plans')} + headCells={headCells} + query={useAllPaymentPlansForTableQuery} + queriedObjectName="allPaymentPlans" + initialVariables={initialVariables} + renderRow={(row) => ( + + )} + /> + ); +}; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/__snapshots__/PeoplePaymentPlansTable.test.tsx.snap b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/__snapshots__/PeoplePaymentPlansTable.test.tsx.snap new file mode 100644 index 0000000000..b16386856e --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/__snapshots__/PeoplePaymentPlansTable.test.tsx.snap @@ -0,0 +1,957 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`containers/tables/payments/PeoplePaymentPlansTable should render loading 1`] = ` +
+
+
+
+
+
+
+ Payment Plans +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Payment Plan ID + + + + + Status + + + + + Target Population + + + + + Num. of People + + + + + Currency + + + + + Total Entitled Quantity + + + + + Total Delivered Quantity + + + + + Total Undelivered Quantity + + + + + Dispersion Start Date + + + + + Dispersion End Date + + + + + Follow-up Payment Plans + + +
+ +
+ +
+ +
+ +
+
+
+
+
+
+

+ Rows per page: +

+
+ + + +
+

+ 1–2 of 2 +

+
+ + +
+
+
+
+
+
+`; + +exports[`containers/tables/payments/PeoplePaymentPlansTable should render with data 1`] = ` +
+
+
+
+
+
+
+ Payment Plans +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Payment Plan ID + + + + + Status + + + + + Target Population + + + + + Num. of People + + + + + Currency + + + + + Total Entitled Quantity + + + + + Total Delivered Quantity + + + + + Total Undelivered Quantity + + + + + Dispersion Start Date + + + + + Dispersion End Date + + + + + Follow-up Payment Plans + + +
+ +
+ +
+ +
+ +
+
+
+
+
+
+

+ Rows per page: +

+
+ + + +
+

+ 1–2 of 2 +

+
+ + +
+
+
+
+
+
+`; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/index.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/index.tsx new file mode 100644 index 0000000000..6bd6609127 --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentPlansTable/index.tsx @@ -0,0 +1 @@ +export { PeoplePaymentPlansTable } from './PeoplePaymentPlansTable'; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTable.test.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTable.test.tsx new file mode 100644 index 0000000000..6ac7d5b327 --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTable.test.tsx @@ -0,0 +1,46 @@ +import { MockedProvider } from '@apollo/react-testing'; +import { act } from '@testing-library/react'; +import wait from 'waait'; +import { fakeApolloAllPaymentsForTable } from '../../../../../fixtures/payments/fakeApolloAllPaymentsForTable'; +import { fakeApolloAllPaymentPlansForTable } from '../../../../../fixtures/payments/fakeApolloAllPaymentPlansForTable'; +import { render } from '../../../../testUtils/testUtils'; +import { PaymentPlanQuery } from '@generated/graphql'; +import { PERMISSIONS } from '../../../../config/permissions'; +import { PeoplePaymentsTable } from './PeoplePaymentsTable'; + +const paymentPlan = fakeApolloAllPaymentPlansForTable[0].result.data + .allPaymentPlans.edges[0].node as PaymentPlanQuery['paymentPlan']; + +describe('containers/tables/paymentmodule/PeoplePaymentsTable', () => { + it('should render with data', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); + + it('should render loading', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTable.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTable.tsx new file mode 100644 index 0000000000..0b3fc44e56 --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTable.tsx @@ -0,0 +1,97 @@ +import { Box, Paper, Typography } from '@mui/material'; +import * as React from 'react'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { TableWrapper } from '@components/core/TableWrapper'; +import { ImportXlsxPaymentPlanPaymentListPerFsp } from '@components/paymentmodule/PaymentPlanDetails/ImportXlsxPaymentPlanPaymentListPerFsp'; +import { + AllPaymentsForTableQuery, + AllPaymentsForTableQueryVariables, + PaymentPlanQuery, + PaymentPlanStatus, + useAllPaymentsForTableQuery, +} from '@generated/graphql'; +import { UniversalTable } from '../../UniversalTable'; +import { PeoplePaymentsTableRow } from './PeoplePaymentsTableRow'; +import { WarningTooltipTable } from './WarningTooltipTable'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { headCells } from './PeoplePaymentsTableHeadCells'; + +const StyledBox = styled(Box)` + background-color: #fff; +`; +interface PeoplePaymentsTableProps { + businessArea: string; + paymentPlan: PaymentPlanQuery['paymentPlan']; + permissions: string[]; + canViewDetails?: boolean; +} + +export const PeoplePaymentsTable = ({ + businessArea, + paymentPlan, + permissions, + canViewDetails = false, +}: PeoplePaymentsTableProps): React.ReactElement => { + const { baseUrl } = useBaseUrl(); + const { t } = useTranslation(); + const [dialogPayment, setDialogPayment] = useState< + AllPaymentsForTableQuery['allPayments']['edges'][number]['node'] | null + >(); + const initialVariables: AllPaymentsForTableQueryVariables = { + businessArea, + paymentPlanId: paymentPlan.id, + }; + + return ( + <> + + + + + {t('Payee List')} + + {(paymentPlan.status === PaymentPlanStatus.Accepted || + paymentPlan.status === PaymentPlanStatus.Finished) && ( + + )} + + + isOnPaper={false} + headCells={headCells} + query={useAllPaymentsForTableQuery} + rowsPerPageOptions={[10, 25, 50]} + queriedObjectName="allPayments" + initialVariables={initialVariables} + defaultOrderBy="createdAt" + defaultOrderDirection="desc" + renderRow={(row) => ( + { + setDialogPayment(payment); + }} + /> + )} + /> + + + setDialogPayment(null)} + canViewDetails={canViewDetails} + baseUrl={baseUrl} + /> + + ); +}; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTableHeadCells.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTableHeadCells.tsx new file mode 100644 index 0000000000..78dfcdd88d --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTableHeadCells.tsx @@ -0,0 +1,63 @@ +import { AllPaymentsForTableQuery } from '@generated/graphql'; +import { HeadCell } from '@components/core/Table/EnhancedTableHead'; + +export const headCells: HeadCell< + AllPaymentsForTableQuery['allPayments']['edges'][number]['node'] +>[] = [ + { + disablePadding: false, + label: '', + id: 'flag', + numeric: false, + }, + { + disablePadding: false, + label: 'Payment ID', + id: 'unicef_id', + numeric: false, + }, + { + disablePadding: false, + label: 'Individual ID', + id: 'individual__unicef_id', + numeric: false, + disableSort: true, + }, + { + disablePadding: false, + label: 'Individual Name', + id: 'individual__full_name', + numeric: false, + disableSort: true, + }, + { + disablePadding: false, + label: 'Administrative Level 2', + id: 'household__admin2__name', + numeric: false, + }, + { + disablePadding: false, + label: 'FSP', + id: 'financial_service_provider__name', + numeric: false, + }, + { + disablePadding: false, + label: 'Entitlement', + id: 'entitlement_quantity_usd', + numeric: false, + }, + { + disablePadding: false, + label: 'Delivered Quantity', + id: 'delivered_quantity', + numeric: false, + }, + { + disablePadding: false, + label: 'Reconciliation', + id: 'mark', + numeric: false, + }, +]; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTableRow.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTableRow.tsx new file mode 100644 index 0000000000..70dbf723ad --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/PeoplePaymentsTableRow.tsx @@ -0,0 +1,177 @@ +import TableCell from '@mui/material/TableCell'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import CheckCircleOutlineRoundedIcon from '@mui/icons-material/CheckCircleOutlineRounded'; +import ErrorOutlineRoundedIcon from '@mui/icons-material/ErrorOutlineRounded'; +import { BlackLink } from '@components/core/BlackLink'; +import { ClickableTableRow } from '@components/core/Table/ClickableTableRow'; +import { WarningTooltip } from '@components/core/WarningTooltip'; +import { + formatCurrencyWithSymbol, + opacityToHex, + renderSomethingOrDash, +} from '@utils/utils'; +import { AllPaymentsForTableQuery, PaymentStatus } from '@generated/graphql'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +export const StyledLink = styled.div` + color: #000; + text-decoration: underline; + cursor: pointer; + display: flex; + align-content: center; +`; + +const RoutedBox = styled.div` + color: ${({ theme }) => theme.hctPalette.red}; + background-color: ${({ theme }) => + `${theme.hctPalette.red}${opacityToHex(0.15)}`}; + border-radius: 16px; + font-family: Roboto; + font-size: 10px; + font-weight: 500; + letter-spacing: 1.2px; + line-height: 16px; + padding: ${({ theme }) => theme.spacing(1)}; + text-align: center; + margin-right: 20px; +`; + +const OrangeError = styled(ErrorOutlineRoundedIcon)` + color: ${({ theme }) => theme.hctPalette.orange}; +`; + +const RedError = styled(ErrorOutlineRoundedIcon)` + color: ${({ theme }) => theme.hctPalette.red}; +`; + +const GreenCheck = styled(CheckCircleOutlineRoundedIcon)` + color: ${({ theme }) => theme.hctPalette.green}; +`; + +interface PeoplePaymentsTableRowProps { + payment: AllPaymentsForTableQuery['allPayments']['edges'][number]['node']; + canViewDetails: boolean; + onWarningClick?: ( + payment: AllPaymentsForTableQuery['allPayments']['edges'][number]['node'], + ) => void; +} + +export const PeoplePaymentsTableRow = ({ + payment, + canViewDetails, + onWarningClick, +}: PeoplePaymentsTableRowProps): React.ReactElement => { + const { t } = useTranslation(); + const { baseUrl } = useBaseUrl(); + const paymentDetailsPath = `/${baseUrl}/payment-module/payments/${payment.id}`; + + const handleDialogWarningOpen = ( + e: React.SyntheticEvent, + ): void => { + e.stopPropagation(); + onWarningClick(payment); + }; + + const renderDeliveredQuantity = (): React.ReactElement => { + const { deliveredQuantity, currency, deliveredQuantityUsd, status } = + payment; + if (status === PaymentStatus.TransactionErroneous) { + return UNSUCCESSFUL; + } + if (deliveredQuantity === null) { + return <>; + } + return ( + <> + {`${formatCurrencyWithSymbol(deliveredQuantity, currency)} + (${formatCurrencyWithSymbol(deliveredQuantityUsd, 'USD')})`} + + ); + }; + + const renderMark = (): React.ReactElement => { + const { deliveredQuantity, entitlementQuantity } = payment; + + if (deliveredQuantity === null) { + return <>; + } + if (deliveredQuantity === 0) { + return ; + } + if (deliveredQuantity === entitlementQuantity) { + return ; + } + return ; + }; + + const individual = payment?.household?.individuals?.edges?.[0]?.node; + const individualDetailsPath = `/${baseUrl}/population/individuals/${individual?.id}`; + + return ( + + + {(payment.paymentPlanHardConflicted || + payment.paymentPlanSoftConflicted) && ( + handleDialogWarningOpen(e)} + message={t( + 'This individual is also included in other Payment Plans. Click this icon to view details.', + )} + confirmed={payment.paymentPlanHardConflicted} + /> + )} + + + {canViewDetails ? ( + {payment.unicefId} + ) : ( + payment.unicefId + )} + + + {canViewDetails ? ( + + {individual?.unicefId} + + ) : ( + individual?.unicefId + )} + + + {canViewDetails ? ( + + {individual?.fullName} + + ) : ( + individual?.fullName + )} + + + {renderSomethingOrDash(payment.household.admin2?.name)} + + + + {payment.financialServiceProvider + ? payment.financialServiceProvider.name + : '-'} + + + {payment.entitlementQuantity != null && payment.entitlementQuantity >= 0 + ? `${formatCurrencyWithSymbol( + payment.entitlementQuantity, + payment.currency, + )} (${formatCurrencyWithSymbol( + payment.entitlementQuantityUsd, + 'USD', + )})` + : '-'} + + + {renderDeliveredQuantity()} + + {renderMark()} + + ); +}; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/WarningTooltipTable/WarningTooltipTable.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/WarningTooltipTable/WarningTooltipTable.tsx new file mode 100644 index 0000000000..070b51e7f1 --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/WarningTooltipTable/WarningTooltipTable.tsx @@ -0,0 +1,168 @@ +import { + Box, + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Grid, + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from '@mui/material'; +import * as React from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { BlackLink } from '@components/core/BlackLink'; +import { LabelizedField } from '@components/core/LabelizedField'; +import { StatusBox } from '@components/core/StatusBox'; +import { ClickableTableRow } from '@components/core/Table/ClickableTableRow'; +import { UniversalMoment } from '@components/core/UniversalMoment'; +import { paymentPlanStatusToColor } from '@utils/utils'; +import { + AllPaymentsForTableQuery, + PaymentConflictDataNode, + PaymentPlanQuery, +} from '@generated/graphql'; +import { DialogFooter } from '../../../../dialogs/DialogFooter'; +import { DialogTitleWrapper } from '../../../../dialogs/DialogTitleWrapper'; + +const StyledTable = styled(Table)` + min-width: 100px; +`; +const Bold = styled.div` + font-weight: bold; + padding: 0 5px; +`; + +const GreyBox = styled(Box)` + background-color: #f3f3f3; +`; + +interface WarningTooltipTableProps { + paymentPlan: PaymentPlanQuery['paymentPlan']; + payment: AllPaymentsForTableQuery['allPayments']['edges'][number]['node']; + setDialogOpen: (dialogOpen: boolean) => void; + baseUrl: string; + canViewDetails: boolean; +} + +export function WarningTooltipTable({ + paymentPlan, + payment, + setDialogOpen, + baseUrl, + canViewDetails = false, +}: WarningTooltipTableProps): React.ReactElement { + const { t } = useTranslation(); + if (!payment) return null; + const mappedPaymentPlanRows = (): React.ReactElement[] => { + const { + paymentPlanSoftConflicted, + paymentPlanHardConflicted, + paymentPlanHardConflictedData, + paymentPlanSoftConflictedData, + } = payment; + + const renderRow = (row: PaymentConflictDataNode): React.ReactElement => ( + + + {canViewDetails ? ( + + {row.paymentPlanUnicefId} + + ) : ( + row.paymentPlanUnicefId + )} + + + {row.paymentPlanStartDate} + + + {row.paymentPlanEndDate} + + + + + {row.paymentUnicefId} + + ); + + if (paymentPlanHardConflicted) { + return paymentPlanHardConflictedData.map((el) => renderRow(el)); + } + if (paymentPlanSoftConflicted) { + return paymentPlanSoftConflictedData.map((el) => renderRow(el)); + } + return []; + }; + + return ( + setDialogOpen(false)} + scroll="paper" + aria-labelledby="form-dialog-title" + maxWidth="md" + > + + {t('Warning')} + + + + {t('Payment Plan ID')} {paymentPlan.unicefId}{' '} + {t('details')}: + + + + + + {paymentPlan.startDate} + + + + + {paymentPlan.endDate} + + + + + + {t('Household ID')} {payment.household?.unicefId}{' '} + {t('is also included in the following Payment Plans')}: + + + + + {t('Payment Plan ID')} + {t('Start Date')} + {t('End Date')} + {t('Status')} + {t('Payment ID')} + + + {mappedPaymentPlanRows()} + + + + + + + + + ); +} diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/WarningTooltipTable/index.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/WarningTooltipTable/index.tsx new file mode 100644 index 0000000000..f4bfcdcdcb --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/WarningTooltipTable/index.tsx @@ -0,0 +1 @@ +export { WarningTooltipTable } from './WarningTooltipTable'; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/__snapshots__/PeoplePaymentsTable.test.tsx.snap b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/__snapshots__/PeoplePaymentsTable.test.tsx.snap new file mode 100644 index 0000000000..95c2658c85 --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/__snapshots__/PeoplePaymentsTable.test.tsx.snap @@ -0,0 +1,1119 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`containers/tables/paymentmodule/PeoplePaymentsTable should render loading 1`] = ` +
+
+
+
+
+ Payee List +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + Payment ID + + + + + Individual ID + + + + Individual Name + + + + Administrative Level 2 + + + + + FSP + + + + + Entitlement + + + + + Delivered Quantity + + + + + Reconciliation + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+
+

+ Rows per page: +

+
+ + + +
+

+ 1–2 of 2 +

+
+ + +
+
+
+
+
+
+
+`; + +exports[`containers/tables/paymentmodule/PeoplePaymentsTable should render with data 1`] = ` +
+
+
+
+
+ Payee List +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + Payment ID + + + + + Individual ID + + + + Individual Name + + + + Administrative Level 2 + + + + + FSP + + + + + Entitlement + + + + + Delivered Quantity + + + + + Reconciliation + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+
+

+ Rows per page: +

+
+ + + +
+

+ 1–2 of 2 +

+
+ + +
+
+
+
+
+
+
+`; diff --git a/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/index.tsx b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/index.tsx new file mode 100644 index 0000000000..f7d7aeb6cf --- /dev/null +++ b/frontend/src/containers/tables/paymentmodulePeople/PeoplePaymentsTable/index.tsx @@ -0,0 +1 @@ +export { PeoplePaymentsTable } from './PeoplePaymentsTable'; diff --git a/frontend/src/containers/tables/payments/CashPlanTable/__snapshots__/CashPlanTable.test.tsx.snap b/frontend/src/containers/tables/payments/CashPlanTable/__snapshots__/CashPlanTable.test.tsx.snap index 4eee1e9933..b7589e5b83 100644 --- a/frontend/src/containers/tables/payments/CashPlanTable/__snapshots__/CashPlanTable.test.tsx.snap +++ b/frontend/src/containers/tables/payments/CashPlanTable/__snapshots__/CashPlanTable.test.tsx.snap @@ -6,7 +6,7 @@ exports[`containers/tables/payments/CashPlanTable should render loading 1`] = ` class="sc-iBdnpw dcYiFg" >
{ + it('should render with data', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); + + it('should render loading', () => { + const { container } = render( + + + , + ); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTable.tsx b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTable.tsx new file mode 100644 index 0000000000..7786b06b03 --- /dev/null +++ b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTable.tsx @@ -0,0 +1,50 @@ +import { ReactElement } from 'react'; +import { useTranslation } from 'react-i18next'; +import { + AllPaymentRecordsAndPaymentsQueryVariables, + HouseholdNode, + PaymentRecordAndPaymentNode, + useAllPaymentRecordsAndPaymentsQuery, +} from '@generated/graphql'; +import { UniversalTable } from '../../UniversalTable'; +import { headCells } from './PaymentRecordAndPaymentPeopleTableHeadCells'; +import { PaymentRecordAndPaymentPeopleTableRow } from './PaymentRecordAndPaymentPeopleTableRow'; + +interface PaymentRecordHouseholdTableProps { + household?: HouseholdNode; + openInNewTab?: boolean; + businessArea: string; + canViewPaymentRecordDetails: boolean; +} +export function PaymentRecordAndPaymentPeopleTable({ + household, + openInNewTab = false, + businessArea, + canViewPaymentRecordDetails, +}: PaymentRecordHouseholdTableProps): ReactElement { + const { t } = useTranslation(); + const initialVariables = { + household: household?.id, + businessArea, + }; + return ( + + title={t('Payment Records')} + headCells={headCells} + query={useAllPaymentRecordsAndPaymentsQuery} + queriedObjectName="allPaymentRecordsAndPayments" + initialVariables={initialVariables} + renderRow={(row) => ( + + )} + /> + ); +} diff --git a/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTableHeadCells.tsx b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTableHeadCells.tsx new file mode 100644 index 0000000000..dda392e1de --- /dev/null +++ b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTableHeadCells.tsx @@ -0,0 +1,35 @@ +import { HeadCell } from '@components/core/Table/EnhancedTableHead'; +import { PaymentRecordAndPaymentNode } from '@generated/graphql'; + +export const headCells: HeadCell[] = [ + { + disablePadding: false, + label: 'Payment ID', + id: 'caId', + numeric: false, + }, + { + disablePadding: false, + label: 'Status', + id: 'status', + numeric: false, + }, + { + disablePadding: false, + label: 'Entitlement Quantity', + id: 'entitlement_quantity', + numeric: true, + }, + { + disablePadding: false, + label: 'Delivered Quantity', + id: 'delivered_quantity', + numeric: true, + }, + { + disablePadding: false, + label: 'Delivery Date', + id: 'delivery_date', + numeric: true, + }, +]; diff --git a/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTableRow.tsx b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTableRow.tsx new file mode 100644 index 0000000000..f31d3dff26 --- /dev/null +++ b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/PaymentRecordAndPaymentPeopleTableRow.tsx @@ -0,0 +1,80 @@ +import TableCell from '@mui/material/TableCell'; +import * as React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { PaymentRecordAndPaymentNode } from '@generated/graphql'; +import { ClickableTableRow } from '@components/core/Table/ClickableTableRow'; +import { StatusBox } from '@components/core/StatusBox'; +import { + formatCurrencyWithSymbol, + paymentRecordStatusToColor, + paymentStatusDisplayMap, +} from '@utils/utils'; +import { UniversalMoment } from '@components/core/UniversalMoment'; +import { BlackLink } from '@components/core/BlackLink'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +interface PaymentRecordAndPaymentPeopleTableRowrops { + paymentRecordOrPayment: PaymentRecordAndPaymentNode; + openInNewTab: boolean; + canViewDetails: boolean; +} + +export function PaymentRecordAndPaymentPeopleTableRow({ + paymentRecordOrPayment, + openInNewTab, + canViewDetails, +}: PaymentRecordAndPaymentPeopleTableRowrops): React.ReactElement { + const { baseUrl } = useBaseUrl(); + const navigate = useNavigate(); + const paymentRecordDetailsPath = `/${baseUrl}/payment-records/${paymentRecordOrPayment.id}`; + const paymentDetailsPath = `/${baseUrl}/payment-module/payments/${paymentRecordOrPayment.id}`; + const detailsPath = + paymentRecordOrPayment.objType === 'PaymentRecord' + ? paymentRecordDetailsPath + : paymentDetailsPath; + const handleClick = (): void => { + if (openInNewTab) { + window.open(detailsPath); + } else { + navigate(detailsPath); + } + }; + return ( + + + {canViewDetails ? ( + {paymentRecordOrPayment.caId} + ) : ( + paymentRecordOrPayment.caId + )} + + + + + + {formatCurrencyWithSymbol( + paymentRecordOrPayment.entitlementQuantity, + paymentRecordOrPayment.currency, + )} + + + {formatCurrencyWithSymbol( + paymentRecordOrPayment.deliveredQuantity, + paymentRecordOrPayment.currency, + )} + + + {paymentRecordOrPayment.deliveryDate} + + + ); +} diff --git a/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/__snapshots__/PaymentRecordAndPaymentPeopleTable.test.tsx.snap b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/__snapshots__/PaymentRecordAndPaymentPeopleTable.test.tsx.snap new file mode 100644 index 0000000000..72ec5d6cc7 --- /dev/null +++ b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/__snapshots__/PaymentRecordAndPaymentPeopleTable.test.tsx.snap @@ -0,0 +1,649 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`containers/tables/payments/PaymentRecordAndPaymentPeopleTable should render loading 1`] = ` +
+
+
+
+
+
+
+ Payment Records +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Payment ID + + + + + Status + + + + + Entitlement Quantity + + + + + Delivered Quantity + + + + + Delivery Date + + +
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+

+ Rows per page: +

+
+ + + +
+

+ 0–0 of 0 +

+
+ + +
+
+
+
+
+
+`; + +exports[`containers/tables/payments/PaymentRecordAndPaymentPeopleTable should render with data 1`] = ` +
+
+
+
+
+
+
+ Payment Records +
+
+
+
+ + + + + + + + + + + + + + + +
+ + Payment ID + + + + + Status + + + + + Entitlement Quantity + + + + + Delivered Quantity + + + + + Delivery Date + + +
+
+
+ +
+
+ No results +
+
+ Try adjusting your search or your filters to find what you are looking for. +
+
+
+
+
+
+
+

+ Rows per page: +

+
+ + + +
+

+ 0–0 of 0 +

+
+ + +
+
+
+
+
+
+`; diff --git a/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/index.ts b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/index.ts new file mode 100644 index 0000000000..4f6f1f3fbe --- /dev/null +++ b/frontend/src/containers/tables/payments/PaymentRecordAndPaymentPeopleTable/index.ts @@ -0,0 +1,3 @@ +import { PaymentRecordAndPaymentPeopleTable } from './PaymentRecordAndPaymentPeopleTable'; + +export { PaymentRecordAndPaymentPeopleTable }; diff --git a/frontend/src/containers/tables/payments/PaymentRecordTable/__snapshots__/PaymentRecordTable.test.tsx.snap b/frontend/src/containers/tables/payments/PaymentRecordTable/__snapshots__/PaymentRecordTable.test.tsx.snap index 3ae7fee8e5..ecd954e58e 100644 --- a/frontend/src/containers/tables/payments/PaymentRecordTable/__snapshots__/PaymentRecordTable.test.tsx.snap +++ b/frontend/src/containers/tables/payments/PaymentRecordTable/__snapshots__/PaymentRecordTable.test.tsx.snap @@ -6,7 +6,7 @@ exports[`containers/tables/payments/PaymentRecordTable should render loading 1`] class="sc-iBdnpw dcYiFg" >
[] = [ + { + disablePadding: false, + label: 'Payment ID', + id: 'payment_record__ca_id', + numeric: false, + }, + { + disablePadding: false, + label: 'Verification Channel', + id: 'payment_verification_plan__verification_channel', + numeric: false, + }, + { + disablePadding: false, + label: 'Verification Plan Id', + id: 'payment_verification_plan__unicef_id', + numeric: false, + }, + { + disablePadding: false, + label: 'Verification Status', + id: 'status', + numeric: false, + }, + { + disablePadding: false, + label: 'Individual (Full name)', + id: 'payment_record__head_of_household__family_name', + numeric: false, + }, + { + disablePadding: false, + label: 'Individual ID', + id: 'payment_record__household__head_of_household__unicef_id', + numeric: false, + }, + { + disablePadding: false, + label: 'Household Status', + id: 'payment_record__household__status', + numeric: false, + }, + { + disablePadding: false, + label: 'Delivered', + id: 'payment_record__delivered_quantity', + numeric: true, + }, + { + disablePadding: false, + label: 'Received', + id: 'received_amount', + numeric: true, + }, + { + disablePadding: false, + label: 'Phone #', + id: 'payment_record__head_of_household__phone_no', + numeric: false, + }, + { + disablePadding: false, + label: 'Alt. Phone #', + id: 'payment_record__head_of_household__phone_no_alternative', + numeric: false, + }, +]; diff --git a/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTable.tsx b/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTable.tsx new file mode 100644 index 0000000000..5abd7ff84b --- /dev/null +++ b/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTable.tsx @@ -0,0 +1,52 @@ +import { ReactElement } from 'react'; +import { useTranslation } from 'react-i18next'; +import { + AllPaymentVerificationsQueryVariables, + PaymentVerificationNode, + useAllPaymentVerificationsQuery, +} from '@generated/graphql'; +import { UniversalTable } from '../../../UniversalTable'; +import { headCells } from './PeopleVerificationRecordsHeadCells'; +import { PeopleVerificationRecordsTableRow } from '@containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTableRow'; + +interface PeopleVerificationRecordsTableProps { + paymentPlanId?: string; + filter; + canViewRecordDetails: boolean; + businessArea: string; +} + +export function PeopleVerificationRecordsTable({ + paymentPlanId, + filter, + canViewRecordDetails, + businessArea, +}: PeopleVerificationRecordsTableProps): ReactElement { + const { t } = useTranslation(); + + const initialVariables: AllPaymentVerificationsQueryVariables = { + ...filter, + businessArea, + paymentPlanId, + }; + + return ( + + title={t('Verification Records')} + headCells={headCells} + query={useAllPaymentVerificationsQuery} + queriedObjectName="allPaymentVerifications" + initialVariables={initialVariables} + renderRow={(paymentVerification) => ( + + )} + /> + ); +} diff --git a/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTableRow.tsx b/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTableRow.tsx new file mode 100644 index 0000000000..c15f8334cf --- /dev/null +++ b/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTableRow.tsx @@ -0,0 +1,91 @@ +import { TableRow } from '@mui/material'; +import TableCell from '@mui/material/TableCell'; +import * as React from 'react'; +import { BlackLink } from '@core/BlackLink'; +import { StatusBox } from '@core/StatusBox'; +import { AnonTableCell } from '@core/Table/AnonTableCell'; +import { + formatCurrencyWithSymbol, + householdStatusToColor, + verificationRecordsStatusToColor, +} from '@utils/utils'; +import { PaymentVerificationNode } from '@generated/graphql'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +interface VerificationRecordsTableRowProps { + paymentVerification: PaymentVerificationNode; + canViewRecordDetails: boolean; + showStatusColumn?: boolean; +} + +export function PeopleVerificationRecordsTableRow({ + paymentVerification, + canViewRecordDetails, + showStatusColumn = true, +}: VerificationRecordsTableRowProps): React.ReactElement { + const { baseUrl } = useBaseUrl(); + + const nodeType = atob(paymentVerification.payment.id).split(':')[0]; + const linkPath = `/${baseUrl}/verification/payment${ + nodeType === 'PaymentRecordNode' ? '-record' : '' + }/${paymentVerification.payment.id}`; + + return ( + + + {canViewRecordDetails ? ( + + {paymentVerification.payment?.unicefId} + + ) : ( + {paymentVerification.payment?.unicefId} + )} + + + {paymentVerification.paymentVerificationPlan.verificationChannel} + + + {paymentVerification.paymentVerificationPlan.unicefId} + + + + + + {paymentVerification.payment.household.headOfHousehold.fullName} + + + {paymentVerification.payment.household.headOfHousehold.unicefId} + + {showStatusColumn && ( + + + + )} + + {formatCurrencyWithSymbol( + paymentVerification.payment.deliveredQuantity, + paymentVerification.payment.currency, + )} + + + {formatCurrencyWithSymbol( + paymentVerification.receivedAmount, + paymentVerification.payment.currency, + )} + + + {paymentVerification.payment.household.headOfHousehold.phoneNo} + + + {paymentVerification.payment.household.headOfHousehold + .phoneNoAlternative || '-'} + + + ); +} diff --git a/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationsHeadCells.tsx b/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationsHeadCells.tsx new file mode 100644 index 0000000000..5a103be5a8 --- /dev/null +++ b/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationsHeadCells.tsx @@ -0,0 +1,65 @@ +import { HeadCell } from '@core/Table/EnhancedTableHead'; +import { PaymentVerificationNode } from '@generated/graphql'; + +export const headCells: HeadCell[] = [ + { + disablePadding: false, + label: 'Payment ID', + id: 'payment_record__ca_id', + numeric: false, + }, + { + disablePadding: false, + label: 'Verification Channel', + id: 'payment_verification_plan__verification_channel', + numeric: false, + }, + { + disablePadding: false, + label: 'Verification Plan Id', + id: 'payment_verification_plan__unicef_id', + numeric: false, + }, + { + disablePadding: false, + label: 'Verification Status', + id: 'status', + numeric: false, + }, + { + disablePadding: false, + label: 'Individual (Full name)', + id: 'payment_record__head_of_household__family_name', + numeric: false, + }, + { + disablePadding: false, + label: 'Individual ID', + id: 'payment_record__head_of_household__unicef_id', + numeric: false, + }, + { + disablePadding: false, + label: 'Delivered', + id: 'payment_record__delivered_quantity', + numeric: true, + }, + { + disablePadding: false, + label: 'Received', + id: 'received_amount', + numeric: true, + }, + { + disablePadding: false, + label: 'Phone #', + id: 'payment_record__head_of_household__phone_no', + numeric: false, + }, + { + disablePadding: false, + label: 'Alt. Phone #', + id: 'payment_record__head_of_household__phone_no_alternative', + numeric: false, + }, +]; diff --git a/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationsTable.tsx b/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationsTable.tsx new file mode 100644 index 0000000000..b395d0a587 --- /dev/null +++ b/frontend/src/containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationsTable.tsx @@ -0,0 +1,53 @@ +import { ReactElement } from 'react'; +import { useTranslation } from 'react-i18next'; +import { + AllPaymentVerificationsQueryVariables, + PaymentVerificationNode, + useAllPaymentVerificationsQuery, +} from '@generated/graphql'; +import { UniversalTable } from '../../../UniversalTable'; +import { headCells } from './PeopleVerificationsHeadCells'; +import { PeopleVerificationRecordsTableRow } from '@containers/tables/payments/VerificationRecordsTable/People/PeopleVerificationRecordsTableRow'; + +interface PeopleVerificationsTableProps { + paymentPlanId?: string; + filter; + canViewRecordDetails: boolean; + businessArea: string; +} + +export function PeopleVerificationsTable({ + paymentPlanId, + filter, + canViewRecordDetails, + businessArea, +}: PeopleVerificationsTableProps): ReactElement { + const { t } = useTranslation(); + + const initialVariables: AllPaymentVerificationsQueryVariables = { + ...filter, + businessArea, + paymentPlanId, + }; + + return ( + + title={t('Verification Records')} + headCells={headCells} + query={useAllPaymentVerificationsQuery} + queriedObjectName="allPaymentVerifications" + initialVariables={initialVariables} + renderRow={(paymentVerification) => ( + + )} + /> + ); +} diff --git a/frontend/src/containers/tables/payments/VerificationRecordsTable/VerificationRecordsTable.tsx b/frontend/src/containers/tables/payments/VerificationRecordsTable/VerificationRecordsTable.tsx index 98b8180923..ea2a842230 100644 --- a/frontend/src/containers/tables/payments/VerificationRecordsTable/VerificationRecordsTable.tsx +++ b/frontend/src/containers/tables/payments/VerificationRecordsTable/VerificationRecordsTable.tsx @@ -32,8 +32,8 @@ export function VerificationRecordsTable({ return ( title={t('Verification Records')} headCells={headCells} diff --git a/frontend/src/containers/tables/payments/VerificationRecordsTable/VerificationsTable.tsx b/frontend/src/containers/tables/payments/VerificationRecordsTable/VerificationsTable.tsx index 3d9269c167..a97a137d82 100644 --- a/frontend/src/containers/tables/payments/VerificationRecordsTable/VerificationsTable.tsx +++ b/frontend/src/containers/tables/payments/VerificationRecordsTable/VerificationsTable.tsx @@ -26,19 +26,14 @@ export function VerificationsTable({ const initialVariables: AllPaymentVerificationsQueryVariables = { ...filter, - // TODO: cleanup - // paymentVerificationPlan: filter.cashPlanPaymentVerification, - // search: filter.search, - // status: filter.status, - // verificationChannel: filter.verificationChannel, businessArea, paymentPlanId, }; return ( title={t('Verification Records')} headCells={headCells} diff --git a/frontend/src/containers/tables/payments/VerificationRecordsTable/__snapshots__/VerificationRecordsTable.test.tsx.snap b/frontend/src/containers/tables/payments/VerificationRecordsTable/__snapshots__/VerificationRecordsTable.test.tsx.snap index 7b92892143..14a3dd1029 100644 --- a/frontend/src/containers/tables/payments/VerificationRecordsTable/__snapshots__/VerificationRecordsTable.test.tsx.snap +++ b/frontend/src/containers/tables/payments/VerificationRecordsTable/__snapshots__/VerificationRecordsTable.test.tsx.snap @@ -6,7 +6,7 @@ exports[`containers/tables/payments/VerificationRecordsTable should render loadi class="sc-iBdnpw dcYiFg" >
{ businessArea="afghanistan" filter={initialFilter} canViewDetails - choicesData={fakeHouseholdChoices} /> , ); @@ -52,7 +50,6 @@ describe('containers/tables/population/PeopleListTable', () => { businessArea="afghanistan" filter={initialFilter} canViewDetails - choicesData={fakeHouseholdChoices} /> , ); diff --git a/frontend/src/containers/tables/people/PeopleListTable/PeopleListTable.tsx b/frontend/src/containers/tables/people/PeopleListTable/PeopleListTable.tsx index 4a24d46fe4..194b0a4f8f 100644 --- a/frontend/src/containers/tables/people/PeopleListTable/PeopleListTable.tsx +++ b/frontend/src/containers/tables/people/PeopleListTable/PeopleListTable.tsx @@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'; import { AllIndividualsForPopulationTableQueryVariables, AllIndividualsQueryVariables, - HouseholdChoiceDataQuery, IndividualNode, useAllIndividualsForPopulationTableQuery, } from '@generated/graphql'; @@ -18,14 +17,12 @@ interface PeopleListTableProps { filter; businessArea: string; canViewDetails: boolean; - choicesData: HouseholdChoiceDataQuery; } export function PeopleListTable({ businessArea, filter, canViewDetails, - choicesData, }: PeopleListTableProps): React.ReactElement { const { t } = useTranslation(); const { programId } = useBaseUrl(); diff --git a/frontend/src/containers/tables/people/PeopleListTable/PeopleListTableHeadCells.tsx b/frontend/src/containers/tables/people/PeopleListTable/PeopleListTableHeadCells.tsx index 4b772a94dc..5b372b6e97 100644 --- a/frontend/src/containers/tables/people/PeopleListTable/PeopleListTableHeadCells.tsx +++ b/frontend/src/containers/tables/people/PeopleListTable/PeopleListTableHeadCells.tsx @@ -23,6 +23,13 @@ export const headCells: HeadCell[] = [ numeric: false, dataCy: 'individual-name', }, + { + disablePadding: false, + label: 'Type', + id: '-birthDate', + numeric: true, + dataCy: 'individual-age', + }, { disablePadding: false, label: 'Age', diff --git a/frontend/src/containers/tables/people/PeopleListTable/PeopleListTableRow.tsx b/frontend/src/containers/tables/people/PeopleListTable/PeopleListTableRow.tsx index 6fc190221d..bb5ddcd16f 100644 --- a/frontend/src/containers/tables/people/PeopleListTable/PeopleListTableRow.tsx +++ b/frontend/src/containers/tables/people/PeopleListTable/PeopleListTableRow.tsx @@ -1,7 +1,8 @@ import TableCell from '@mui/material/TableCell'; import * as React from 'react'; import { useNavigate } from 'react-router-dom'; -import { IndividualNode } from '@generated/graphql'; +import { useTranslation } from 'react-i18next'; +import { IndividualNode, IndividualRelationship } from '@generated/graphql'; import { BlackLink } from '@components/core/BlackLink'; import { AnonTableCell } from '@components/core/Table/AnonTableCell'; import { ClickableTableRow } from '@components/core/Table/ClickableTableRow'; @@ -20,6 +21,7 @@ export const PeopleListTableRow = ({ }: IndividualsListTableRowProps): React.ReactElement => { const navigate = useNavigate(); const { baseUrl } = useBaseUrl(); + const { t } = useTranslation(); const individualDetailsPath = `/${baseUrl}/population/people/${individual.id}`; const handleClick = (): void => { @@ -41,6 +43,11 @@ export const PeopleListTableRow = ({ {individual.unicefId} {individual.fullName} + + {individual.relationship === IndividualRelationship.Head + ? t('Beneficiary') + : t('Non-beneficiary')} + {individual.age} {sexToCapitalize(individual.sex)} {individual.household?.admin2?.name} diff --git a/frontend/src/containers/tables/people/PeopleListTable/__snapshots__/PeopleListTable.test.tsx.snap b/frontend/src/containers/tables/people/PeopleListTable/__snapshots__/PeopleListTable.test.tsx.snap index 372267b604..1a7d544dde 100644 --- a/frontend/src/containers/tables/people/PeopleListTable/__snapshots__/PeopleListTable.test.tsx.snap +++ b/frontend/src/containers/tables/people/PeopleListTable/__snapshots__/PeopleListTable.test.tsx.snap @@ -9,7 +9,7 @@ exports[`containers/tables/population/PeopleListTable should render loading 1`] class="sc-fsYfdN iJWUfq" >
+ + + Type + +
{ - navigate(importDetailsForPeoplePath); + navigate(importDetailsForPeoplePath); }; const renderImportedBy = (): string => { if (registrationDataImport?.importedBy) { diff --git a/frontend/src/containers/tables/rdi/RegistrationDataImportForPeopleTable/__snapshots__/RegistrationDataImportForPeopleTable.test.tsx.snap b/frontend/src/containers/tables/rdi/RegistrationDataImportForPeopleTable/__snapshots__/RegistrationDataImportForPeopleTable.test.tsx.snap index c89bd3b873..8f2b67e0fc 100644 --- a/frontend/src/containers/tables/rdi/RegistrationDataImportForPeopleTable/__snapshots__/RegistrationDataImportForPeopleTable.test.tsx.snap +++ b/frontend/src/containers/tables/rdi/RegistrationDataImportForPeopleTable/__snapshots__/RegistrationDataImportForPeopleTable.test.tsx.snap @@ -9,7 +9,7 @@ exports[`containers/tables/rdi/RegistrationDataImportTable should render loading class="sc-fsYfdN iJWUfq" >
Test Import diff --git a/frontend/src/containers/tables/rdi/RegistrationDataImportTable/__snapshots__/RegistrationDataImportTable.test.tsx.snap b/frontend/src/containers/tables/rdi/RegistrationDataImportTable/__snapshots__/RegistrationDataImportTable.test.tsx.snap index 3a628e9434..032b777cc7 100644 --- a/frontend/src/containers/tables/rdi/RegistrationDataImportTable/__snapshots__/RegistrationDataImportTable.test.tsx.snap +++ b/frontend/src/containers/tables/rdi/RegistrationDataImportTable/__snapshots__/RegistrationDataImportTable.test.tsx.snap @@ -9,7 +9,7 @@ exports[`containers/tables/rdi/RegistrationDataImportTable should render loading class="sc-fsYfdN iJWUfq" >
{ + const initialFilter = { + name: '', + status: '', + totalHouseholdsCountMin: null, + totalHouseholdsCountMax: null, + createdAtRangeMin: '', + createdAtRangeMax: '', + }; + + it('should render with data', async () => { + const { container } = render( + + + , + ); + await act(() => wait(0)); // wait for response + + expect(container).toMatchSnapshot(); + }); + + it('should render loading', () => { + const { container } = render( + + + , + ); + + expect(container).toMatchSnapshot(); + }); +}); diff --git a/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTable.tsx b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTable.tsx new file mode 100644 index 0000000000..cc1b154c43 --- /dev/null +++ b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTable.tsx @@ -0,0 +1,88 @@ +import { ReactElement } from 'react'; +import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { + AllTargetPopulationsQueryVariables, + TargetPopulationNode, + useAllTargetPopulationsQuery, +} from '@generated/graphql'; +import { TableWrapper } from '@components/core/TableWrapper'; +import { useBaseUrl } from '@hooks/useBaseUrl'; +import { dateToIsoString } from '@utils/utils'; +import { UniversalTable } from '../../UniversalTable'; +import { headCells } from './TargetPopulationForPeopleTableHeadCells'; +import { TargetPopulationForPeopleTableRow } from './TargetPopulationForPeopleTableRow'; + +interface TargetPopulationProps { + filter; + canViewDetails: boolean; + enableRadioButton?: boolean; + selectedTargetPopulation?; + handleChange?; + noTableStyling?; + noTitle?; +} + +const NoTableStyling = styled.div` + .MuiPaper-elevation1 { + box-shadow: none; + padding: 0 !important; + } +`; + +export function TargetPopulationForPeopleTable({ + filter, + canViewDetails, + enableRadioButton, + selectedTargetPopulation, + handleChange, + noTableStyling, + noTitle, +}: TargetPopulationProps): ReactElement { + const { t } = useTranslation(); + const { businessArea, programId } = useBaseUrl(); + const initialVariables: AllTargetPopulationsQueryVariables = { + name: filter.name, + totalHouseholdsCountMin: filter.totalHouseholdsCountMin || null, + totalHouseholdsCountMax: filter.totalHouseholdsCountMax || null, + status: filter.status, + businessArea, + program: [programId], + createdAtRange: JSON.stringify({ + min: dateToIsoString(filter.createdAtRangeMin, 'startOfDay'), + max: dateToIsoString(filter.createdAtRangeMax, 'endOfDay'), + }), + }; + const handleRadioChange = (id: string): void => { + handleChange(id); + }; + + const renderTable = (): React.ReactElement => ( + + + title={noTitle ? null : t('Target Populations')} + headCells={enableRadioButton ? headCells : headCells.slice(1)} + rowsPerPageOptions={[10, 15, 20]} + query={useAllTargetPopulationsQuery} + queriedObjectName="allTargetPopulation" + defaultOrderBy="createdAt" + defaultOrderDirection="desc" + initialVariables={initialVariables} + renderRow={(row) => ( + + )} + /> + + ); + return noTableStyling ? ( + {renderTable()} + ) : ( + renderTable() + ); +} diff --git a/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTableHeadCells.tsx b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTableHeadCells.tsx new file mode 100644 index 0000000000..74241f621b --- /dev/null +++ b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTableHeadCells.tsx @@ -0,0 +1,54 @@ +import { HeadCell } from '@components/core/Table/EnhancedTableHead'; +import { TargetPopulationNode } from '@generated/graphql'; + +export const headCells: HeadCell[] = [ + { + disablePadding: false, + label: '', + id: 'radio', + numeric: false, + dataCy: 'radio-id', + }, + { + disablePadding: false, + label: 'Name', + id: 'name', + numeric: false, + dataCy: 'name', + }, + { + disablePadding: false, + label: 'Status', + id: 'status', + numeric: false, + dataCy: 'status', + }, + { + disablePadding: false, + label: 'Num. of People', + id: 'total_households_count', + numeric: false, + dataCy: 'num-of-households', + }, + { + disablePadding: false, + label: 'Date Created', + id: 'created_at', + numeric: false, + dataCy: 'date-created', + }, + { + disablePadding: false, + label: 'Last Edited', + id: 'updated_at', + numeric: false, + dataCy: 'last-edited', + }, + { + disablePadding: false, + label: 'Created by', + id: 'created_by', + numeric: false, + dataCy: 'created-by', + }, +]; diff --git a/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTableRow.tsx b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTableRow.tsx new file mode 100644 index 0000000000..dbd643f24b --- /dev/null +++ b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/TargetPopulationForPeopleTableRow.tsx @@ -0,0 +1,87 @@ +import TableCell from '@mui/material/TableCell'; +import * as React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { Radio } from '@mui/material'; +import { BlackLink } from '@components/core/BlackLink'; +import { StatusBox } from '@components/core/StatusBox'; +import { ClickableTableRow } from '@components/core/Table/ClickableTableRow'; +import { UniversalMoment } from '@components/core/UniversalMoment'; +import { targetPopulationStatusToColor } from '@utils/utils'; +import { TargetPopulationNode } from '@generated/graphql'; +import { useBaseUrl } from '@hooks/useBaseUrl'; + +interface TargetPopulationTableRowProps { + targetPopulation: TargetPopulationNode; + canViewDetails: boolean; + selectedTargetPopulation?; + radioChangeHandler?: (id: string) => void; +} + +export function TargetPopulationForPeopleTableRow({ + targetPopulation, + canViewDetails, + radioChangeHandler, + selectedTargetPopulation, +}: TargetPopulationTableRowProps): React.ReactElement { + const navigate = useNavigate(); + const { baseUrl } = useBaseUrl(); + const targetPopulationDetailsPath = `/${baseUrl}/target-population/${targetPopulation.id}`; + const handleClick = (): void => { + if (radioChangeHandler !== undefined) { + radioChangeHandler(targetPopulation.id); + } else { + navigate(targetPopulationDetailsPath); + } + }; + return ( + + {radioChangeHandler && ( + + { + radioChangeHandler(targetPopulation.id); + }} + value={targetPopulation.id} + name="radio-button-household" + inputProps={{ 'aria-label': targetPopulation.id }} + /> + + )} + + {canViewDetails ? ( + + {targetPopulation.name} + + ) : ( + targetPopulation.name + )} + + + + + + {targetPopulation.totalHouseholdsCount || '0'} + + + {targetPopulation.createdAt} + + + {targetPopulation.updatedAt} + + + {targetPopulation.createdBy?.firstName}{' '} + {targetPopulation.createdBy?.lastName} + + + ); +} diff --git a/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/__snapshots__/TargetPopulationForPeopleTable.test.tsx.snap b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/__snapshots__/TargetPopulationForPeopleTable.test.tsx.snap new file mode 100644 index 0000000000..fa52f8cf62 --- /dev/null +++ b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/__snapshots__/TargetPopulationForPeopleTable.test.tsx.snap @@ -0,0 +1,1118 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`containers/tables/targeting/TargetPopulation/TargetPopulationTable should render loading 1`] = ` +
+
+
+
+
+
+
+
+ Target Populations +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Name + + + + + Status + + + + + Num. of People + + + + + Date Created + + + + + Last Edited + + + + + Created by + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+

+ Rows per page: +

+
+ + + +
+

+ 0–0 of 0 +

+
+ + +
+
+
+
+
+
+
+`; + +exports[`containers/tables/targeting/TargetPopulation/TargetPopulationTable should render with data 1`] = ` +
+
+
+
+
+
+
+
+ Target Populations +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Name + + + + + Status + + + + + Num. of People + + + + + Date Created + + + + + Last Edited + + + + + Created by + + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+
+

+ Rows per page: +

+
+ + + +
+

+ 1–4 of 4 +

+
+ + +
+
+
+
+
+
+
+`; diff --git a/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/index.tsx b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/index.tsx new file mode 100644 index 0000000000..17f34f6460 --- /dev/null +++ b/frontend/src/containers/tables/targeting/TargetPopulationForPeopleTable/index.tsx @@ -0,0 +1,3 @@ +import { TargetPopulationForPeopleTable } from './TargetPopulationForPeopleTable'; + +export { TargetPopulationForPeopleTable }; diff --git a/frontend/src/containers/tables/targeting/TargetPopulationHouseholdTable/TargetPopulationHouseholdRow.tsx b/frontend/src/containers/tables/targeting/TargetPopulationHouseholdTable/TargetPopulationHouseholdRow.tsx index 8ba33d2896..bc71eab85f 100644 --- a/frontend/src/containers/tables/targeting/TargetPopulationHouseholdTable/TargetPopulationHouseholdRow.tsx +++ b/frontend/src/containers/tables/targeting/TargetPopulationHouseholdTable/TargetPopulationHouseholdRow.tsx @@ -29,6 +29,7 @@ export function TargetPopulationHouseholdTableRow({ hover onClick={canViewDetails ? handleClick : undefined} role="checkbox" + data-cy="target-population-household-row" key={household.id} > diff --git a/frontend/src/containers/tables/targeting/TargetPopulationPeopleTable/TargetPopulationPeopleRow.tsx b/frontend/src/containers/tables/targeting/TargetPopulationPeopleTable/TargetPopulationPeopleRow.tsx index a8b22d82d5..876a00c901 100644 --- a/frontend/src/containers/tables/targeting/TargetPopulationPeopleTable/TargetPopulationPeopleRow.tsx +++ b/frontend/src/containers/tables/targeting/TargetPopulationPeopleTable/TargetPopulationPeopleRow.tsx @@ -29,6 +29,7 @@ export function TargetPopulationPeopleTableRow({ hover onClick={canViewDetails ? handleClick : undefined} role="checkbox" + data-cy="target-population-people-row" key={household.id} > diff --git a/frontend/src/containers/tables/targeting/TargetPopulationTable/__snapshots__/TargetPopulationTable.test.tsx.snap b/frontend/src/containers/tables/targeting/TargetPopulationTable/__snapshots__/TargetPopulationTable.test.tsx.snap index a58f246254..9f7f08ed4d 100644 --- a/frontend/src/containers/tables/targeting/TargetPopulationTable/__snapshots__/TargetPopulationTable.test.tsx.snap +++ b/frontend/src/containers/tables/targeting/TargetPopulationTable/__snapshots__/TargetPopulationTable.test.tsx.snap @@ -9,7 +9,7 @@ exports[`containers/tables/targeting/TargetPopulation/TargetPopulationTable shou class="sc-fsYfdN iJWUfq" >
void; + isActiveProgram: boolean; + isSocialDctType: boolean; + isStandardDctType: boolean; +}; + export const ProgramContext = createContext(null); export function ProgramProvider({ @@ -54,5 +66,5 @@ export function ProgramProvider({ ); } -// eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export const useProgramContext = () => useContext(ProgramContext); +export const useProgramContext = (): ProgramContent => + useContext(ProgramContext); diff --git a/frontend/src/shared/Formik/FormikSelectField/FormikSelectField.tsx b/frontend/src/shared/Formik/FormikSelectField/FormikSelectField.tsx index b4fb0b0938..df289278b5 100644 --- a/frontend/src/shared/Formik/FormikSelectField/FormikSelectField.tsx +++ b/frontend/src/shared/Formik/FormikSelectField/FormikSelectField.tsx @@ -70,6 +70,23 @@ export function FormikSelectField({ id={`textField-${field.name}`} error={isInvalid} renderValue={(selected) => { + if (Array.isArray(selected)) { + return selected + .map((s) => { + const selectedItem = otherProps.choices.find( + (choice) => + choice.value === s || + choice.name === s || + choice.label === s, + ); + return selectedItem + ? selectedItem.labelEn || + selectedItem.name || + selectedItem.label + : s; + }) + .join(', '); + } const selectedItem = otherProps.choices.find( (choice) => choice.value === selected || choice.name === selected, ); @@ -108,7 +125,7 @@ export function FormikSelectField({ {each.description ? ( diff --git a/frontend/src/testUtils/testUtils.tsx b/frontend/src/testUtils/testUtils.tsx index 71a10f6efd..18d14756f5 100644 --- a/frontend/src/testUtils/testUtils.tsx +++ b/frontend/src/testUtils/testUtils.tsx @@ -59,7 +59,22 @@ export class ApolloLoadingLink extends MockLink { } export const fakeContextProgram = { - id: 1, - name: 'someName', - status: ProgramStatus.Active, + selectedProgram: { + id: '1', + name: 'someName', + status: ProgramStatus.Active, + dataCollectingType: { + id: '1', + householdFiltersAvailable: true, + individualFiltersAvailable: true, + label: 'data collecting type', + code: '123', + type: 'full', + children: null, + }, + }, + setSelectedProgram: () => {}, + isActiveProgram: true, + isSocialDctType: false, + isStandardDctType: true, }; diff --git a/frontend/src/utils/en.json b/frontend/src/utils/en.json index 6302512b9a..90f59a1dce 100644 --- a/frontend/src/utils/en.json +++ b/frontend/src/utils/en.json @@ -873,5 +873,6 @@ "Action completed successfully": "Action completed successfully", "Sent for Approval by": "Sent for Approval by", "Approved by": "Approved by", - "Authorized by": "Authorized by" + "Authorized by": "Authorized by", + "This individual is also included in other Payment Plans. Click this icon to view details.": "This individual is also included in other Payment Plans. Click this icon to view details." }