Skip to content

Commit

Permalink
Merge pull request #42 from openimis/main
Browse files Browse the repository at this point in the history
feat: Merge Main into mngoe
  • Loading branch information
kevel-dev authored May 23, 2024
2 parents 4c97695 + b9b1c1f commit 67c70bb
Show file tree
Hide file tree
Showing 19 changed files with 1,033 additions and 324 deletions.
66 changes: 30 additions & 36 deletions insuree/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,24 @@
"gql_mutation_create_insurees_perms": ["101102"],
"gql_mutation_update_insurees_perms": ["101103"],
"gql_mutation_delete_insurees_perms": ["101104"],
"insuree_photos_root_path": None,
"insuree_photos_root_path": os.path.abspath("./images/insurees"),
"excluded_insuree_chfids": ['999999999'], # fake insurees (and bound families) used, for example, in 'funding'
"renewal_photo_age_adult": 60, # age (in months) of a picture due for renewal for adults
"renewal_photo_age_child": 12, # age (in months) of a picture due for renewal for children
"insuree_number_validator": None, # Insuree number *function* that validates the insuree number
"insuree_number_validator": None, # Insuree number *function* that validates the insuree number for example
# 'msystems.utils.is_valid_resident_identifier'
"insuree_number_length": None, # Insuree number length to validate
"insuree_number_modulo_root": None, # modulo base for checksum on last digit, requires length to be set too
"validation_code_taken_insuree_number": 1,
"validation_code_no_insuree_number": 2,
"validation_code_invalid_insuree_number_len": 3,
"validation_code_invalid_insuree_number_checksum": 4,
"validation_code_invalid_insuree_number_exception": 5,
"validation_code_validator_import_error": 6,
"validation_code_validator_function_error": 7,
"insuree_fsp_mandatory": False,
"insuree_as_worker": False,

}


Expand All @@ -47,49 +58,32 @@ class InsureeConfig(AppConfig):
gql_mutation_create_insurees_perms = []
gql_mutation_update_insurees_perms = []
gql_mutation_delete_insurees_perms = []
validation_code_taken_insuree_number = 1
validation_code_no_insuree_number = 2
validation_code_invalid_insuree_number_len = 3
validation_code_invalid_insuree_number_checksum = 4
validation_code_invalid_insuree_number_exception = 5
validation_code_taken_insuree_number = None
validation_code_no_insuree_number = None
validation_code_invalid_insuree_number_len = None
validation_code_invalid_insuree_number_checksum = None
validation_code_invalid_insuree_number_exception = None
validation_code_validator_import_error = None
validation_code_validator_function_error = None
insuree_photos_root_path = None
excluded_insuree_chfids = ['999999999']
renewal_photo_age_adult = 60
renewal_photo_age_child = 12
excluded_insuree_chfids = []
renewal_photo_age_adult = None
renewal_photo_age_child = None
insuree_number_validator = None
insuree_number_length = None
insuree_number_modulo_root = None
insuree_fsp_mandatory = None
insuree_as_worker = None

def _configure_permissions(self, cfg):
InsureeConfig.gql_query_insurees_perms = cfg["gql_query_insurees_perms"]
InsureeConfig.gql_query_insuree_perms = cfg["gql_query_insuree_perms"]
InsureeConfig.gql_query_insuree_photo_perms = cfg["gql_query_insuree_photo_perms"]
InsureeConfig.gql_query_insuree_officers_perms = cfg["gql_query_insuree_officers_perms"]
InsureeConfig.gql_query_insuree_family_members = cfg["gql_query_insuree_family_members"]
InsureeConfig.gql_query_families_perms = cfg["gql_query_families_perms"]
InsureeConfig.gql_query_insuree_policy_perms = cfg["gql_query_insuree_policy_perms"]
InsureeConfig.gql_mutation_create_families_perms = cfg["gql_mutation_create_families_perms"]
InsureeConfig.gql_mutation_update_families_perms = cfg["gql_mutation_update_families_perms"]
InsureeConfig.gql_mutation_create_insurees_perms = cfg["gql_mutation_create_insurees_perms"]
InsureeConfig.gql_mutation_update_insurees_perms = cfg["gql_mutation_update_insurees_perms"]
InsureeConfig.gql_mutation_delete_insurees_perms = cfg["gql_mutation_delete_insurees_perms"]
InsureeConfig.insuree_number_validator = cfg["insuree_number_validator"]
InsureeConfig.insuree_number_length = cfg["insuree_number_length"]
InsureeConfig.insuree_number_modulo_root = cfg["insuree_number_modulo_root"]

def _configure_fake_insurees(self, cfg):
InsureeConfig.excluded_insuree_chfids = cfg["excluded_insuree_chfids"]

def _configure_renewal(self, cfg):
InsureeConfig.renewal_photo_age_adult = cfg["renewal_photo_age_adult"]
InsureeConfig.renewal_photo_age_child = cfg["renewal_photo_age_child"]
def __load_config(self, cfg):
for field in cfg:
if hasattr(InsureeConfig, field):
setattr(InsureeConfig, field, cfg[field])

def ready(self):
from core.models import ModuleConfiguration
cfg = ModuleConfiguration.get_or_default(MODULE_NAME, DEFAULT_CFG)
self._configure_permissions(cfg)
self._configure_fake_insurees(cfg)
self._configure_renewal(cfg)
self.__load_config(cfg)
self._configure_photo_root(cfg)

# Getting these at runtime for easier testing
Expand Down
72 changes: 35 additions & 37 deletions insuree/gql_mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import pathlib
import base64
import graphene
from insuree.apps import InsureeConfig
from insuree.services import validate_insuree_number, InsureeService, FamilyService, InsureePolicyService

from insuree.services import validate_insuree_number, InsureeService, FamilyService

from .apps import InsureeConfig
from core.schema import OpenIMISMutation
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ValidationError, PermissionDenied
Expand All @@ -33,7 +32,7 @@ class InsureeBase:
chf_id = graphene.String(max_length=12, required=False)
last_name = graphene.String(max_length=100, required=True)
other_names = graphene.String(max_length=100, required=True)
gender_id = graphene.String(max_length=1, required=True, description="Was mandatory in Legacy but not in modular")
gender_id = graphene.String(max_length=1, required=True)
dob = graphene.Date(required=True)
head = graphene.Boolean(required=False)
marital = graphene.String(max_length=1, required=False)
Expand All @@ -55,6 +54,9 @@ class InsureeBase:
health_facility_id = graphene.Int(required=False)
offline = graphene.Boolean(required=False)
json_ext = graphene.types.json.JSONString(required=False)
status = graphene.String(required=False)
status_reason = graphene.String(required=False)
status_date = graphene.Date(required=False)


class CreateInsureeInputType(InsureeBase, OpenIMISMutation.Input):
Expand Down Expand Up @@ -99,23 +101,6 @@ class UpdateFamilyInputType(FamilyInputType):
pass


def create_file(date, insuree_id, photo_bin):
date_iso = date.isoformat()
root = InsureeConfig.insuree_photos_root_path
file_dir = '%s/%s/%s/%s' % (
date_iso[0:4],
date_iso[5:7],
date_iso[8:10],
insuree_id
)
file_name = uuid.uuid4()
file_path = '%s/%s' % (file_dir, file_name)
pathlib.Path('%s/%s' % (root, file_dir)).mkdir(parents=True, exist_ok=True)
f = open('%s/%s' % (root, file_path), "xb")
f.write(base64.b64decode(photo_bin))
f.close()
return file_dir, file_name


def update_or_create_insuree(data, user):
data.pop('client_mutation_id', None)
Expand Down Expand Up @@ -152,7 +137,8 @@ def async_mutate(cls, user, **data):
data['validity_from'] = TimeUtils.now()
client_mutation_id = data.get("client_mutation_id")
family = update_or_create_family(data, user)
FamilyMutation.object_mutated(user, client_mutation_id=client_mutation_id, family=family)
FamilyMutation.object_mutated(
user, client_mutation_id=client_mutation_id, family=family)
return None
except Exception as exc:
logger.exception("insuree.mutation.failed_to_create_family")
Expand Down Expand Up @@ -183,7 +169,8 @@ def async_mutate(cls, user, **data):
data['audit_user_id'] = user.id_for_audit
client_mutation_id = data.get("client_mutation_id")
family = update_or_create_family(data, user)
FamilyMutation.object_mutated(user, client_mutation_id=client_mutation_id, family=family)
FamilyMutation.object_mutated(
user, client_mutation_id=client_mutation_id, family=family)
return None
except Exception as exc:
logger.exception("insuree.mutation.failed_to_update_family")
Expand Down Expand Up @@ -212,15 +199,16 @@ def async_mutate(cls, user, **data):
for family_uuid in data["uuids"]:
family = Family.objects \
.prefetch_related('members') \
.filter(uuid=family_uuid) \
.filter(uuid=(family_uuid)) \
.first()
if family is None:
errors.append({
'title': family_uuid,
'list': [{'message': _("insuree.mutation.failed_to_delete_family") % {'uuid': family_uuid}}]
})
continue
errors += FamilyService(user).set_deleted(family, data["delete_members"])
errors += FamilyService(user).set_deleted(family,
data["delete_members"])
if len(errors) == 1:
errors = errors[0]['list']
return errors
Expand Down Expand Up @@ -249,7 +237,8 @@ def async_mutate(cls, user, **data):
data['validity_from'] = TimeUtils.now()
client_mutation_id = data.get("client_mutation_id")
insuree = update_or_create_insuree(data, user)
InsureeMutation.object_mutated(user, client_mutation_id=client_mutation_id, insuree=insuree)
InsureeMutation.object_mutated(
user, client_mutation_id=client_mutation_id, insuree=insuree)
return None
except Exception as exc:
logger.exception("insuree.mutation.failed_to_create_insuree")
Expand Down Expand Up @@ -278,11 +267,13 @@ def async_mutate(cls, user, **data):
if not user.has_perms(InsureeConfig.gql_mutation_create_insurees_perms):
raise PermissionDenied(_("unauthorized"))
if 'uuid' not in data:
raise ValidationError("There is no uuid in updateMutation input!")
raise ValidationError(
"There is no uuid in updateMutation input!")
data['audit_user_id'] = user.id_for_audit
client_mutation_id = data.get("client_mutation_id")
insuree = update_or_create_insuree(data, user)
InsureeMutation.object_mutated(user, client_mutation_id=client_mutation_id, insuree=insuree)
InsureeMutation.object_mutated(
user, client_mutation_id=client_mutation_id, insuree=insuree)
return None
except Exception as exc:
logger.exception("insuree.mutation.failed_to_update_insuree")
Expand All @@ -300,7 +291,8 @@ class DeleteInsureesMutation(OpenIMISMutation):
_mutation_class = "DeleteInsureesMutation"

class Input(OpenIMISMutation.Input):
uuid = graphene.String(required=False) # family uuid, to 'lock' family while mutation is processed
# family uuid, to 'lock' family while mutation is processed
uuid = graphene.String(required=False)
uuids = graphene.List(graphene.String)

@classmethod
Expand All @@ -311,7 +303,7 @@ def async_mutate(cls, user, **data):
for insuree_uuid in data["uuids"]:
insuree = Insuree.objects \
.prefetch_related('family') \
.filter(uuid=insuree_uuid) \
.filter(uuid__iexact=insuree_uuid) \
.first()
if insuree is None:
errors.append({
Expand Down Expand Up @@ -353,7 +345,7 @@ def async_mutate(cls, user, **data):
for insuree_uuid in data["uuids"]:
insuree = Insuree.objects \
.prefetch_related('family') \
.filter(uuid=insuree_uuid) \
.filter(uuid=(insuree_uuid)) \
.first()
if insuree is None:
errors += {
Expand Down Expand Up @@ -394,8 +386,8 @@ def async_mutate(cls, user, **data):
if not user.has_perms(InsureeConfig.gql_mutation_update_families_perms):
raise PermissionDenied(_("unauthorized"))
try:
family = Family.objects.get(uuid=data['uuid'])
insuree = Insuree.objects.get(uuid=data['insuree_uuid'])
family = Family.objects.get(uuid=(data['uuid']))
insuree = Insuree.objects.get(uuid=(data['insuree_uuid']))
family.save_history()
prev_head = family.head_insuree
if prev_head:
Expand Down Expand Up @@ -434,16 +426,22 @@ def async_mutate(cls, user, **data):
not user.has_perms(InsureeConfig.gql_mutation_update_insurees_perms):
raise PermissionDenied(_("unauthorized"))
try:
family = Family.objects.get(uuid=data['family_uuid'])
insuree = Insuree.objects.get(uuid=data['insuree_uuid'])
family = Family.objects.get(uuid=(data['family_uuid']))
insuree = Insuree.objects.get(uuid=(data['insuree_uuid']))
insuree.save_history()
insuree.family = family
insuree.save()

if data['cancel_policies']:
return InsureeService(user).cancel_policies(insuree)
InsureeService(user).cancel_policies(insuree)

# Assign all the valid policies from the new family
InsureePolicyService(user).add_insuree_policy(insuree)

return None
except Exception as exc:
logger.exception("insuree.mutation.failed_to_change_insuree_family")
logger.exception(
"insuree.mutation.failed_to_change_insuree_family")
return [{
'message': _("insuree.mutation.failed_to_change_insuree_family"),
'detail': str(exc)}
Expand Down
21 changes: 17 additions & 4 deletions insuree/gql_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .apps import InsureeConfig
from .models import Insuree, InsureePhoto, Education, Profession, Gender, IdentificationType, \
Family, FamilyType, ConfirmationType, Relation, InsureePolicy, FamilyMutation, InsureeMutation
Family, FamilyType, ConfirmationType, Relation, InsureePolicy, FamilyMutation, InsureeMutation, InsureeStatusReason
from location.schema import LocationGQLType
from policy.gql_queries import PolicyGQLType
from core import prefix_filterset, filter_validity, ExtendedConnection
Expand Down Expand Up @@ -90,6 +90,18 @@ class Meta:
}


class InsureeStatusReasonGQLType(DjangoObjectType):
class Meta:
model = InsureeStatusReason
interfaces = (graphene.relay.Node,)
filter_fields = {
"code": ["exact"],
"insuree_status_reason": ["exact", 'icontains', 'istartswith'],
"status_type": ["exact"]
}
connection_class = ExtendedConnection


class InsureeGQLType(DjangoObjectType):
age = graphene.Int(source='age')
client_mutation_id = graphene.String()
Expand Down Expand Up @@ -128,7 +140,7 @@ def resolve_photo(self, info):
class Meta:
model = Insuree
filter_fields = {
"uuid": ["exact"],
"uuid": ["exact","iexact"],
"chf_id": ["exact", "istartswith", "icontains", "iexact"],
"last_name": ["exact", "istartswith", "icontains", "iexact"],
"other_names": ["exact", "istartswith", "icontains", "iexact"],
Expand All @@ -139,6 +151,7 @@ class Meta:
"passport": ["exact", "istartswith", "icontains", "iexact", "isnull"],
"gender__code": ["exact", "isnull"],
"marital": ["exact", "isnull"],
"status": ["exact"],
"validity_from": ["exact", "lt", "lte", "gt", "gte", "isnull"],
"validity_to": ["exact", "lt", "lte", "gt", "gte", "isnull"],
**prefix_filterset("photo__", PhotoGQLType._meta.filter_fields),
Expand Down Expand Up @@ -178,7 +191,7 @@ def resolve_head_insuree(self, info):
class Meta:
model = Family
filter_fields = {
"uuid": ["exact"],
"uuid": ["exact","iexact"],
"poverty": ["exact", "isnull"],
"confirmation_no": ["exact", "istartswith", "icontains", "iexact"],
"confirmation_type": ["exact"],
Expand All @@ -188,7 +201,7 @@ class Meta:
"is_offline": ["exact"],
**prefix_filterset("location__", LocationGQLType._meta.filter_fields),
**prefix_filterset("head_insuree__", InsureeGQLType._meta.filter_fields),
** prefix_filterset("members__", InsureeGQLType._meta.filter_fields)
**prefix_filterset("members__", InsureeGQLType._meta.filter_fields)
}
interfaces = (graphene.relay.Node,)
connection_class = ExtendedConnection
Expand Down
2 changes: 0 additions & 2 deletions insuree/management/commands/generateinsurees.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def handle(self, *args, **options):
last_name=fake.last_name(),
other_names=fake.first_name(),
dob=fake.date_between(start_date='-105y', end_date='today'),
chf_id=random.randrange(100000000, 999999999),
)
family_props = dict(
location_id=self.get_random_village(),
Expand All @@ -61,7 +60,6 @@ def handle(self, *args, **options):
props["other_names"] = fake.first_name()
props["dob"] = fake.date_between(start_date='-105y', end_date='today')
props["family_id"] = insuree.family_id
props["chf_id"] = random.randrange(100000000, 999999999)
member = create_test_insuree(with_family=False, custom_props=props)
if verbose:
print("Created family member", member_num, member.other_names)
Expand Down
24 changes: 24 additions & 0 deletions insuree/migrations/0016_alter_jsonext_column.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 3.2.18 on 2023-06-02 12:04
from django.conf import settings
from django.db import migrations


class Migration(migrations.Migration):

psql_code = 'select 1'

dependencies = [
('insuree', '0015_set_managed_to_true_in_all_models'),
]

operations = [
migrations.RunSQL('ALTER TABLE [tblInsuree] ALTER COLUMN [JsonExt] NVARCHAR(MAX)'
if settings.MSSQL else psql_code,
reverse_sql='ALTER TABLE [tblInsuree] ALTER COLUMN [JsonExt] TEXT'
if settings.MSSQL else psql_code),
migrations.RunSQL('ALTER TABLE [tblFamilies] ALTER COLUMN [JsonExt] NVARCHAR(MAX)'
if settings.MSSQL else psql_code,
reverse_sql='ALTER TABLE [tblFamilies] ALTER COLUMN [JsonExt] TEXT'
if settings.MSSQL else psql_code),
]

Loading

0 comments on commit 67c70bb

Please sign in to comment.