Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Master into stg #4534

Merged
merged 26 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5fb9b23
AB#226656 Error Cannot read properties of undefined Grievance ticket
johniak Dec 12, 2024
62c8f66
Merge pull request #4525 from unicef/hotfix/AB#226656-Error-Cannot-re…
johniak Dec 13, 2024
e9d623b
Fixes to managers for migretable models
johniak Dec 18, 2024
3b33179
added unicef id
johniak Dec 18, 2024
386b269
fix frontend lint
johniak Dec 18, 2024
2430469
Merge pull request #4528 from unicef/hotfix/use-good-household-manager
pkujawa Dec 18, 2024
10a927f
unique unicef_id constraint
pkujawa Dec 19, 2024
ef70802
fix test_double_entries
johniak Dec 19, 2024
c17c42b
fix household test_models
pkujawa Dec 19, 2024
e444871
change exclusion for importing hh and inds to another program
pkujawa Dec 19, 2024
40e76e7
fix test_create_pending_objects_from_objects
johniak Dec 19, 2024
7f7152d
Merge branch 'unique_program_unicef_id_in_program' of github.com:unic…
johniak Dec 19, 2024
86a6f03
fix linters
johniak Dec 19, 2024
a3af87c
fix test_create_targeting_for_people
johniak Dec 19, 2024
48c1627
add models for new constraints
pkujawa Dec 19, 2024
455ec74
fix test
pkujawa Dec 19, 2024
47ba8ae
remove one time scripts which are not valid with new contraint
johniak Dec 19, 2024
aa581a5
Merge branch 'unique_program_unicef_id_in_program' of github.com:unic…
johniak Dec 19, 2024
eba2c5e
fixed format
johniak Dec 19, 2024
805e792
change unique name
pkujawa Dec 19, 2024
807bfb0
fixed tests
johniak Dec 19, 2024
2b87e59
Merge branch 'unique_program_unicef_id_in_program' of github.com:unic…
johniak Dec 19, 2024
6221b0a
fix more tests
pkujawa Dec 19, 2024
3b5db8c
fix laast e2e tests
johniak Dec 19, 2024
f3ef838
Merge pull request #4529 from unicef/unique_program_unicef_id_in_program
johniak Dec 19, 2024
6588ec0
Merge branch 'master' into master_into_stg
pavlo-mk Dec 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ distribution = true

[project]
name = "hope"
version = "2.15.0"
version = "2.16.0"
description = "HCT MIS is UNICEF's humanitarian cash transfer platform."
authors = [
{ name = "Tivix" },
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "2.15.0",
"version": "2.16.0",
"private": true,
"type": "module",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export function LookUpReassignRole({
return (
<Formik
initialValues={{
selectedIndividual: individualData.individual,
selectedIndividual: individualData?.individual,
selectedHousehold,
role: individualRole.role,
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export function ReassignMultipleRoleBox({
(el) =>
el.role === IndividualRoleInHouseholdRole.Primary || el.role === 'HEAD',
);

const mappedReassignLookups = (): ReactElement => (
<>
{selectedIndividualsToReassign.map((selectedIndividualToReassign) => {
Expand Down Expand Up @@ -97,7 +96,7 @@ export function ReassignMultipleRoleBox({
ticket={ticket}
household={householdAndRole.household}
individualToReassign={selectedIndividualToReassign}
initialSelectedIndividualId={reassignDataDictByIndividualId[selectedIndividualToReassign.id].new_individual}
initialSelectedIndividualId={reassignDataDictByIndividualId[selectedIndividualToReassign.id]?.new_individual}
/>
</Box>
));
Expand Down Expand Up @@ -137,7 +136,7 @@ export function ReassignMultipleRoleBox({
ticket={ticket}
household={household}
individualToReassign={selectedIndividualToReassign}
initialSelectedIndividualId={reassignDataDictByIndividualId[selectedIndividualToReassign.id].new_individual}
initialSelectedIndividualId={reassignDataDictByIndividualId[selectedIndividualToReassign.id]?.new_individual}
/>
</Box>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export function ImportedHouseholdTableRow({
</TableCell>
<TableCell align="left">
<StyledLink onClick={() => handleClick()}>
{isMerged ? household.unicefId : household.importId}
{household.unicefId}
</StyledLink>
</TableCell>
<AnonTableCell>{household?.headOfHousehold?.fullName}</AnonTableCell>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ interface ImportedIndividualsTableRowProps {
export function ImportedIndividualsTableRow({
individual,
choices,
isMerged,
rdi,
}: ImportedIndividualsTableRowProps): ReactElement {
const navigate = useNavigate();
Expand Down Expand Up @@ -56,7 +55,7 @@ export function ImportedIndividualsTableRow({
>
<TableCell align="left">
<BlackLink to={individualDetailsPath}>
{isMerged ? individual.unicefId : individual.importId}
{individual.unicefId}
</BlackLink>
</TableCell>
<AnonTableCell>{individual.fullName}</AnonTableCell>
Expand Down
2 changes: 2 additions & 0 deletions src/hct_mis_api/api/endpoints/rdi/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class Meta:
"updated_at",
"version",
"vector_column",
"unicef_id",
]

def validate_role(self, value: str) -> Optional[str]:
Expand Down Expand Up @@ -175,6 +176,7 @@ class Meta:
"geopoint",
"detail_id",
"version",
"unicef_id",
]
validators = [HouseholdValidator()]

Expand Down
7 changes: 5 additions & 2 deletions src/hct_mis_api/apps/account/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,9 +378,12 @@ def check_node_permission(cls, info: Any, object_instance: Any) -> None:
raise PermissionDenied("Permission Denied")

@classmethod
def get_node(cls, info: Any, object_id: str) -> Optional[Model]:
def get_node(cls, info: Any, object_id: str, **kwargs: Any) -> Optional[Model]:
try:
object_instance = cls._meta.model.objects.get(pk=object_id)
if "get_object_queryset" in kwargs:
object_instance = kwargs.get("get_object_queryset").get(pk=object_id)
else:
object_instance = cls.get_queryset(cls._meta.model.objects, info).get(pk=object_id)
cls.check_node_permission(info, object_instance)
except cls._meta.model.DoesNotExist:
object_instance = None
Expand Down
21 changes: 21 additions & 0 deletions src/hct_mis_api/apps/household/migrations/0005_migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 3.2.25 on 2024-12-19 11:34

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('household', '0004_migration'),
]

operations = [
migrations.AddConstraint(
model_name='household',
constraint=models.UniqueConstraint(condition=models.Q(('is_removed', False)), fields=('unicef_id', 'program'), name='unique_hh_unicef_id_in_program'),
),
migrations.AddConstraint(
model_name='individual',
constraint=models.UniqueConstraint(condition=models.Q(('is_removed', False), ('duplicate', False)), fields=('unicef_id', 'program'), name='unique_ind_unicef_id_in_program'),
),
]
14 changes: 14 additions & 0 deletions src/hct_mis_api/apps/household/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,13 @@ class CollectType(models.TextChoices):
class Meta:
verbose_name = "Household"
permissions = (("can_withdrawn", "Can withdrawn Household"),)
constraints = [
UniqueConstraint(
fields=["unicef_id", "program"],
condition=Q(is_removed=False),
name="unique_hh_unicef_id_in_program",
)
]

def save(self, *args: Any, **kwargs: Any) -> None:
from hct_mis_api.apps.targeting.models import (
Expand Down Expand Up @@ -1187,6 +1194,13 @@ def __str__(self) -> str:
class Meta:
verbose_name = "Individual"
indexes = (GinIndex(fields=["vector_column"]),)
constraints = [
UniqueConstraint(
fields=["unicef_id", "program"],
condition=Q(is_removed=False) & Q(duplicate=False),
name="unique_ind_unicef_id_in_program",
)
]

def recalculate_data(self, save: bool = True) -> Tuple[Any, List[str]]:
update_fields = ["disability"]
Expand Down
32 changes: 21 additions & 11 deletions src/hct_mis_api/apps/household/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
Case,
F,
Func,
Model,
OuterRef,
Prefetch,
Q,
Expand Down Expand Up @@ -264,13 +265,17 @@ class IndividualNode(BaseNodePermissionMixin, AdminUrlNodeMixin, DjangoObjectTyp
IndividualIdentityNode,
)

@classmethod
def get_node(cls, info: Any, object_id: str, **kwargs: Any) -> Optional[Model]:
return super().get_node(info, object_id, get_object_queryset=Individual.all_merge_status_objects)

@staticmethod
def resolve_documents(parent: Individual, info: Any) -> QuerySet[Document]:
return Document.objects.filter(pk__in=parent.documents.values("id"))
return parent.documents(manager="all_merge_status_objects")

@staticmethod
def resolve_identities(parent: Individual, info: Any) -> QuerySet[IndividualIdentity]:
return IndividualIdentity.objects.filter(pk__in=parent.identities.values("id"))
return parent.identities(manager="all_merge_status_objects")

@staticmethod
def resolve_import_id(parent: Individual, info: Any) -> str:
Expand All @@ -282,16 +287,16 @@ def resolve_preferred_language(parent: Individual, info: Any) -> Optional[str]:

@staticmethod
def resolve_payment_channels(parent: Individual, info: Any) -> QuerySet[BankAccountInfo]:
return BankAccountInfo.objects.filter(individual=parent).annotate(type=Value("BANK_TRANSFER"))
return BankAccountInfo.all_merge_status_objects.filter(individual=parent).annotate(type=Value("BANK_TRANSFER"))

def resolve_bank_account_info(parent, info: Any) -> Optional[BankAccountInfo]:
bank_account_info = parent.bank_account_info.first()
bank_account_info = parent.bank_account_info(manager="all_merge_status_objects").first() # type: ignore
if bank_account_info:
return bank_account_info
return None

def resolve_role(parent, info: Any) -> str:
role = parent.households_and_roles.first()
role = parent.households_and_roles(manager="all_merge_status_objects").first()
if role is not None:
return role.role
return ROLE_NO_ROLE
Expand Down Expand Up @@ -481,13 +486,14 @@ def resolve_selection(parent: Household, info: Any) -> HouseholdSelection:

@staticmethod
def resolve_individuals(parent: Household, info: Any, *arg: Any, **kwargs: Any) -> QuerySet:
individuals_ids = list(parent.individuals.values_list("id", flat=True))
collectors_ids = list(parent.representatives.values_list("id", flat=True))
individuals_ids = list(parent.individuals(manager="all_merge_status_objects").values_list("id", flat=True))

collectors_ids = list(parent.representatives(manager="all_merge_status_objects").values_list("id", flat=True))
ids = list(set(individuals_ids + collectors_ids))
return Individual.objects.filter(id__in=ids).prefetch_related(
return Individual.all_merge_status_objects.filter(id__in=ids).prefetch_related(
Prefetch(
"households_and_roles",
queryset=IndividualRoleInHousehold.objects.filter(household=parent.id),
queryset=IndividualRoleInHousehold.all_merge_status_objects.filter(household=parent.id),
)
)

Expand Down Expand Up @@ -578,6 +584,10 @@ def get_queryset(cls, queryset: QuerySet[Household], info: Any) -> QuerySet[Hous
qs = super().get_queryset(queryset, info)
return qs

@classmethod
def get_node(cls, info: Any, object_id: str, **kwargs: Any) -> Optional[Model]:
return super().get_node(info, object_id, get_object_queryset=Household.all_merge_status_objects)

class Meta:
model = Household
filter_fields = []
Expand Down Expand Up @@ -706,7 +716,7 @@ def resolve_all_individuals(self, info: Any, **kwargs: Any) -> QuerySet[Individu
if program and program.status == Program.DRAFT:
return Individual.objects.none()

queryset = Individual.objects.all()
queryset = Individual.all_merge_status_objects.all()
if does_path_exist_in_query("edges.node.household", info):
queryset = queryset.select_related("household")
if does_path_exist_in_query("edges.node.household.admin2", info):
Expand Down Expand Up @@ -762,7 +772,7 @@ def resolve_all_households(self, info: Any, **kwargs: Any) -> QuerySet:
if program and program.status == Program.DRAFT:
return Household.objects.none()

queryset = Household.objects.all()
queryset = Household.all_merge_status_objects.all()

if not user.partner.is_unicef: # Unicef partner has full access to all AdminAreas
business_area_id = BusinessArea.objects.get(slug=business_area_slug).id
Expand Down
10 changes: 8 additions & 2 deletions src/hct_mis_api/apps/registration_datahub/mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,21 @@ def create_registration_data_import_for_import_program_population(
pull_pictures = registration_data_import_data.pop("pull_pictures", True)
screen_beneficiary = registration_data_import_data.pop("screen_beneficiary", False)
import_from_program_id = registration_data_import_data.pop("import_from_program_id", None)
households_to_exclude = Household.all_merge_status_objects.filter(
program=import_to_program_id,
).values_list("unicef_id", flat=True)
households = Household.objects.filter(
program_id=import_from_program_id,
withdrawn=False,
).exclude(household_collection__households__program=import_to_program_id)
).exclude(unicef_id__in=households_to_exclude)
individuals_to_exclude = Individual.all_merge_status_objects.filter(
program=import_to_program_id,
).values_list("unicef_id", flat=True)
individuals = Individual.objects.filter(
program_id=import_from_program_id,
withdrawn=False,
duplicate=False,
).exclude(individual_collection__individuals__program=import_to_program_id)
).exclude(unicef_id__in=individuals_to_exclude)
created_obj_hct = RegistrationDataImport(
status=RegistrationDataImport.IMPORTING,
imported_by=user,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@
def import_program_population(
import_from_program_id: str, import_to_program_id: str, rdi: RegistrationDataImport
) -> None:
households_to_exclude = Household.all_merge_status_objects.filter(
program=import_to_program_id,
).values_list("unicef_id", flat=True)
copy_from_households = Household.objects.filter(
program=import_from_program_id,
withdrawn=False,
).exclude(household_collection__households__program_id=import_to_program_id)
).exclude(unicef_id__in=households_to_exclude)
individuals_to_exclude = Individual.all_merge_status_objects.filter(
program=import_to_program_id,
).values_list("unicef_id", flat=True)
copy_from_individuals = (
Individual.objects.filter(
program_id=import_from_program_id,
withdrawn=False,
duplicate=False,
)
.exclude(individual_collection__individuals__program_id=import_to_program_id)
.exclude(unicef_id__in=individuals_to_exclude)
.order_by("first_registration_date")
)
import_to_program = Program.objects.get(id=import_to_program_id)
Expand Down
4 changes: 1 addition & 3 deletions src/hct_mis_api/apps/utils/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ class SoftDeletableRepresentationMergeStatusModel(MergeStatusModel):
class Meta:
abstract = True

# objects = SoftDeletableRepresentationMergedManager(_emit_deprecation_warnings=True)
# now we use 'rdi_merge_status' field for filtering
objects = SoftDeletableRepresentationManager()
objects = SoftDeletableRepresentationMergedManager(_emit_deprecation_warnings=True)
all_merge_status_objects = SoftDeletableRepresentationManager()
available_objects = SoftDeletableRepresentationMergedManager()
all_objects = models.Manager()
Expand Down

This file was deleted.

This file was deleted.

Loading
Loading