Skip to content

Commit 177ea70

Browse files
more accurate timestamp generation
1 parent 6ca570d commit 177ea70

14 files changed

Lines changed: 5124 additions & 5114 deletions

apps/bfd-model/bfd-model-idr/sample-data/generator/claims_generator.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
from pathlib import Path
1313
from dateutil.parser import parse
1414
from datetime import date, datetime, timedelta
15+
from faker import Faker
1516

1617
generator = GeneratorUtil()
18+
faker = Faker()
1719

1820
def save_output_files(clm,clm_line,clm_val,clm_dt_sgntr,clm_prod,clm_instnl,clm_line_instnl,clm_dcmtn,clm_fiss):
1921
Path("out").mkdir(exist_ok=True)
@@ -172,8 +174,6 @@ def add_diagnoses(clm_type_cd=-1):
172174
'CLM_PROD_TYPE_CD':'D'}
173175
diagnosis_list.append(diagnosis)
174176

175-
for diagnosis in diagnosis_list:
176-
add_meta_timestamps(diagnosis)
177177
return diagnosis_list
178178

179179

@@ -182,15 +182,13 @@ def gen_procedure_icd10pcs():
182182
procedure['CLM_PROD_TYPE_CD'] = 'S'
183183
procedure['CLM_PRCDR_CD'] = random.choice(available_procedure_codes_icd10_pcs)
184184
procedure['CLM_DGNS_PRCDR_ICD_IND'] = '0'
185-
add_meta_timestamps(procedure)
186185
return procedure
187186

188187

189-
def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today())):
188+
def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today())):
190189
claim = {'CLM':{},'CLM_LINE':[],'CLM_DT_SGNTR':{},'CLM_LINE_INSTNL':[], 'CLM_DCMTN':{}}
191190
clm_dt_sgntr = {}
192191
clm_dt_sgntr['CLM_DT_SGNTR_SK'] = ''.join(random.choices(string.digits, k=12))
193-
add_meta_timestamps(clm_dt_sgntr)
194192
claim['CLM']['CLM_DT_SGNTR_SK'] = clm_dt_sgntr['CLM_DT_SGNTR_SK']
195193
claim['CLM']['CLM_UNIQ_ID'] = ''.join(random.choices(string.digits, k=13))
196194
#clm_type_cd = 60
@@ -203,7 +201,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
203201
elif(clm_type_cd in fiss_clm_type_cds):
204202
clm_src_id = 21000
205203
claim['CLM']['CLM_SRC_ID'] = clm_src_id
206-
claim['CLM']['CLM_FROM_DT'] = random_date(minDate, maxDate)
204+
claim['CLM']['CLM_FROM_DT'] = random_date(min_date, max_date)
207205
claim['CLM']['CLM_THRU_DT'] = gen_thru_dt(claim['CLM']['CLM_FROM_DT'])
208206

209207

@@ -216,7 +214,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
216214

217215
claim['CLM']['CLM_NUM_SK'] = 1
218216
claim['CLM']['CLM_EFCTV_DT'] = str(date.today())
219-
claim['CLM']['CLM_IDR_LD_DT'] = str(date.today())
217+
claim['CLM']['CLM_IDR_LD_DT'] = random_date(claim['CLM']['CLM_FROM_DT'], max_date)
220218
claim['CLM']['CLM_OBSLT_DT'] = '9999-12-31'
221219
claim['CLM']['GEO_BENE_SK'] = ''.join(random.choices(string.digits, k=5))
222220
claim['CLM']['BENE_SK'] = bene_sk
@@ -231,7 +229,8 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
231229
claim['CLM']['CLM_CNTRCTR_NUM'] = random.choice(generator.code_systems['CLM_CNTRCTR_NUM'])
232230
claim['CLM']['CLM_NCH_PRMRY_PYR_CD'] = random.choice(generator.code_systems['CLM_NCH_PRMRY_PYR_CD'])
233231

234-
add_meta_timestamps(claim['CLM'])
232+
add_meta_timestamps(claim['CLM'], claim['CLM'], max_date)
233+
add_meta_timestamps(clm_dt_sgntr, claim['CLM'], max_date)
235234

236235
clm_finl_actn_ind = 'N'
237236
if(clm_type_cd in (10,20,30,40,50,60,61,62,63,71,72,81,82)):
@@ -267,7 +266,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
267266
claim['CLM_DCMTN']['CLM_NUM_SK'] = claim['CLM']['CLM_NUM_SK']
268267
claim['CLM_DCMTN']['GEO_BENE_SK'] = claim['CLM']['GEO_BENE_SK']
269268
claim['CLM_DCMTN']['CLM_TYPE_CD'] = claim['CLM']['CLM_TYPE_CD']
270-
add_meta_timestamps(claim['CLM_DCMTN'])
269+
add_meta_timestamps(claim['CLM_DCMTN'], claim['CLM'], max_date)
271270

272271
#provider elements:
273272
if((clm_type_cd < 65 and clm_type_cd >= 10) or clm_type_cd in fiss_clm_type_cds):
@@ -311,7 +310,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
311310
'CLM_VAL_SQNC_NUM':3}
312311
claim['CLM_VAL'].append(clm_val_ime)
313312
for clm_val in claim['CLM_VAL']:
314-
add_meta_timestamps(clm_val)
313+
add_meta_timestamps(clm_val, claim['CLM'], max_date)
315314

316315
#Add procedures
317316
claim['CLM_PROD'] = []
@@ -325,6 +324,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
325324
procedure['CLM_NUM_SK'] = claim['CLM']['CLM_NUM_SK']
326325
procedure['GEO_BENE_SK'] = claim['CLM']['GEO_BENE_SK']
327326
procedure['CLM_TYPE_CD'] = claim['CLM']['CLM_TYPE_CD']
327+
add_meta_timestamps(procedure, claim['CLM'], max_date)
328328
claim['CLM_PROD'].append(procedure)
329329

330330
#add diagnoses
@@ -335,6 +335,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
335335
diagnosis['GEO_BENE_SK'] = claim['CLM']['GEO_BENE_SK']
336336
diagnosis['CLM_TYPE_CD'] = claim['CLM']['CLM_TYPE_CD']
337337
claim['CLM_PROD'].append(diagnosis)
338+
add_meta_timestamps(diagnosis, claim['CLM'], max_date)
338339

339340
#clm_dt_sgntr info
340341
if(clm_type_cd in (10,20,30,50,60,61,62,63,64)):
@@ -397,7 +398,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
397398
institutional_parts['CLM_MDCR_IP_PPS_CPTL_TOT_AMT'] = round(random.uniform(0,25),2)
398399
institutional_parts['CLM_MDCR_IP_BENE_DDCTBL_AMT'] = round(random.uniform(0,25),2)
399400
institutional_parts['CLM_PPS_IND_CD'] = random.choice(['','2'])
400-
add_meta_timestamps(institutional_parts)
401+
add_meta_timestamps(institutional_parts, claim['CLM'], max_date)
401402

402403
if(clm_type_cd==10):
403404
if(random.choice([0,1])):
@@ -459,7 +460,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
459460
claim_line['CLM_LINE_PRVDR_PMT_AMT'] = round(random.uniform(0,1500),2)
460461
claim_line['CLM_LINE_NCVRD_CHRG_AMT'] = round(random.uniform(0,1500),2)
461462

462-
add_meta_timestamps(claim_line)
463+
add_meta_timestamps(claim_line, claim['CLM'], max_date)
463464

464465
claim_line_inst['CLM_LINE_INSTNL_ADJSTD_AMT'] = round(random.uniform(0,1500),2)
465466
claim_line_inst['CLM_LINE_INSTNL_RDCD_AMT'] = round(random.uniform(0,1500),2)
@@ -476,7 +477,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
476477
claim_line_inst['CLM_REV_PMT_MTHD_CD'] = random.choice(generator.code_systems['CLM_REV_PMT_MTHD_CD'])
477478
claim_line_inst['CLM_REV_CNTR_STUS_CD'] = random.choice(generator.code_systems['CLM_REV_CNTR_STUS_CD'])
478479
claim_line_inst['CLM_ANSI_SGNTR_SK'] = random.choice(['8585','1','4365','1508','5555','9204','6857','5816','11978'])
479-
add_meta_timestamps(claim_line_inst)
480+
add_meta_timestamps(claim_line_inst, claim['CLM'], max_date)
480481

481482
claim_line['CLM_UNIQ_ID'] = claim['CLM']['CLM_UNIQ_ID']
482483
claim_line['CLM_LINE_NUM'] = line
@@ -489,7 +490,7 @@ def gen_claim(bene_sk = '-1', minDate = '2018-01-01', maxDate = str(date.today()
489490

490491

491492

492-
def gen_pac_version_of_claim(claim):
493+
def gen_pac_version_of_claim(claim, max_date):
493494
#note the fields to delete
494495
'''
495496
Generating a Synthetic PAC claim is done in a rather naive way.
@@ -514,7 +515,7 @@ def gen_pac_version_of_claim(claim):
514515
pac_claim['CLM_FISS']['CLM_NUM_SK'] = pac_claim['CLM']['CLM_NUM_SK']
515516
pac_claim['CLM_FISS']['CLM_TYPE_CD'] = pac_claim['CLM']['CLM_TYPE_CD']
516517
pac_claim['CLM_FISS']['CLM_CRNT_STUS_CD'] = random.choice(['A','F','I','S','M','P','R','D','T','U'])
517-
add_meta_timestamps(pac_claim['CLM_FISS'])
518+
add_meta_timestamps(pac_claim['CLM_FISS'], claim['CLM'], max_date)
518519

519520

520521
for i in range(len(pac_claim['CLM_LINE'])):
@@ -588,10 +589,13 @@ def gen_pac_version_of_claim(claim):
588589

589590
return pac_claim
590591

591-
def add_meta_timestamps(obj):
592-
has_insrt_ts = random.random() > 0.2
593-
obj['IDR_INSRT_TS'] = datetime.today() if has_insrt_ts else None
594-
obj['IDR_UPDT_TS'] = datetime.today() if has_insrt_ts and random.random() > 0.8 else None
592+
def add_meta_timestamps(obj, clm, max_date):
593+
if date.fromisoformat(clm['CLM_IDR_LD_DT']) < date(2021, 4, 19):
594+
has_insrt_ts = random.random() > 0.5
595+
else:
596+
has_insrt_ts = True
597+
obj['IDR_INSRT_TS'] = faker.date_time_between_dates(datetime.fromisoformat(clm['CLM_IDR_LD_DT']), datetime.fromisoformat(max_date)) if has_insrt_ts else None
598+
obj['IDR_UPDT_TS'] = faker.date_time_between_dates(obj['IDR_INSRT_TS'], datetime.fromisoformat(max_date)) if has_insrt_ts and random.random() > 0.8 else None
595599

596600
'''
597601
def pull_code_systems():
@@ -646,12 +650,13 @@ def main():
646650
CLM_DCMTN = []
647651
CLM_FISS = []
648652
pt_complete = 0
653+
max_date = str(date.today())
649654
for pt_bene_sk in bene_sk_list:
650655
if((pt_complete)%1000 == 0 and pt_complete>0):
651656
print(f"Completed {pt_complete} patients with {claims_to_generate_per_person} claims per patient.")
652657
for i in range(claims_to_generate_per_person):
653658
clm_from_dt_min = '2018-01-01'
654-
claim = gen_claim(bene_sk = pt_bene_sk,minDate = clm_from_dt_min)
659+
claim = gen_claim(bene_sk = pt_bene_sk, min_date = clm_from_dt_min, max_date=max_date)
655660
CLM.append(claim['CLM'])
656661
for line in claim['CLM_LINE']:
657662
CLM_LINE.append(line)
@@ -665,7 +670,7 @@ def main():
665670
CLM_LINE_INSTNL.append(line)
666671
CLM_DCMTN.append(claim['CLM_DCMTN'])
667672
if(random.choice([0,1])):
668-
pac_claim = gen_pac_version_of_claim(claim)
673+
pac_claim = gen_pac_version_of_claim(claim, max_date)
669674
CLM.append(pac_claim['CLM'])
670675
for line in pac_claim['CLM_LINE']:
671676
CLM_LINE.append(line)

apps/bfd-pipeline/bfd-pipeline-idr/model.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,7 @@ def computed_keys() -> list[str]:
8181

8282
@classmethod
8383
def unique_key(cls) -> list[str]:
84-
return [
85-
key for key in cls.model_fields.keys() if cls._extract_meta(key, PRIMARY_KEY) == True
86-
]
84+
return [key for key in cls.model_fields if cls._extract_meta(key, PRIMARY_KEY)]
8785

8886
@classmethod
8987
def batch_timestamp_col(cls, is_historical: bool) -> str | None:
@@ -870,4 +868,5 @@ def _current_fetch_query() -> str:
870868
"""
871869

872870
def is_historical(self) -> bool:
873-
return self.last_ts <= datetime(2021, 1, 1, tzinfo=UTC)
871+
# 2021-4-18 is the most recent date where idr_insrt_ts could be null in claims data
872+
return self.last_ts <= datetime(2021, 4, 19, tzinfo=UTC)

apps/bfd-pipeline/bfd-pipeline-idr/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies = [
1111
]
1212

1313
[dependency-groups]
14-
dev = ["ruff>=0.9.2", "uv>=0.7.8", "pytest>=8.3.5", "testcontainers>=4.9.2"]
14+
dev = ["ruff>=0.11.11", "uv>=0.7.8", "pytest>=8.3.5", "testcontainers>=4.9.2"]
1515

1616
# [[tool.mypy.overrides]]
1717
# module = ["testcontainers.*"]

apps/bfd-pipeline/bfd-pipeline-idr/test_pipeline.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import time
2-
from datetime import datetime, timezone
2+
from datetime import datetime, timezone, UTC
33
from typing import cast
44

55
import psycopg
@@ -67,7 +67,7 @@ def test_pipeline(self, psql_url: str):
6767
SET bene_mbi_id = '1S000000000', idr_insrt_ts=%(timestamp)s
6868
WHERE bene_sk = 53965935
6969
""",
70-
{"timestamp": datetime.now(timezone.utc)},
70+
{"timestamp": datetime.now(UTC)},
7171
)
7272
conn.commit()
7373
run_pipeline(PostgresExtractor(psql_url, 100_000), psql_url)
@@ -100,43 +100,43 @@ def test_pipeline(self, psql_url: str):
100100
cur = conn.execute("select * from idr.claim order by clm_uniq_id")
101101
assert cur.rowcount == 150
102102
rows = cur.fetchmany(1)
103-
assert rows[0]["clm_uniq_id"] == 99283365695
103+
assert rows[0]["clm_uniq_id"] == 74294264116
104104
assert rows[0]["clm_nrln_ric_cd"] == "V"
105105

106106
cur = conn.execute("select * from idr.claim_institutional order by clm_uniq_id")
107107
assert cur.rowcount == 150
108108
rows = cur.fetchmany(1)
109-
assert rows[0]["clm_uniq_id"] == 99283365695
109+
assert rows[0]["clm_uniq_id"] == 74294264116
110110

111111
cur = conn.execute("select * from idr.claim_date_signature order by clm_dt_sgntr_sk")
112112
assert cur.rowcount == 150
113113
rows = cur.fetchmany(1)
114-
assert rows[0]["clm_dt_sgntr_sk"] == 21539345781
114+
assert rows[0]["clm_dt_sgntr_sk"] == 5123224512
115115

116116
cur = conn.execute("select * from idr.claim_value order by clm_uniq_id")
117-
assert cur.rowcount == 176
117+
assert cur.rowcount == 136
118118
rows = cur.fetchmany(1)
119-
assert rows[0]["clm_uniq_id"] == 99283365695
119+
assert rows[0]["clm_uniq_id"] == 191283812055
120120

121121
cur = conn.execute("select * from idr.claim_line order by clm_uniq_id")
122-
assert cur.rowcount == 1188
122+
assert cur.rowcount == 1160
123123
rows = cur.fetchmany(1)
124-
assert rows[0]["clm_uniq_id"] == 99283365695
124+
assert rows[0]["clm_uniq_id"] == 74294264116
125125

126126
cur = conn.execute("select * from idr.claim_line_institutional order by clm_uniq_id")
127-
assert cur.rowcount == 1188
127+
assert cur.rowcount == 1160
128128
rows = cur.fetchmany(1)
129-
assert rows[0]["clm_uniq_id"] == 99283365695
129+
assert rows[0]["clm_uniq_id"] == 74294264116
130130

131131
cur = conn.execute("select * from idr.claim_ansi_signature order by clm_ansi_sgntr_sk")
132132
assert cur.rowcount == 12072
133133
rows = cur.fetchmany(1)
134134
assert rows[0]["clm_ansi_sgntr_sk"] == 0
135135

136136
cur = conn.execute("select * from idr.claim_procedure order by clm_uniq_id, bfd_row_num")
137-
assert cur.rowcount == 1918
137+
assert cur.rowcount == 2020
138138
rows = cur.fetchmany(1)
139-
assert rows[0]["clm_uniq_id"] == 99283365695
139+
assert rows[0]["clm_uniq_id"] == 74294264116
140140
assert rows[0]["bfd_row_num"] == 1
141141

142142
# TODO: add these back when contract data is added

0 commit comments

Comments
 (0)