Exemplo n.º 1
0
 def async_mutate(cls, user, **data):
     try:
         if not user.has_perms(
                 ClaimConfig.gql_mutation_deliver_claim_feedback_perms):
             raise PermissionDenied(_("unauthorized"))
         claim = Claim.objects.select_related('feedback').get(
             uuid=data['claim_uuid'], validity_to__isnull=True)
         prev_feedback = claim.feedback
         prev_claim_id = claim.save_history()
         if prev_feedback:
             prev_feedback.claim_id = prev_claim_id
             prev_feedback.save()
         feedback = data['feedback']
         from core.utils import TimeUtils
         feedback['validity_from'] = TimeUtils.now()
         feedback['audit_user_id'] = user.id_for_audit
         # The legacy model has a Foreign key on both sides of this one-to-one relationship
         f, created = Feedback.objects.update_or_create(claim=claim,
                                                        defaults=feedback)
         claim.feedback = f
         claim.feedback_status = 8
         claim.feedback_available = True
         claim.save()
         return None
     except Exception as exc:
         return [{
             'message': _("claim.mutation.failed_to_update_claim") % {
                 'code': claim.code
             },
             'detail': str(exc)
         }]
Exemplo n.º 2
0
def set_claim_submitted(claim, errors, user):
    try:
        if errors:
            claim.status = Claim.STATUS_REJECTED
        else:
            claim.approved = approved_amount(claim)
            claim.status = Claim.STATUS_CHECKED
            claim.audit_user_id_submit = user.id_for_audit
            from core.utils import TimeUtils
            claim.submit_stamp = TimeUtils.now()
            claim.category = get_claim_category(claim)
        claim.save()
        return []
    except Exception as exc:
        return {
            'title':
            claim.code,
            'list': [{
                'message':
                _("claim.mutation.failed_to_change_status_of_claim") % {
                    'code': claim.code
                },
                'detail': claim.uuid
            }]
        }
Exemplo n.º 3
0
 def async_mutate(cls, user, **data):
     try:
         # TODO move this verification to OIMutation
         if type(user) is AnonymousUser or not user.id:
             raise ValidationError(_("mutation.authentication_required"))
         if not user.has_perms(
                 ClaimConfig.gql_mutation_create_claims_perms):
             raise PermissionDenied(_("unauthorized"))
         # Claim code unicity should be enforced at DB Scheme level...
         if Claim.objects.filter(code=data['code']).exists():
             return [{
                 'message': _("claim.mutation.duplicated_claim_code") % {
                     'code': data['code']
                 },
             }]
         data['audit_user_id'] = user.id_for_audit
         data['status'] = Claim.STATUS_ENTERED
         from core.utils import TimeUtils
         data['validity_from'] = TimeUtils.now()
         attachments = data.pop(
             'attachments') if 'attachments' in data else None
         claim = update_or_create_claim(data, user)
         if attachments:
             create_attachments(claim.id, attachments)
         return None
     except Exception as exc:
         return [{
             'message': _("claim.mutation.failed_to_create_claim") % {
                 'code': data['code']
             },
             'detail': str(exc)
         }]
Exemplo n.º 4
0
def mark_test_claim_as_processed(claim, status=Claim.STATUS_CHECKED, audit_user_id=-1):
    claim.approved = approved_amount(claim)
    claim.status = status
    claim.audit_user_id_submit = audit_user_id
    from core.utils import TimeUtils
    claim.submit_stamp = TimeUtils.now()
    claim.category = get_claim_category(claim)
    claim.save()
Exemplo n.º 5
0
def process_child_relation(user, data_children, prev_claim_id, claim_id,
                           children, create_hook):
    claimed = 0
    prev_elts = [s.id for s in children.all()]
    from core.utils import TimeUtils
    for elt in data_children:
        claimed += elt['qty_provided'] * elt['price_asked']
        elt_id = elt.pop('id') if 'id' in elt else None
        if elt_id:
            prev_elts.remove(elt_id)
            # explanation and justification are both TextField (ntext in db) and cannot be compared with str
            # [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]The data types ntext and nvarchar are incompatible in the equal to operator
            # need to cast!
            explanation = elt.pop('explanation', None)
            justification = elt.pop('justification', None)
            prev_elt = children.\
                annotate(strexplanation=Cast('explanation', CharField())). \
                annotate(strjustification=Cast('justification', CharField())). \
                filter(id=elt_id, **elt). \
                filter(strexplanation=explanation). \
                filter(strjustification=justification). \
                first()
            if not prev_elt:
                # item has been updated, let's bind the old value to prev_claim
                prev_elt = children.get(id=elt_id)
                prev_elt.claim_id = prev_claim_id
                prev_elt.save()
                # ... and update with the new values
                new_elt = copy(prev_elt)
                [setattr(new_elt, key, elt[key]) for key in elt]
                new_elt.explanation = explanation
                new_elt.justification = justification
                new_elt.id = None
                new_elt.validity_from = TimeUtils.now()
                new_elt.audit_user_id = user.id_for_audit
                new_elt.claim_id = claim_id
                new_elt.save()
        else:
            elt['validity_from'] = TimeUtils.now()
            elt['audit_user_id'] = user.id_for_audit
            create_hook(claim_id, elt)

    if prev_elts:
        children.filter(id__in=prev_elts).update(claim_id=prev_claim_id,
                                                 validity_to=TimeUtils.now())
    return claimed
def process_child_relation(user, data_children, claim_id, children,
                           create_hook):
    claimed = 0
    from core.utils import TimeUtils
    for data_elt in data_children:
        claimed += data_elt['qty_provided'] * data_elt['price_asked']
        elt_id = data_elt.pop('id') if 'id' in data_elt else None
        if elt_id:
            # elt has been historized along with claim historization
            elt = children.get(id=elt_id)
            [setattr(elt, k, v) for k, v in data_elt.items()]
            elt.validity_from = TimeUtils.now()
            elt.audit_user_id = user.id_for_audit
            elt.claim_id = claim_id
            elt.save()
        else:
            data_elt['validity_from'] = TimeUtils.now()
            data_elt['audit_user_id'] = user.id_for_audit
            create_hook(claim_id, data_elt)

    return claimed
Exemplo n.º 7
0
 def async_mutate(cls, user, **data):
     try:
         if type(user) is AnonymousUser or not user.id:
             raise ValidationError("mutation.authentication_required")
         if not user.has_perms(CoreConfig.gql_mutation_create_roles_perms):
             raise PermissionDenied("unauthorized")
         from core.utils import TimeUtils
         data['validity_from'] = TimeUtils.now()
         data['audit_user_id'] = user.id_for_audit
         update_or_create_role(data, user)
         return None
     except Exception as exc:
         return [{
             'message': "core.mutation.failed_to_create_role",
             'detail': str(exc)
         }]
Exemplo n.º 8
0
def set_claim_processed_or_valuated(claim, errors, user):
    try:
        if errors:
            claim.status = Claim.STATUS_REJECTED
        else:
            claim.status = Claim.STATUS_PROCESSED if with_relative_prices(
                claim) else Claim.STATUS_VALUATED
            claim.audit_user_id_process = user.id_for_audit
            from core.utils import TimeUtils
            claim.process_stamp = TimeUtils.now()
        claim.save()
        return []
    except Exception as ex:
        return {
            'title':
            claim.code,
            'list': [{
                'message':
                _("claim.mutation.failed_to_change_status_of_claim") % {
                    'code': claim.code
                },
                'detail': claim.uuid
            }]
        }
def do_process_batch(audit_user_id, location_id, period, year):
    relative_index_calculation_monthly(rel_type=12,
                                       period=period,
                                       year=year,
                                       location_id=location_id,
                                       product_id=0,
                                       audit_user_id=audit_user_id)
    if period == 3:
        relative_index_calculation_monthly(rel_type=4,
                                           period=1,
                                           year=year,
                                           location_id=location_id,
                                           product_id=0,
                                           audit_user_id=audit_user_id)
    if period == 6:
        relative_index_calculation_monthly(rel_type=4,
                                           period=2,
                                           year=year,
                                           location_id=location_id,
                                           product_id=0,
                                           audit_user_id=audit_user_id)
    if period == 9:
        relative_index_calculation_monthly(rel_type=4,
                                           period=3,
                                           year=year,
                                           location_id=location_id,
                                           product_id=0,
                                           audit_user_id=audit_user_id)
    if period == 12:
        relative_index_calculation_monthly(rel_type=4,
                                           period=4,
                                           year=year,
                                           location_id=location_id,
                                           product_id=0,
                                           audit_user_id=audit_user_id)
        relative_index_calculation_monthly(rel_type=1,
                                           period=1,
                                           year=year,
                                           location_id=location_id,
                                           product_id=0,
                                           audit_user_id=audit_user_id)

    for svc_item in [ClaimItem, ClaimService]:
        prod_qs = svc_item.objects \
            .filter(claim__status=Claim.STATUS_PROCESSED) \
            .filter(claim__validity_to__isnull=True) \
            .filter(validity_to__isnull=True) \
            .filter(status=svc_item.STATUS_PASSED) \
            .filter(price_origin=ProductItemOrService.ORIGIN_RELATIVE) \
            .annotate(prod_location=Coalesce("product__location_id", Value(-1))) \
            .filter(prod_location=location_id if location_id else -1)

        product_loop = prod_qs.values(
            "claim__health_facility__level", "product_id", "product__period_rel_prices",
            "product__period_rel_prices_op",
            "product__period_rel_prices_ip", "claim__process_stamp__month", "claim__process_stamp__year") \
            .distinct()

        for product in product_loop:
            index = -1
            target_month = product["claim__process_stamp__month"]
            target_year = product["claim__process_stamp__year"]
            # Will fail with Ethiopian calendar but so will the rest of this procedure
            target_quarter = int((target_month - 1) / 3) + 1

            index = -1
            if product["product__period_rel_prices"]:
                prod_rel_price_type = product["product__period_rel_prices"]
            elif product["claim__health_facility__level"] == 'H' and product[
                    "product__period_rel_prices_ip"]:
                prod_rel_price_type = product["product__period_rel_prices_ip"]
            elif product["claim__health_facility__level"] != 'H' and product[
                    "product__period_rel_prices_op"]:
                prod_rel_price_type = product["product__period_rel_prices_op"]
            else:
                raise Exception(
                    f"product {product['product_id']} has an impossible in/out patient or both"
                )

            if prod_rel_price_type == RelativeIndex.TYPE_MONTH:
                index = _get_relative_index(product["product_id"],
                                            target_month, target_year,
                                            RelativeIndex.CARE_TYPE_BOTH,
                                            RelativeIndex.TYPE_MONTH)
            if prod_rel_price_type == RelativeIndex.TYPE_QUARTER:
                index = _get_relative_index(product["product_id"],
                                            target_quarter, target_year,
                                            RelativeIndex.CARE_TYPE_BOTH,
                                            RelativeIndex.TYPE_QUARTER)
            if prod_rel_price_type == RelativeIndex.TYPE_YEAR:
                index = _get_relative_index(product["product_id"], None,
                                            target_year,
                                            RelativeIndex.CARE_TYPE_BOTH,
                                            RelativeIndex.TYPE_YEAR)

            if index > -1:
                prod_qs \
                    .filter(claim__health_facility__level=product["claim__health_facility__level"]) \
                    .filter(product_id=product["product_id"]) \
                    .update(remunerated_amount=F(F("price_valuated") * index))

    # Get all the claims in valuated state with no Relative index /Services
    def filter_valuated_claims(base):
        return base.objects.filter(claim__status=Claim.STATUS_VALUATED) \
            .filter(claim__validity_to__isnull=True) \
            .filter(validity_to__isnull=True) \
            .filter(status=ClaimDetail.STATUS_PASSED) \
            .exclude(price_origin='R') \
            .annotate(prod_location=Coalesce("product__location_id", Value(-1))) \
            .filter(prod_location=location_id if location_id else -1) \
            .filter(claim__batch_run_id__isnull=True) \
            .filter(claim__process_stamp__month=period) \
            .filter(claim__process_stamp__year=year) \
            .values("claim_id") \
            .distinct()

    item_ids = filter_valuated_claims(ClaimItem)
    service_ids = filter_valuated_claims(ClaimService)

    all_ids = item_ids.union(service_ids).distinct().values_list("id",
                                                                 flat=True)

    def filter_item_or_service(base):
        return base.objects \
            .filter(claim__validity_to__isnull=True) \
            .annotate(prod_location=Coalesce("product__location_id", Value(-1))) \
            .filter(prod_location=location_id if location_id else -1) \
            .filter(remunerated_amount__isnull=True) \
            .filter(validity_to__isnull=True) \
            .filter(status=ClaimItem.STATUS_PASSED) \
            .filter(claim__status=Claim.STATUS_PROCESSED) \
            .values("claim_id") \
            .distinct()

    item_prod_ids = filter_item_or_service(ClaimItem)
    service_prod_ids = filter_item_or_service(ClaimService)

    Claim.objects \
        .filter(status=Claim.STATUS_PROCESSED) \
        .filter(id__in=all_ids) \
        .filter(validity_to__isnull=True) \
        .exclude(id__in=item_prod_ids) \
        .exclude(id__in=service_prod_ids) \
        .update(status=Claim.STATUS_VALUATED)

    from core.utils import TimeUtils
    created_run = BatchRun.objects.create(location_id=location_id,
                                          run_year=year,
                                          run_month=period,
                                          run_date=TimeUtils.now(),
                                          audit_user_id=audit_user_id,
                                          validity_from=TimeUtils.now())

    month_start = 0
    month_end = 0
    if period in (3, 6, 9):
        month_start = period - 2
        month_end = period
    if period == 12:
        month_start = 1
        month_end = 12

    # Link claims to this batch run
    filter_base = Claim.objects \
        .filter(id__in=all_ids) \
        .filter(status=Claim.STATUS_VALUATED) \
        .filter(batch_run_id__isnull=True) \
        .filter(process_stamp__year=year)

    filter_base \
        .filter(process_stamp__month=period) \
        .update(batch_run=created_run)

    # If more than a month was run
    if month_start > 0:
        filter_base \
            .filter(process_stamp__month__gte=month_start) \
            .filter(process_stamp__month__lte=month_end) \
            .update(batch_run=created_run)
def create_relative_index(prod_id,
                          prod_value,
                          year,
                          relative_type,
                          location_id,
                          audit_user_id,
                          rel_price_type,
                          period=None,
                          month_start=None,
                          month_end=None):
    distr = RelativeDistribution.objects \
        .filter(product_id=prod_id) \
        .filter(period=period) \
        .filter(type=relative_type) \
        .filter(care_type=rel_price_type) \
        .filter(validity_to__isnull=False) \
        .first()
    distr_perc = distr.percent if distr and distr.percent else 1

    claim_value = 0
    for claim_detail in [ClaimService, ClaimItem]:
        qs_val = claim_detail.objects \
            .filter(status=ClaimDetail.STATUS_PASSED) \
            .filter(claim__validity_to__isnull=True) \
            .filter(validity_to__isnull=True) \
            .filter(claim__status__in=[Claim.STATUS_PROCESSED, Claim.STATUS_VALUATED]) \
            .annotate(nn_process_stamp_month=Coalesce(ExtractMonth("claim__process_stamp"), Value(-1))) \
            .annotate(nn_process_stamp_year=Coalesce(ExtractYear("claim__process_stamp"), Value(-1))) \
            .filter(nn_process_stamp_year=year) \
            .filter(product_id=prod_id)
        if period:
            qs_val = qs_val.filter(nn_process_stamp_month=period)
        elif month_start and month_end:
            qs_val = qs_val.filter(
                nn_process_stamp_month__gte=month_start).filter(
                    nn_process_stamp_month__lte=month_end)
        # else not needed as the year simply relies on the above year filter

        if rel_price_type == RelativeIndex.CARE_TYPE_IN_PATIENT:
            qs_val = qs_val.filter(
                claim__health_facility__level=HealthFacility.LEVEL_HOSPITAL)
        elif rel_price_type == RelativeIndex.CARE_TYPE_OUT_PATIENT:
            qs_val = qs_val.exclude(
                claim__health_facility__level=HealthFacility.LEVEL_HOSPITAL)
        # else both, no filter needed

        price_valuated = qs_val.values("price_valuated").aggregate(
            sum=Sum(Coalesce("price_valuated", 0)))["sum"]
        claim_value += price_valuated if price_valuated else 0

    if claim_value == 0:
        rel_index = 1
    else:
        rel_index = (prod_value * distr_perc) / claim_value

    from core.utils import TimeUtils
    return RelativeIndex.objects.create(
        product_id=prod_id,
        type=relative_type,
        care_type=RelativeIndex.CARE_TYPE_IN_PATIENT,
        year=year,
        period=period,
        calc_date=TimeUtils.now(),
        rel_index=rel_index,
        audit_user_id=audit_user_id,
        location_id=location_id,
    )