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) }]
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 }] }
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) }]
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()
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
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) }]
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, )