Skip to content

Commit c6f7641

Browse files
authored
Merge pull request #8 from openimis/feature/harmonize-submit
fix test and code
2 parents 09006fd + 5dad26c commit c6f7641

File tree

2 files changed

+89
-116
lines changed

2 files changed

+89
-116
lines changed

claim_sampling/services.py

Lines changed: 33 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,26 @@
33
from typing import List
44

55
from claim.apps import ClaimConfig
6-
from claim.models import Claim, ClaimItem, ClaimService
6+
from claim.models import (
7+
Claim, ClaimItem, ClaimService,
8+
)
9+
710
from enum import Enum
8-
from django.db.models import OuterRef, Subquery, Avg, Q, Sum, F, ExpressionWrapper, DecimalField, Subquery, OuterRef, Case, Value, When
11+
from django.db.models import (
12+
OuterRef, Subquery, Avg, Q, Sum, F, ExpressionWrapper,
13+
FloatField, DecimalField, Subquery, OuterRef, Case, Value, When
14+
)
915
from django.db.models.functions import Coalesce
1016
from django.db import transaction
1117
from django.utils.translation import gettext as _
1218

13-
from claim.services import set_claims_status, update_claims_dedrems, validate_and_process_dedrem_claim
19+
from claim.services import (
20+
set_claims_status, update_claims_dedrems, processing_claim,
21+
)
22+
from claim.subqueries import (
23+
total_srv_adjusted_exp, total_itm_adjusted_exp,
24+
total_srv_approved_exp, total_itm_approved_exp,elm_approved_exp,update_claim_approved, elm_adjusted_exp,elm_approved_exp
25+
)
1426
from claim_sampling.models import (
1527
ClaimSamplingBatch,
1628
ClaimSamplingBatchAssignment,
@@ -118,94 +130,38 @@ def extrapolate_results(self, claim_sampling_id):
118130
claim_sampling = ClaimSamplingBatch.objects.get(id=claim_sampling_id)
119131

120132
qs = Claim.objects.filter(assignments__claim_batch=claim_sampling, *filter_validity())
121-
# Subquery for total_itm_adjusted
122-
total_itm_adjusted_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
123-
total_itm_adjusted=Sum(
124-
F("items__qty_provided") * Coalesce("items__price_adjusted", "items__price_asked")
125-
)
126-
).values('total_itm_adjusted')[:1]
127-
128-
# Subquery for total_srv_adjusted
129-
total_srv_adjusted_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
130-
total_srv_adjusted=Sum(
131-
F("services__qty_provided") * Coalesce("services__price_adjusted", "services__price_asked")
132-
)
133-
).values('total_srv_adjusted')[:1]
134-
135-
# Subquery for total_itm_approved
136-
total_itm_approved_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
137-
total_itm_approved=Sum(
138-
Case(
139-
When(status=Claim.STATUS_REJECTED, then=Value(0)),
140-
default=Coalesce("items__qty_approved", "items__qty_provided", 0) *
141-
Coalesce("items__price_approved", "services__price_adjusted", "items__price_asked"),
142-
output_field=DecimalField()
143-
)
144-
)
145-
).values('total_itm_approved')[:1]
146-
147-
# Subquery for total_srv_approved
148-
total_srv_approved_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
149-
total_srv_approved=Sum(
150-
Case(
151-
When(status=Claim.STATUS_REJECTED, then=Value(0)),
152-
default=Coalesce("services__qty_approved", "services__qty_provided", 0) *
153-
Coalesce("services__price_approved", "services__price_adjusted", "services__price_asked"),
154-
output_field=DecimalField()
155-
)
156-
)
157-
).values('total_srv_approved')[:1]
158-
133+
159134
deductible = qs.filter(review_status=Claim.REVIEW_DELIVERED)\
160-
.filter(Q(services__rejection_reason=-1) | Q(services__rejection_reason__isnull=True))\
161-
.annotate(total_srv_adjusted=(total_srv_adjusted_subquery))\
162-
.annotate(total_itm_adjusted=(total_itm_adjusted_subquery))\
163-
.annotate(total_srv_approved=(total_srv_approved_subquery))\
164-
.annotate(total_itm_approved=(total_itm_approved_subquery))\
135+
.filter(Q(services__rejection_reason__lte=0) | Q(services__rejection_reason__isnull=True))\
136+
.annotate(total_srv_adjusted=total_srv_adjusted_exp)\
137+
.annotate(total_itm_adjusted=total_itm_adjusted_exp)\
138+
.annotate(total_srv_approved=total_srv_approved_exp)\
139+
.annotate(total_itm_approved=total_itm_approved_exp)\
165140
.aggregate(value=ExpressionWrapper(
166141
(Sum("total_srv_approved") + Sum("total_itm_approved")) /
167142
( Sum("total_srv_adjusted") + Sum("total_itm_adjusted")),
168143
output_field=DecimalField()
169144
))["value"]
170-
171-
172-
qs_extrapolated = qs.filter(assignments__status=ClaimSamplingBatchAssignmentStatus.SKIPPED, review_status=Claim.REVIEW_SELECTED)
173-
174-
# Subquery for total_itm_adjusted
175-
total_itm_adjusted_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
176-
total_itm_adjusted=Sum(
177-
F("items__qty_provided") * Coalesce("items__price_adjusted", "items__price_asked")
178-
)
179-
).values('total_itm_adjusted')[:1]
180-
181-
# Subquery for total_srv_adjusted
182-
total_srv_adjusted_subquery = Claim.objects.filter(id=OuterRef('id')).annotate(
183-
total_srv_adjusted=Sum(
184-
F("services__qty_provided") * Coalesce("services__price_adjusted", "services__price_asked")
185-
)
186-
).values('total_srv_adjusted')[:1]
187145

188146
# Filter claims for extrapolation
189-
qs_extrapolated = qs.filter(assignments__status=ClaimSamplingBatchAssignmentStatus.SKIPPED, review_status=Claim.REVIEW_IDLE)
190-
191-
# Update the claims using subqueries
192-
qs_extrapolated.update(
193-
review_status=Claim.REVIEW_BYPASSED,
194-
approved=ExpressionWrapper(
195-
deductible * (
196-
Coalesce(Subquery(total_itm_adjusted_subquery), 0) +
197-
Coalesce(Subquery(total_srv_adjusted_subquery), 0)
198-
),
199-
output_field=DecimalField()
200-
)
147+
qs_extrapolated = qs.filter(
148+
assignments__status=ClaimSamplingBatchAssignmentStatus.SKIPPED,
149+
review_status=Claim.REVIEW_IDLE
201150
)
151+
152+
# update the items and services
153+
deductible = float(deductible or 0)
154+
155+
202156
# update service and item
203157
ClaimItem.objects.filter(claim__in=qs_extrapolated).update(price_approved=deductible * F("price_adjusted"))
204158
ClaimService.objects.filter(claim__in=qs_extrapolated).update(price_approved=deductible * F("price_adjusted"))
205159

160+
update_claim_approved(qs_extrapolated, updates={'review_status': Claim.REVIEW_BYPASSED})
161+
206162
errors = []
207-
for claim in qs:
208-
errors += validate_and_process_dedrem_claim(claim, self.user, True)
163+
for claim in qs.filter(status=Claim.STATUS_CHECKED):
164+
errors += processing_claim(claim, self.user, True)
209165

210166
return errors
211167

claim_sampling/tests.py

Lines changed: 56 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@
2424
from graphene_django.utils.testing import GraphQLTestCase
2525
from claim_sampling import schema as claim_schema
2626
from graphene.test import Client
27-
28-
27+
from policy.test_helpers import create_test_policy2
28+
from product.test_helpers import create_test_product, create_test_product_service, create_test_product_item
29+
from medical_pricelist.test_helpers import add_service_to_hf_pricelist, add_item_to_hf_pricelist
30+
from product.models import ProductItemOrService
31+
from datetime import date, timedelta, datetime
2932
class ClaimSubmitServiceTestCase(GraphQLTestCase):
3033
GRAPHQL_URL = f'/{settings.SITE_ROOT()}graphql'
3134
# This is required by some version of graphene but is never used. It should be set to the schema but the import
@@ -50,9 +53,9 @@ class ClaimSubmitServiceTestCase(GraphQLTestCase):
5053

5154
test_claims = []
5255

56+
5357
@classmethod
54-
def setUpClass(cls):
55-
super().setUpClass()
58+
def setUpTestData(cls):
5659
cls.admin_user = create_test_interactive_user(username="testLocationAdmin")
5760
cls.admin_token = get_token(cls.admin_user, DummyContext(user=cls.admin_user))
5861
cls.schema = Schema(
@@ -63,8 +66,6 @@ def setUpClass(cls):
6366

6467
cls.officer = create_test_officer(custom_props={"code": "TSTSIMP1"})
6568

66-
@classmethod
67-
def setUpTestData(cls):
6869
if cls.test_region is None:
6970
cls.test_village = create_test_village()
7071
cls.test_ward = cls.test_village.parent
@@ -82,35 +83,56 @@ def setUpTestData(cls):
8283
location=cls.test_village,
8384
)
8485
cls.test_insuree = create_test_insuree(is_head=True, custom_props=props, family_custom_props=family_props)
86+
product = create_test_product("TEST_CLM")
87+
cls.test_policy , ip = create_test_policy2(product, cls.test_insuree)
8588
cls.test_claim_admin = create_test_claim_admin()
8689
cls.test_icd = Diagnosis(code='ICD00I', name='diag test', audit_user_id=-1)
8790
cls.test_icd.save()
8891

89-
cls._create_test_claims()
92+
cls._create_test_claims(cls.test_policy.product)
93+
9094

9195
@classmethod
92-
def _create_test_claims(cls):
96+
def _create_test_claims(cls, product):
97+
configdate = datetime.now() - timedelta(days=265)
98+
9399
test_item = create_test_item(
94100
'D',
95-
custom_props={"code": "cCode", "price": 1000}
101+
custom_props={"code": "csamCo", "price": 1000 }
96102
)
97103
test_service = create_test_service(
98104
'D',
99-
custom_props={"code": "sCode", "price": 1000}
105+
custom_props={"code": "ssamCo", "price": 1000}
106+
)
107+
create_test_product_service(
108+
product,
109+
test_service,
110+
custom_props={"price_origin": ProductItemOrService.ORIGIN_RELATIVE},
100111
)
112+
create_test_product_item(
113+
product,
114+
test_item,
115+
custom_props={"price_origin": ProductItemOrService.ORIGIN_RELATIVE},
116+
)
117+
add_service_to_hf_pricelist(test_service, hf_id=cls.test_hf.id)
118+
add_item_to_hf_pricelist(test_item, hf_id=cls.test_hf.id)
119+
120+
dateclaim = date.today() - timedelta(days=5)
121+
datetimeclaim = datetime.now() - timedelta(days=5)
101122
for i in range(10):
102123
claim = Claim.objects.create(
103-
date_claimed=core.datetime.date(2024, 1, 15),
124+
date_claimed=dateclaim,
104125
code=F"code_ABV{i}",
105126
icd=cls.test_icd,
106127
claimed=2000,
107-
date_from=core.datetime.date(2024, 1, 13),
108-
date_to=core.datetime.date(2024, 1, 15),
128+
date_from=dateclaim,
129+
date_to=None,
109130
admin=cls.test_claim_admin,
110131
insuree=cls.test_insuree,
111132
health_facility=cls.test_hf,
112133
status=Claim.STATUS_ENTERED,
113-
audit_user_id=-1
134+
audit_user_id=-1,
135+
validity_from=datetimeclaim
114136
)
115137
claim_item = ClaimItem.objects.create(
116138
claim=claim,
@@ -119,53 +141,46 @@ def _create_test_claims(cls):
119141
qty_provided=1,
120142
audit_user_id=-1,
121143
status=ClaimDetail.STATUS_PASSED,
122-
availability=True
144+
availability=True,
145+
validity_from=datetimeclaim
123146
)
124147
claim_service = ClaimService.objects.create(
125148
claim=claim,
126149
service=test_service,
127150
price_asked=1000,
128151
qty_provided=1,
129152
audit_user_id=-1,
130-
status=ClaimDetail.STATUS_PASSED
153+
status=ClaimDetail.STATUS_PASSED,
154+
validity_from=datetimeclaim
131155
)
132-
133-
mark_test_claim_as_processed(claim)
156+
claim.refresh_from_db()
157+
ClaimSubmitService(cls.admin_user).submit_claim(claim)
134158
cls.test_claims.append(claim)
135-
159+
136160
@classmethod
137161
def _set_claim_as_valuated(cls, claim, user, is_process=False):
138162
# Mock of dedrem
139163
claim.status = Claim.STATUS_PROCESSED
140164
claim.save()
141165
return []
142166

143-
@mock.patch("claim.services.validate_claim")
144-
@mock.patch("claim.services.process_dedrem")
145-
@mock.patch("claim.services.validate_assign_prod_to_claimitems_and_services")
146-
def test_mutation_create_claim(
147-
self,
148-
validate_claim,
149-
process_dedrem,
150-
validate_assign_prod_to_claimitems_and_services):
151-
validate_claim.return_value = []
152-
process_dedrem.side_effect = self._set_claim_as_valuated
153-
validate_assign_prod_to_claimitems_and_services.return_value = []
167+
def test_mutation_create_claim( self):
168+
154169
percentage_for_sample = 20
155-
response = self.query('''
156-
mutation {
170+
response = self.query(f'''
171+
mutation {{
157172
createClaimSamplingBatch(
158-
input: {
173+
input: {{
159174
clientMutationId: "fdcc211f-7225-4f0e-8a66-11223344667d"
160175
clientMutationLabel: "Create Claim Sampling Batch"
161176
percentage: 30
162-
filters: "{\\"status\\":4, \\"dateFrom\\": \\"2024-01-13\\"}"
163-
}
164-
) {
177+
filters: "{{\\"status\\":4, \\"dateFrom\\": \\"{date.today() - timedelta(days=5)}\\"}}"
178+
}}
179+
) {{
165180
clientMutationId
166181
internalId
167-
}
168-
}
182+
}}
183+
}}
169184
''', headers={"HTTP_AUTHORIZATION": f"Bearer {self.admin_token}"})
170185

171186
claim_sampling = ClaimSamplingBatch.objects.first()
@@ -202,16 +217,18 @@ def test_mutation_create_claim(
202217
self.assertEqual(rejected_from_review.count(), 2)
203218
self.assertEqual(reviewed_delivered.count(), 3)
204219
self.assertEqual(total, 3)
220+
datetimeclaim = datetime.now() - timedelta(days=5)
205221

206222
# Extrapolation
207223
service.extrapolate_results(claim_sampling.id)
208224
attachments = ClaimSamplingBatchAssignment.objects.filter(claim_batch=claim_sampling)
209225
# 50% of remaining claims should be rejected and 50% should be valuated
210226
skip = [x.claim for x in attachments.filter(status=ClaimSamplingBatchAssignmentStatus.SKIPPED)]
211-
accepted = [x for x in skip if x.status in [Claim.STATUS_PROCESSED, Claim.STATUS_VALUATED]]
227+
accepted = [x for x in skip if x.status in [ Claim.STATUS_PROCESSED, Claim.STATUS_VALUATED]]
212228
rejected = [x for x in skip if x.status in [Claim.STATUS_REJECTED]]
213229
self.assertEqual(len(accepted), 7)
214230
self.assertEqual(len(rejected), 0)
231+
215232
# FIXME check the ratio (done manually looks ok)
216233

217234

0 commit comments

Comments
 (0)