Skip to content

Commit

Permalink
harmonize submit
Browse files Browse the repository at this point in the history
  • Loading branch information
delcroip committed Aug 20, 2024
1 parent 9400532 commit 4dd996f
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 83 deletions.
26 changes: 13 additions & 13 deletions claim/gql_mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@

from claim.utils import process_items_relations, process_services_relations
from claim.services import validate_claim_data as service_validate_claim_data, \
update_or_create_claim as service_update_or_create_claim, check_unique_claim_code, submit_claim,\
validate_and_process_dedrem_claim as service_validate_and_process_dedrem_claim,\
update_or_create_claim as service_update_or_create_claim, check_unique_claim_code, ClaimSubmitService,\
processing_claim as service_processing_claim,\
create_feedback_prompt as service_create_feedback_prompt, update_claims_dedrems,\
set_feedback_prompt_validity_to_to_current_date, set_claims_status
from django.db import transaction
Expand Down Expand Up @@ -596,20 +596,23 @@ def async_mutate(cls, user, **data):
errors = []
uuids = data.get("uuids", [])
client_mutation_id = data.get("client_mutation_id", None)
service = ClaimSubmitService(user)
c_errors = []
claims = Claim.objects \
.filter(uuid__in=uuids,
validity_to__isnull=True) \
claims = Claim.objects.filter(uuid__in=uuids,
validity_to__isnull=True) \
.prefetch_related(Prefetch('items', queryset=ClaimItem.objects.filter(
*filter_validity(),
Q(Q(rejection_reason=0) | Q(rejection_reason__isnull=True))))) \
.prefetch_related(Prefetch('services', queryset=ClaimService.objects.filter(
*filter_validity(),
Q(Q(rejection_reason=0) | Q(rejection_reason__isnull=True)))))
remaining_uuid = list(map(str.upper,uuids))

for claim in claims:
remaining_uuid.remove(claim.uuid.upper())
c_errors += submit_claim(claim, user)
subm_claim, error = service.submit_claim(claim, user)
if error:
c_errors += error
if c_errors:
errors.append({
'title': claim.code,
Expand Down Expand Up @@ -935,22 +938,19 @@ def async_mutate(cls, user, **data):
remaining_uuid = list(map(str.upper,uuids))
for claim in claims:
remaining_uuid.remove(claim.uuid.upper())


logger.debug("ProcessClaimsMutation: processing %s", claim.uuid)
c_errors = []

claim.save_history()
claim.audit_user_id_process = user.id_for_audit
logger.debug("ProcessClaimsMutation: validating claim %s", claim.uuid)
c_errors += validate_and_process_dedrem_claim(claim, user, True)

c_errors += processing_claim(claim, user, True)
logger.debug("ProcessClaimsMutation: claim %s set processed or valuated", claim.uuid)
if c_errors:
errors.append({
'title': claim.code,
'list': c_errors
})
claim.save()

if len(remaining_uuid):
errors += {
Expand Down Expand Up @@ -1018,5 +1018,5 @@ def set_claim_deleted(claim):



def validate_and_process_dedrem_claim(claim, user, is_process):
return service_validate_and_process_dedrem_claim(claim, user, is_process)
def processing_claim(claim, user, is_process):
return service_processing_claim(claim, user, is_process)
10 changes: 9 additions & 1 deletion claim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ class Claim(core_models.VersionedModel, core_models.ExtendableModel):
db_column='AuditUserIDProcess', blank=True, null=True)
care_type = models.CharField(db_column='CareType', max_length=4, blank=True, null=True)

# row_id = models.BinaryField(db_column='RowID', blank=True, null=True)


class Meta:
managed = True
Expand Down Expand Up @@ -383,6 +383,7 @@ class ClaimDetail:

objects = ClaimDetailManager()


@property
def itemsvc(self):
if hasattr(self, "item"):
Expand All @@ -392,6 +393,13 @@ def itemsvc(self):
else:
raise Exception("ClaimDetail has neither item nor service")


def get_value(self):
if self.status != self.STATUS_REJECTED and not self.rejection_reason:
qty = self.qty_approved or self.qty_provided or 0
price = self.price_approved or self.price_adjusted or self.price_asked or 0
return qty * price

class Meta:
abstract = True

Expand Down
61 changes: 22 additions & 39 deletions claim/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def submit(self, claim_submit):
def enter_and_submit(self, claim: dict, rule_engine_validation: bool = True) -> Claim:
create_claim_service = ClaimCreateService(self.user)
entered_claim = create_claim_service.enter_claim(claim)
submitted_claim = self.submit_claim(entered_claim, rule_engine_validation)
submitted_claim, errors = self.submit_claim(entered_claim, rule_engine_validation)
return submitted_claim

@register_service_signal('claim.submit_claim')
Expand All @@ -219,13 +219,11 @@ def submit_claim(self, claim: Claim, rule_engine_validation=True):
self._validate_submit_permissions()
self._validate_user_hf(claim.health_facility.code)
claim.save_history()
validation_errors = processing_claim(claim, self.user, False, rule_engine_validation)
if validation_errors:
return self.__submit_to_rejected(claim), validation_errors

if rule_engine_validation:
validation_errors = self._validate_claim(claim)
if validation_errors:
return self.__submit_to_rejected(claim)

return self.__submit_to_checked(claim)
return self.__submit_to_checked(claim), []

def _validate_submit_permissions(self):
if type(self.user) is AnonymousUser or not self.user.id:
Expand All @@ -240,12 +238,6 @@ def _validate_user_hf(self, hf_code):
if not hf and settings.ROW_SECURITY:
raise ClaimSubmitError("Invalid health facility code or health facility not allowed for user")

def _validate_claim(self, claim):
errors = validate_claim(claim, True)
if not errors:
errors = validate_assign_prod_to_claimitems_and_services(claim)
errors += process_dedrem(claim, self.user.id_for_audit, False)
return errors or []

def __submit_to_rejected(self, claim: Claim):
claim.status = Claim.STATUS_REJECTED
Expand Down Expand Up @@ -541,22 +533,6 @@ def validate_number_of_additional_diagnoses(incoming_data):
return additional_diagnoses_count <= ClaimConfig.additional_diagnosis_number_allowed


def submit_claim(claim, user):
c_errors = []
claim.save_history()
logger.debug("SubmitClaimsMutation: validating claim %s", claim.uuid)
c_errors += validate_claim(claim, True)
logger.debug("SubmitClaimsMutation: claim %s validated, nb of errors: %s", claim.uuid, len(c_errors))
if len(c_errors) == 0:
c_errors = validate_assign_prod_to_claimitems_and_services(claim)
logger.debug("SubmitClaimsMutation: claim %s assigned, nb of errors: %s", claim.uuid, len(c_errors))
c_errors += process_dedrem(claim, user.id_for_audit, False)
logger.debug("SubmitClaimsMutation: claim %s processed for dedrem, nb of errors: %s", claim.uuid,
len(c_errors))
c_errors += set_claim_submitted(claim, c_errors, user)
logger.debug("SubmitClaimsMutation: claim %s set submitted", claim.uuid)
return c_errors


def set_claim_submitted(claim, errors, user):
try:
Expand All @@ -580,16 +556,19 @@ def set_claim_submitted(claim, errors, user):
}


def validate_and_process_dedrem_claim(claim, user, is_process):
errors = validate_claim(claim, False)
logger.debug("ProcessClaimsMutation: claim %s validated, nb of errors: %s", claim.uuid, len(errors))
if len(errors) == 0:
errors = validate_assign_prod_to_claimitems_and_services(claim)
logger.debug("ProcessClaimsMutation: claim %s assigned, nb of errors: %s", claim.uuid, len(errors))
def processing_claim(claim, user, is_process=False, validate=True):
errors = []
if validate and claim.status != Claim.STATUS_CHECKED:
errors = validate_claim(claim, False)
logger.debug("ProcessClaimsMutation: claim %s validated, nb of errors: %s", claim.uuid, len(errors))
if len(errors) == 0:
errors = validate_assign_prod_to_claimitems_and_services(claim)
logger.debug("ProcessClaimsMutation: claim %s assigned, nb of errors: %s", claim.uuid, len(errors))
if len(errors) == 0:
errors += process_dedrem(claim, user.id_for_audit, is_process)
logger.debug("ProcessClaimsMutation: claim %s processed for dedrem, nb of errors: %s", claim.uuid,
len(errors))
else:
len(errors))
if len(errors) > 0:
# OMT-208 the claim is invalid. If there is a dedrem, we need to clear it (caused by a review)
deleted_dedrems = ClaimDedRem.objects.filter(claim=claim).delete()
if deleted_dedrems:
Expand All @@ -604,7 +583,11 @@ def set_claim_processed_or_valuated(claim, errors, user):
if errors:
claim.status = Claim.STATUS_REJECTED
else:
claim.status = Claim.STATUS_PROCESSED if with_relative_prices(claim) else Claim.STATUS_VALUATED
if with_relative_prices(claim):
claim.status = Claim.STATUS_PROCESSED
else:
claim.status = Claim.STATUS_VALUATED
claim.valuated = approved_amount()
claim.audit_user_id_process = user.id_for_audit
from core.utils import TimeUtils
claim.process_stamp = TimeUtils.now()
Expand Down Expand Up @@ -732,7 +715,7 @@ def update_claims_dedrems(uuids, user):
for claim in claims:
remaining_uuid.remove(claim.uuid.upper())
logger.debug(f"delivering review on {claim.uuid}, reprocessing dedrem ({user})")
errors += validate_and_process_dedrem_claim(claim, user, False)
errors += processing_claim(claim, user, False)
if len(remaining_uuid):
errors.append(_(
"claim.validation.id_does_not_exist") % {'id': ','.join(remaining_uuid)})
Expand Down
41 changes: 41 additions & 0 deletions claim/subqueries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from claim.models import Claim, ClaimDetail
from django.db.models import OuterRef, Subquery, Avg, Q, Sum, F, ExpressionWrapper, DecimalField, Subquery, OuterRef, Case, Value, When
from django.db.models.functions import Coalesce

# row_id = models.BinaryField(db_column='RowID', blank=True, null=True)

# subqueries
# Subquery for total_itm_adjusted
total_itm_adjusted_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
total_itm_adjusted=Sum(
F("items__qty_provided") * Coalesce("items__price_adjusted", "items__price_asked")
)
).values('total_itm_adjusted')[:1]
# Subquery for total_srv_adjusted
total_srv_adjusted_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
total_srv_adjusted=Sum(
F("services__qty_provided") * Coalesce("services__price_adjusted", "services__price_asked")
)
).values('total_srv_adjusted')[:1]
# Subquery for total_itm_approved
total_itm_approved_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
total_itm_approved=Sum(
Case(
When(Q(status=Claim.STATUS_REJECTED, items__status=ClaimDetail.STATUS_REJECTED), then=Value(0)),
default=Coalesce("items__qty_approved", "items__qty_provided", 0) *
Coalesce("items__price_approved", "services__price_adjusted", "items__price_asked"),
output_field=DecimalField()
)
)
).values('total_itm_approved')[:1]
# Subquery for total_srv_approved
total_srv_approved_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
total_srv_approved=Sum(
Case(
When(Q(status=Claim.STATUS_REJECTED, items__status=ClaimDetail.STATUS_REJECTED), then=Value(0)),
default=Coalesce("services__qty_approved", "services__qty_provided", 0) *
Coalesce("services__price_approved", "services__price_adjusted", "services__price_asked"),
output_field=DecimalField()
)
)
).values('total_srv_approved')[:1]
56 changes: 26 additions & 30 deletions claim/validations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
from collections import namedtuple

from claim.models import ClaimItem, Claim, ClaimService, ClaimDedRem, ClaimDetail, ClaimServiceService, ClaimServiceItem
from claim.subqueries import (
total_srv_adjusted_subquery, total_itm_adjusted_subquery,
total_srv_approved_subquery, total_itm_approved_subquery,
)
from core import utils
from core.datetimes.shared import datetimedelta
from core.utils import filter_validity
from django.db import connection
from django.db.models import Sum, Q
from django.db.models import Sum, Q, ExpressionWrapper, DecimalField
from django.db.models.functions import Coalesce
from django.utils.translation import gettext as _
from insuree.models import InsureePolicy
Expand Down Expand Up @@ -41,6 +45,8 @@
REJECTION_REASON_MAX_ANTENATAL = 19
REJECTION_REASON_INVALID_CLAIM = 20



def validate_claim(claim, check_max):
"""
Based on the legacy validation, this method returns standard codes along with details
Expand All @@ -55,7 +61,7 @@ def validate_claim(claim, check_max):
detail_errors = []
errors += validate_target_date(claim)
if len(errors) == 0:
errors += validate_family(claim, claim.insuree)
errors += validate_insuree(claim, claim.insuree)
if len(errors) == 0:
detail_errors += validate_claimitems(claim)
detail_errors += validate_claimservices(claim)
Expand Down Expand Up @@ -109,7 +115,7 @@ def validate_claim(claim, check_max):
return errors


def validate_claimitems(claim):
def validate_claimitems(claim, save=True):
errors = []
target_date = claim.date_from if claim.date_from else claim.date_to
for claimitem in claim.items.all():
Expand All @@ -136,11 +142,12 @@ def validate_claimitems(claim):
else:
claimitem.rejection_reason = 0
claimitem.status = ClaimItem.STATUS_PASSED
claimitem.save()
if save:
claimitem.save()
return errors


def validate_claimservices(claim):
def validate_claimservices(claim, save=True):
errors = []
target_date = claim.date_from if claim.date_from else claim.date_to
base_category = get_claim_category(claim)
Expand Down Expand Up @@ -171,7 +178,8 @@ def validate_claimservices(claim):
else:
claimservice.rejection_reason = 0
claimservice.status = ClaimService.STATUS_PASSED
claimservice.save()
if save:
claimservice.save()
return errors


Expand Down Expand Up @@ -348,26 +356,14 @@ def validate_target_date(claim):
return errors


def validate_family(claim, insuree):
def validate_insuree(claim, insuree):
errors = []
if insuree.validity_to is not None:
errors += [{'code': REJECTION_REASON_FAMILY,
'message': _("claim.validation.family.insuree_validity") % {
'code': claim.code,
'insuree': str(insuree)},
'detail': claim.uuid}]
elif insuree.family is None:
errors += [{'code': REJECTION_REASON_FAMILY,
'message': _("claim.validation.family.no_family") % {
'code': claim.code,
'insuree': str(insuree)},
'detail': claim.uuid}]
elif insuree.family.validity_to is not None:
errors += [{'code': REJECTION_REASON_FAMILY,
'message': _("claim.validation.family.family_validity") % {
'code': claim.code,
'insuree': str(insuree)},
'detail': claim.uuid}]
if len(errors) > 0:
claim.reject(REJECTION_REASON_FAMILY)
return errors
Expand Down Expand Up @@ -833,17 +829,17 @@ def validate_assign_prod_to_claimitems_and_services(claim):


def approved_amount(claim):
app_item_value = claim.items \
.annotate(value=Coalesce("qty_approved", "qty_provided") * Coalesce("price_approved", "price_asked")) \
.filter(validity_to__isnull=True, status=ClaimItem.STATUS_PASSED) \
.aggregate(Sum("value"))
app_service_value = claim.services \
.annotate(value=Coalesce("qty_approved", "qty_provided") * Coalesce("price_approved", "price_asked")) \
.filter(validity_to__isnull=True, status=ClaimService.STATUS_PASSED) \
.aggregate(Sum("value"))
return (app_item_value['value__sum'] if app_item_value['value__sum'] else 0) + \
(app_service_value['value__sum']
if app_service_value['value__sum'] else 0)
qs = Claim.objects.filter(id=claim.id)
if claim.status != Claim.STATUS_REJECTED:
return qs.annotate(total_srv_approved=(total_srv_approved_subquery))\
.annotate(total_itm_approved=(total_itm_approved_subquery))\
.aggregate(value=ExpressionWrapper(
(Sum("total_srv_approved") + Sum("total_itm_approved")) ,
output_field=DecimalField()
))["value"]

else:
return 0


def _query_product_item_service_limit(target_date, family_id, elt_qs,
Expand Down

0 comments on commit 4dd996f

Please sign in to comment.