mphapi 1.11.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mphapi-1.11.0/PKG-INFO +13 -0
- mphapi-1.11.0/mphapi/__init__.py +5 -0
- mphapi-1.11.0/mphapi/claim.py +374 -0
- mphapi-1.11.0/mphapi/client.py +383 -0
- mphapi-1.11.0/mphapi/client_test.py +114 -0
- mphapi-1.11.0/mphapi/credentials.py +256 -0
- mphapi-1.11.0/mphapi/date.py +125 -0
- mphapi-1.11.0/mphapi/env.py +24 -0
- mphapi-1.11.0/mphapi/fields.py +17 -0
- mphapi-1.11.0/mphapi/pricing.py +558 -0
- mphapi-1.11.0/mphapi/py.typed +0 -0
- mphapi-1.11.0/mphapi/response.py +124 -0
- mphapi-1.11.0/mphapi/snapshots/client_test/test_client/hcfa.json +75 -0
- mphapi-1.11.0/mphapi/snapshots/client_test/test_client/inpatient.json +405 -0
- mphapi-1.11.0/mphapi/snapshots/client_test/test_client/outpatient.json +723 -0
- mphapi-1.11.0/mphapi/testdata/hcfa.json +30 -0
- mphapi-1.11.0/mphapi/testdata/inpatient.json +135 -0
- mphapi-1.11.0/mphapi/testdata/outpatient.json +265 -0
- mphapi-1.11.0/pyproject.toml +24 -0
mphapi-1.11.0/PKG-INFO
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: mphapi
|
|
3
|
+
Version: 1.11.0
|
|
4
|
+
Summary: A Python interface to the MyPriceHealth API
|
|
5
|
+
Author: David Archibald
|
|
6
|
+
Author-email: davidarchibald@myprice.health
|
|
7
|
+
Requires-Python: >=3.12,<4.0
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
11
|
+
Requires-Dist: pydantic (>=2.6.4,<3.0.0)
|
|
12
|
+
Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
|
|
13
|
+
Requires-Dist: requests (>=2.31.0,<3.0.0)
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import decimal
|
|
2
|
+
from enum import Enum, IntEnum
|
|
3
|
+
from typing import Annotated, Any, Optional
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field, GetCoreSchemaHandler
|
|
6
|
+
from pydantic_core import CoreSchema, core_schema
|
|
7
|
+
|
|
8
|
+
from .date import Date
|
|
9
|
+
from .fields import camel_case_model_config, field_name
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FormType(str, Enum):
|
|
13
|
+
"""Type of form used to submit the claim. Can be HCFA or UB-04 (from CLM05_02)"""
|
|
14
|
+
|
|
15
|
+
UB_04 = "UB-04"
|
|
16
|
+
HCFA = "HCFA"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BillTypeSequence(str, Enum):
|
|
20
|
+
"""Where the claim is at in its billing lifecycle (e.g. 0: Non-Pay, 1: Admit Through
|
|
21
|
+
Discharge, 7: Replacement, etc.) (from CLM05_03)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
NON_PAY = "0"
|
|
25
|
+
ADMIT_THROUGH_DISCHARGE = "1"
|
|
26
|
+
FIRST_INTERIM = "2"
|
|
27
|
+
CONTINUING_INTERIM = "3"
|
|
28
|
+
LAST_INTERIM = "4"
|
|
29
|
+
LATE_CHARGE = "5"
|
|
30
|
+
FIRST_INTERIM_DEPRECATED = "6"
|
|
31
|
+
REPLACEMENT = "7"
|
|
32
|
+
VOID_OR_CANCEL = "8"
|
|
33
|
+
FINAL_CLAIM = "9"
|
|
34
|
+
CWF_ADJUSTMENT = "G"
|
|
35
|
+
CMS_ADJUSTMENT = "H"
|
|
36
|
+
INTERMEDIARY_ADJUSTMENT = "I"
|
|
37
|
+
OTHER_ADJUSTMENT = "J"
|
|
38
|
+
OIG_ADJUSTMENT = "K"
|
|
39
|
+
MSP_ADJUSTMENT = "M"
|
|
40
|
+
QIO_ADJUSTMENT = "P"
|
|
41
|
+
PROVIDER_ADJUSTMENT = "Q"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SexType(IntEnum):
|
|
45
|
+
"""Biological sex of the patient for clinical purposes"""
|
|
46
|
+
|
|
47
|
+
UNKNOWN = 0
|
|
48
|
+
MALE = 1
|
|
49
|
+
FEMALE = 2
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class Provider(BaseModel):
|
|
53
|
+
"""
|
|
54
|
+
Provider represents the service provider that rendered healthcare services on behalf of the patient.
|
|
55
|
+
This can be found in Loop 2000A and/or Loop 2310 NM101-77 at the claim level, and may also be overridden at the service level in the 2400 loop
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
model_config = camel_case_model_config
|
|
59
|
+
|
|
60
|
+
npi: str
|
|
61
|
+
"""National Provider Identifier of the provider (from NM109, required)"""
|
|
62
|
+
|
|
63
|
+
ccn: Optional[str] = None
|
|
64
|
+
"""CMS Certification Number (optional)"""
|
|
65
|
+
|
|
66
|
+
provider_tax_id: Annotated[Optional[str], field_name("providerTaxID")] = None
|
|
67
|
+
"""City of the provider (from N401, highly recommended)"""
|
|
68
|
+
|
|
69
|
+
provider_phones: Optional[list[str]] = None
|
|
70
|
+
"""Address line 1 of the provider (from N301, highly recommended)"""
|
|
71
|
+
|
|
72
|
+
provider_faxes: Optional[list[str]] = None
|
|
73
|
+
"""Commercial number of the provider used by some payers (from REF G2, optional)"""
|
|
74
|
+
|
|
75
|
+
provider_emails: Optional[list[str]] = None
|
|
76
|
+
"""State license number of the provider (from REF 0B, optional)"""
|
|
77
|
+
|
|
78
|
+
provider_license_number: Optional[str] = None
|
|
79
|
+
"""Last name of the provider (from NM103, highly recommended)"""
|
|
80
|
+
|
|
81
|
+
provider_commercial_number: Optional[str] = None
|
|
82
|
+
"""Email addresses of the provider (from PER, optional)"""
|
|
83
|
+
|
|
84
|
+
provider_taxonomy: Optional[str] = None
|
|
85
|
+
"""State of the provider (from N402, highly recommended)"""
|
|
86
|
+
|
|
87
|
+
provider_first_name: Optional[str] = None
|
|
88
|
+
"""Taxonomy code of the provider (from PRV03, highly recommended)"""
|
|
89
|
+
|
|
90
|
+
provider_last_name: Optional[str] = None
|
|
91
|
+
"""First name of the provider (NM104, highly recommended)"""
|
|
92
|
+
|
|
93
|
+
provider_org_name: Optional[str] = None
|
|
94
|
+
"""Organization name of the provider (from NM103, highly recommended)"""
|
|
95
|
+
|
|
96
|
+
provider_address1: Optional[str] = None
|
|
97
|
+
"""Tax ID of the provider (from REF highly recommended)"""
|
|
98
|
+
|
|
99
|
+
provider_address2: Optional[str] = None
|
|
100
|
+
"""Phone numbers of the provider (from PER, optional)"""
|
|
101
|
+
|
|
102
|
+
provider_city: Optional[str] = None
|
|
103
|
+
"""Fax numbers of the provider (from PER, optional)"""
|
|
104
|
+
|
|
105
|
+
provider_state: Optional[str] = None
|
|
106
|
+
"""Address line 2 of the provider (from N302, optional)"""
|
|
107
|
+
|
|
108
|
+
provider_zip: Annotated[Optional[str], field_name("providerZIP")] = None
|
|
109
|
+
"""ZIP code of the provider (from N403, required)"""
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class Decimal:
|
|
113
|
+
"""
|
|
114
|
+
An arbitrary precision number.
|
|
115
|
+
When deserializing it allows to deserialize from a float, str, or int.
|
|
116
|
+
When serialized it always serializes to a str to prevent loss of precision.
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
# Python has an arbitrary precision number built in that this type is just a thin wrapper around.
|
|
120
|
+
value: decimal.Decimal
|
|
121
|
+
|
|
122
|
+
def __init__(self, value: decimal.Decimal):
|
|
123
|
+
self.value = value
|
|
124
|
+
|
|
125
|
+
def __str__(self) -> str:
|
|
126
|
+
return str(self.value)
|
|
127
|
+
|
|
128
|
+
# Based off of this: https://docs.pydantic.dev/2.1/usage/types/custom/#handling-third-party-types
|
|
129
|
+
@classmethod
|
|
130
|
+
def __get_pydantic_core_schema__(
|
|
131
|
+
cls, source_type: Any, handler: GetCoreSchemaHandler
|
|
132
|
+
) -> CoreSchema:
|
|
133
|
+
def to_decimal(value: float | int | str | decimal.Decimal) -> Decimal:
|
|
134
|
+
return Decimal(decimal.Decimal(value))
|
|
135
|
+
|
|
136
|
+
from_value = core_schema.chain_schema(
|
|
137
|
+
[
|
|
138
|
+
core_schema.union_schema(
|
|
139
|
+
[
|
|
140
|
+
core_schema.str_schema(),
|
|
141
|
+
core_schema.is_instance_schema(decimal.Decimal),
|
|
142
|
+
core_schema.float_schema(),
|
|
143
|
+
core_schema.int_schema(),
|
|
144
|
+
]
|
|
145
|
+
),
|
|
146
|
+
core_schema.no_info_plain_validator_function(to_decimal),
|
|
147
|
+
]
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return core_schema.json_or_python_schema(
|
|
151
|
+
json_schema=from_value,
|
|
152
|
+
python_schema=core_schema.union_schema(
|
|
153
|
+
[
|
|
154
|
+
core_schema.is_instance_schema(Decimal),
|
|
155
|
+
from_value,
|
|
156
|
+
]
|
|
157
|
+
),
|
|
158
|
+
serialization=core_schema.plain_serializer_function_ser_schema(
|
|
159
|
+
lambda decimal: str(decimal)
|
|
160
|
+
),
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class ValueCode(BaseModel):
|
|
165
|
+
model_config = camel_case_model_config
|
|
166
|
+
|
|
167
|
+
code: str
|
|
168
|
+
"""Code indicating the type of value provided (from HIxx_02)"""
|
|
169
|
+
|
|
170
|
+
amount: Decimal
|
|
171
|
+
"""Amount associated with the value code (from HIxx_05)"""
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class Diagnosis(BaseModel):
|
|
175
|
+
"""Principal, Other Diagnosis, Admitting Diagnosis, External Cause of Injury"""
|
|
176
|
+
|
|
177
|
+
model_config = camel_case_model_config
|
|
178
|
+
|
|
179
|
+
code: str
|
|
180
|
+
"""ICD-10 diagnosis code (from HIxx_02)"""
|
|
181
|
+
|
|
182
|
+
present_on_admission: Optional[str] = None
|
|
183
|
+
"""Flag indicates whether diagnosis was present at the time of admission (from HIxx_09)"""
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class Service(BaseModel):
|
|
187
|
+
model_config = camel_case_model_config
|
|
188
|
+
|
|
189
|
+
provider: Optional[Provider] = None
|
|
190
|
+
"""Additional provider information specific to this service item"""
|
|
191
|
+
|
|
192
|
+
line_number: Optional[str] = None
|
|
193
|
+
"""Unique line number for the service item (from LX01)"""
|
|
194
|
+
|
|
195
|
+
rev_code: Optional[str] = None
|
|
196
|
+
"""Revenue code (from SV2_01)"""
|
|
197
|
+
|
|
198
|
+
procedure_code: Optional[str] = None
|
|
199
|
+
"""Procedure code (from SV101_02 / SV202_02)"""
|
|
200
|
+
|
|
201
|
+
procedure_modifiers: Optional[list[str]] = None
|
|
202
|
+
"""Procedure modifiers (from SV101_03, 4, 5, 6 / SV202_03, 4, 5, 6)"""
|
|
203
|
+
|
|
204
|
+
drug_code: Optional[str] = None
|
|
205
|
+
"""National Drug Code (from LIN03)"""
|
|
206
|
+
|
|
207
|
+
date_from: Optional[Date] = None
|
|
208
|
+
"""Begin date of service (from DTP 472)"""
|
|
209
|
+
|
|
210
|
+
date_through: Optional[Date] = None
|
|
211
|
+
"""End date of service (from DTP 472)"""
|
|
212
|
+
|
|
213
|
+
billed_amount: Optional[float] = None
|
|
214
|
+
"""Billed charge for the service (from SV102 / SV203)"""
|
|
215
|
+
|
|
216
|
+
allowed_amount: Optional[float] = None
|
|
217
|
+
"""Plan allowed amount for the service (non-EDI)"""
|
|
218
|
+
|
|
219
|
+
paid_amount: Optional[float] = None
|
|
220
|
+
"""Plan paid amount for the service (non-EDI)"""
|
|
221
|
+
|
|
222
|
+
quantity: Optional[float] = None
|
|
223
|
+
"""Quantity of the service (from SV104 / SV205)"""
|
|
224
|
+
|
|
225
|
+
units: Optional[str] = None
|
|
226
|
+
"""Units connected to the quantity given (from SV103 / SV204)"""
|
|
227
|
+
|
|
228
|
+
place_of_service: Optional[str] = None
|
|
229
|
+
"""Place of service code (from SV105)"""
|
|
230
|
+
|
|
231
|
+
ambulance_pickup_zip: Annotated[Optional[str], field_name("ambulancePickupZIP")] = (
|
|
232
|
+
None
|
|
233
|
+
)
|
|
234
|
+
"""ZIP code where ambulance picked up patient. Supplied if different than claim-level value (from NM1 PW)"""
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class Claim(Provider, BaseModel):
|
|
238
|
+
model_config = camel_case_model_config
|
|
239
|
+
|
|
240
|
+
claim_id: Annotated[Optional[str], field_name("claimID")] = None
|
|
241
|
+
"""Unique identifier for the claim (from REF D9)"""
|
|
242
|
+
|
|
243
|
+
plan_code: Optional[str] = None
|
|
244
|
+
"""Identifies the subscriber's plan (from SBR03)"""
|
|
245
|
+
|
|
246
|
+
patient_sex: Optional[SexType] = None
|
|
247
|
+
"""Biological sex of the patient for clinical purposes (from DMG02). 0:Unknown, 1:Male,
|
|
248
|
+
2:Female
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
patient_date_of_birth: Optional[Date] = None
|
|
252
|
+
"""Patient date of birth (from DMG03)"""
|
|
253
|
+
|
|
254
|
+
patient_height_in_cm: Annotated[
|
|
255
|
+
Optional[float], field_name("patientHeightInCM")
|
|
256
|
+
] = None
|
|
257
|
+
"""Patient height in centimeters (from HI value A9, MEA value HT)"""
|
|
258
|
+
|
|
259
|
+
patient_weight_in_kg: Annotated[
|
|
260
|
+
Optional[float], field_name("patientWeightInKG")
|
|
261
|
+
] = None
|
|
262
|
+
"""Patient weight in kilograms (from HI value A8, PAT08, CR102 [ambulance only])"""
|
|
263
|
+
|
|
264
|
+
ambulance_pickup_zip: Annotated[Optional[str], field_name("ambulancePickupZIP")] = (
|
|
265
|
+
None
|
|
266
|
+
)
|
|
267
|
+
"""Location where patient was picked up in ambulance (from HI with HIxx_01=BE and HIxx_02=A0
|
|
268
|
+
or NM1 loop with NM1 PW)
|
|
269
|
+
"""
|
|
270
|
+
|
|
271
|
+
form_type: Optional[FormType] = None
|
|
272
|
+
"""Type of form used to submit the claim. Can be HCFA or UB-04 (from CLM05_02)"""
|
|
273
|
+
|
|
274
|
+
bill_type_or_pos: Annotated[Optional[str], field_name("billTypeOrPOS")] = None
|
|
275
|
+
"""Describes type of facility where services were rendered (from CLM05_01)"""
|
|
276
|
+
|
|
277
|
+
bill_type_sequence: Optional[BillTypeSequence] = None
|
|
278
|
+
"""Where the claim is at in its billing lifecycle (e.g. 0: Non-Pay, 1: Admit Through Discharge, 7: Replacement, etc.) (from CLM05_03)"""
|
|
279
|
+
|
|
280
|
+
billed_amount: Optional[float] = None
|
|
281
|
+
"""Billed amount from provider (from CLM02)"""
|
|
282
|
+
|
|
283
|
+
allowed_amount: Optional[float] = None
|
|
284
|
+
"""Amount allowed by the plan for payment. Both member and plan responsibility (non-EDI)"""
|
|
285
|
+
|
|
286
|
+
paid_amount: Optional[float] = None
|
|
287
|
+
"""Amount paid by the plan for the claim (non-EDI)"""
|
|
288
|
+
|
|
289
|
+
date_from: Optional[Date] = None
|
|
290
|
+
"""Earliest service date among services, or statement date if not found"""
|
|
291
|
+
|
|
292
|
+
date_through: Optional[Date] = None
|
|
293
|
+
"""Latest service date among services, or statement date if not found"""
|
|
294
|
+
|
|
295
|
+
discharge_status: Optional[str] = None
|
|
296
|
+
"""Status of the patient at time of discharge (from CL103)"""
|
|
297
|
+
|
|
298
|
+
admit_diagnosis: Optional[str] = None
|
|
299
|
+
"""ICD diagnosis at the time the patient was admitted (from HI ABJ or BJ)"""
|
|
300
|
+
|
|
301
|
+
principal_diagnosis: Optional[Diagnosis] = None
|
|
302
|
+
"""Principal ICD diagnosis for the patient (from HI ABK or BK)"""
|
|
303
|
+
|
|
304
|
+
other_diagnoses: Optional[list[Diagnosis]] = None
|
|
305
|
+
"""Other ICD diagnoses that apply to the patient (from HI ABF or BF)"""
|
|
306
|
+
|
|
307
|
+
principal_procedure: Optional[str] = None
|
|
308
|
+
"""Principal ICD procedure for the patient (from HI BBR or BR)"""
|
|
309
|
+
|
|
310
|
+
other_procedures: Optional[list[str]] = None
|
|
311
|
+
"""Other ICD procedures that apply to the patient (from HI BBQ or BQ)"""
|
|
312
|
+
|
|
313
|
+
condition_codes: Optional[list[str]] = None
|
|
314
|
+
"""Special conditions that may affect payment or other processing (from HI BG)"""
|
|
315
|
+
|
|
316
|
+
value_codes: Optional[list[ValueCode]] = None
|
|
317
|
+
"""Numeric values related to the patient or claim (HI BE)"""
|
|
318
|
+
|
|
319
|
+
occurrence_codes: Optional[list[str]] = None
|
|
320
|
+
"""Date related occurrences related to the patient or claim (from HI BH)"""
|
|
321
|
+
|
|
322
|
+
drg: Optional[str] = None
|
|
323
|
+
"""Diagnosis Related Group for inpatient services (from HI DR)"""
|
|
324
|
+
|
|
325
|
+
services: list[Service] = Field(min_length=1)
|
|
326
|
+
"""One or more services provided to the patient (from LX loop)"""
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class RateSheetService(BaseModel):
|
|
330
|
+
model_config = camel_case_model_config
|
|
331
|
+
|
|
332
|
+
procedure_code: Optional[str] = None
|
|
333
|
+
"""Procedure code (from SV101_02 / SV202_02)"""
|
|
334
|
+
|
|
335
|
+
procedure_modifiers: Optional[list[str]] = None
|
|
336
|
+
"""Procedure modifiers (from SV101_03, 4, 5, 6 / SV202_03, 4, 5, 6)"""
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class RateSheet(BaseModel):
|
|
340
|
+
npi: str
|
|
341
|
+
"""National Provider Identifier of the provider (from NM109, required)"""
|
|
342
|
+
|
|
343
|
+
provider_first_name: Optional[str] = None
|
|
344
|
+
"""First name of the provider (NM104, highly recommended)"""
|
|
345
|
+
|
|
346
|
+
provider_last_name: Optional[str] = None
|
|
347
|
+
"""Last name of the provider (from NM103, highly recommended)"""
|
|
348
|
+
|
|
349
|
+
provider_org_name: Optional[str] = None
|
|
350
|
+
"""Organization name of the provider (from NM103, highly recommended)"""
|
|
351
|
+
|
|
352
|
+
provider_address: Optional[str] = None
|
|
353
|
+
"""Address of the provider (from N301, highly recommended)"""
|
|
354
|
+
|
|
355
|
+
provider_city: Optional[str] = None
|
|
356
|
+
"""City of the provider (from N401, highly recommended)"""
|
|
357
|
+
|
|
358
|
+
provider_state: Optional[str] = None
|
|
359
|
+
"""State of the provider (from N402, highly recommended)"""
|
|
360
|
+
|
|
361
|
+
provider_zip: Annotated[str, field_name("providerZIP")]
|
|
362
|
+
"""ZIP code of the provider (from N403, required)"""
|
|
363
|
+
|
|
364
|
+
form_type: Optional[FormType] = None
|
|
365
|
+
"""Type of form used to submit the claim. Can be HCFA or UB-04 (from CLM05_02)"""
|
|
366
|
+
|
|
367
|
+
bill_type_or_pos: Annotated[Optional[str], field_name("billTypeOrPOS")] = None
|
|
368
|
+
"""Describes type of facility where services were rendered (from CLM05_01)"""
|
|
369
|
+
|
|
370
|
+
drg: Optional[str] = None
|
|
371
|
+
"""Diagnosis Related Group for inpatient services (from HI DR)"""
|
|
372
|
+
|
|
373
|
+
services: Optional[list[RateSheetService]] = None
|
|
374
|
+
"""One or more services provided to the patient (from LX loop)"""
|