mphapi 0.4.1__tar.gz → 0.4.3__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-0.4.1 → mphapi-0.4.3}/PKG-INFO +1 -1
- {mphapi-0.4.1 → mphapi-0.4.3}/mphapi/claim.py +58 -7
- {mphapi-0.4.1 → mphapi-0.4.3}/mphapi/client.py +24 -0
- {mphapi-0.4.1 → mphapi-0.4.3}/mphapi/pricing.py +95 -20
- {mphapi-0.4.1 → mphapi-0.4.3}/pyproject.toml +1 -1
- {mphapi-0.4.1 → mphapi-0.4.3}/mphapi/__init__.py +0 -0
- {mphapi-0.4.1 → mphapi-0.4.3}/mphapi/date.py +0 -0
- {mphapi-0.4.1 → mphapi-0.4.3}/mphapi/fields.py +0 -0
- {mphapi-0.4.1 → mphapi-0.4.3}/mphapi/response.py +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import decimal
|
|
1
2
|
from enum import Enum, IntEnum
|
|
2
|
-
from typing import Annotated, Optional
|
|
3
|
+
from typing import Annotated, Any, Optional
|
|
3
4
|
|
|
4
|
-
from pydantic import BaseModel, Field
|
|
5
|
+
from pydantic import BaseModel, Field, GetCoreSchemaHandler
|
|
6
|
+
from pydantic_core import CoreSchema, core_schema
|
|
5
7
|
|
|
6
8
|
from .date import Date
|
|
7
9
|
from .fields import camel_case_model_config, field_name
|
|
@@ -100,17 +102,69 @@ class Provider(BaseModel):
|
|
|
100
102
|
provider_state: Optional[str] = None
|
|
101
103
|
"""Address line 2 of the provider (from N302, optional)"""
|
|
102
104
|
|
|
103
|
-
provider_zip: Annotated[str, field_name("providerZIP")]
|
|
105
|
+
provider_zip: Annotated[Optional[str], field_name("providerZIP")] = None
|
|
104
106
|
"""ZIP code of the provider (from N403, required)"""
|
|
105
107
|
|
|
106
108
|
|
|
109
|
+
class Decimal:
|
|
110
|
+
"""
|
|
111
|
+
An arbitrary precision number.
|
|
112
|
+
When deserializing it allows to deserialize from a float, str, or int.
|
|
113
|
+
When serialized it always serializes to a str to prevent loss of precision.
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
# Python has an arbitrary precision number built in that this type is just a thin wrapper around.
|
|
117
|
+
value: decimal.Decimal
|
|
118
|
+
|
|
119
|
+
def __init__(self, value: decimal.Decimal):
|
|
120
|
+
self.value = value
|
|
121
|
+
|
|
122
|
+
def __str__(self) -> str:
|
|
123
|
+
return str(self.value)
|
|
124
|
+
|
|
125
|
+
# Based off of this: https://docs.pydantic.dev/2.1/usage/types/custom/#handling-third-party-types
|
|
126
|
+
@classmethod
|
|
127
|
+
def __get_pydantic_core_schema__(
|
|
128
|
+
cls, source_type: Any, handler: GetCoreSchemaHandler
|
|
129
|
+
) -> CoreSchema:
|
|
130
|
+
def to_decimal(value: float | int | str | decimal.Decimal) -> Decimal:
|
|
131
|
+
return Decimal(decimal.Decimal(value))
|
|
132
|
+
|
|
133
|
+
from_value = core_schema.chain_schema(
|
|
134
|
+
[
|
|
135
|
+
core_schema.union_schema(
|
|
136
|
+
[
|
|
137
|
+
core_schema.str_schema(),
|
|
138
|
+
core_schema.is_instance_schema(decimal.Decimal),
|
|
139
|
+
core_schema.float_schema(),
|
|
140
|
+
core_schema.int_schema(),
|
|
141
|
+
]
|
|
142
|
+
),
|
|
143
|
+
core_schema.no_info_plain_validator_function(to_decimal),
|
|
144
|
+
]
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return core_schema.json_or_python_schema(
|
|
148
|
+
json_schema=from_value,
|
|
149
|
+
python_schema=core_schema.union_schema(
|
|
150
|
+
[
|
|
151
|
+
core_schema.is_instance_schema(Decimal),
|
|
152
|
+
from_value,
|
|
153
|
+
]
|
|
154
|
+
),
|
|
155
|
+
serialization=core_schema.plain_serializer_function_ser_schema(
|
|
156
|
+
lambda decimal: str(decimal)
|
|
157
|
+
),
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
107
161
|
class ValueCode(BaseModel):
|
|
108
162
|
model_config = camel_case_model_config
|
|
109
163
|
|
|
110
164
|
code: str
|
|
111
165
|
"""Code indicating the type of value provided (from HIxx_02)"""
|
|
112
166
|
|
|
113
|
-
amount:
|
|
167
|
+
amount: Decimal
|
|
114
168
|
"""Amount associated with the value code (from HIxx_05)"""
|
|
115
169
|
|
|
116
170
|
|
|
@@ -173,9 +227,6 @@ class Service(BaseModel):
|
|
|
173
227
|
place_of_service: Optional[str] = None
|
|
174
228
|
"""Place of service code (from SV105)"""
|
|
175
229
|
|
|
176
|
-
diagnosis_pointers: Optional[list[int]] = None
|
|
177
|
-
"""Diagnosis pointers (from SV107)"""
|
|
178
|
-
|
|
179
230
|
ambulance_pickup_zip: Annotated[Optional[str], field_name("ambulancePickupZIP")] = (
|
|
180
231
|
None
|
|
181
232
|
)
|
|
@@ -14,6 +14,9 @@ Header = Mapping[str, str | bytes | None]
|
|
|
14
14
|
class PriceConfig(BaseModel):
|
|
15
15
|
"""PriceConfig is used to configure the behavior of the pricing API"""
|
|
16
16
|
|
|
17
|
+
price_zero_billed: StrictBool
|
|
18
|
+
"""set to true to price claims with zero billed amounts (default is false)"""
|
|
19
|
+
|
|
17
20
|
is_commercial: StrictBool
|
|
18
21
|
"""set to true to use commercial code crosswalks"""
|
|
19
22
|
|
|
@@ -35,6 +38,15 @@ class PriceConfig(BaseModel):
|
|
|
35
38
|
include_edits: StrictBool
|
|
36
39
|
"""set to true to include edit details in the response"""
|
|
37
40
|
|
|
41
|
+
continue_on_edit_fail: StrictBool
|
|
42
|
+
"""set to true to continue to price the claim even if there are edit failures"""
|
|
43
|
+
|
|
44
|
+
continue_on_provider_match_fail: StrictBool
|
|
45
|
+
"""set to true to continue with a average provider for the geographic area if the provider cannot be matched"""
|
|
46
|
+
|
|
47
|
+
disable_machine_learning_estimates: StrictBool
|
|
48
|
+
"""set to true to disable machine learning estimates (applies to estimates only)"""
|
|
49
|
+
|
|
38
50
|
|
|
39
51
|
class Client:
|
|
40
52
|
url: str
|
|
@@ -191,6 +203,9 @@ class Client:
|
|
|
191
203
|
|
|
192
204
|
def _get_price_headers(self, config: PriceConfig) -> Header:
|
|
193
205
|
headers: Header = {}
|
|
206
|
+
if config.price_zero_billed:
|
|
207
|
+
headers["price-zero-billed"] = "true"
|
|
208
|
+
|
|
194
209
|
if config.is_commercial:
|
|
195
210
|
headers["is-commercial"] = "true"
|
|
196
211
|
|
|
@@ -212,4 +227,13 @@ class Client:
|
|
|
212
227
|
if config.use_best_drg_price:
|
|
213
228
|
headers["use-best-drg-price"] = "true"
|
|
214
229
|
|
|
230
|
+
if config.continue_on_edit_fail:
|
|
231
|
+
headers["continue-on-edit-fail"] = "true"
|
|
232
|
+
|
|
233
|
+
if config.continue_on_provider_match_fail:
|
|
234
|
+
headers["continue-on-provider-match-fail"] = "true"
|
|
235
|
+
|
|
236
|
+
if config.disable_machine_learning_estimates:
|
|
237
|
+
headers["disable-machine-learning-estimates"] = "true"
|
|
238
|
+
|
|
215
239
|
return headers
|
|
@@ -52,6 +52,28 @@ class RuralIndicator(str, Enum):
|
|
|
52
52
|
URBAN = ""
|
|
53
53
|
|
|
54
54
|
|
|
55
|
+
class MedicareSource(str, Enum):
|
|
56
|
+
Ambulance = "AmbulanceFS"
|
|
57
|
+
Anesthesia = "AnesthesiaFS"
|
|
58
|
+
CriticalAccessHospital = "CAH pricer"
|
|
59
|
+
Drugs = "DrugsFS"
|
|
60
|
+
EditError = "Claim editor"
|
|
61
|
+
EstimateByCodeOnly = "CodeOnly"
|
|
62
|
+
EstimateByLocalityCode = "LocalityCode"
|
|
63
|
+
EstimateByLocalityOnly = "LocalityOnly"
|
|
64
|
+
EstimateByNational = "National"
|
|
65
|
+
EstimateByStateCode = "StateCode"
|
|
66
|
+
EstimateByStateOnly = "StateOnly"
|
|
67
|
+
EstimateByUnknown = "Unknown"
|
|
68
|
+
Inpatient = "IPPS"
|
|
69
|
+
Labs = "LabsFS"
|
|
70
|
+
MPFS = "MPFS"
|
|
71
|
+
Outpatient = "Outpatient pricer"
|
|
72
|
+
ManualPricing = "Manual Pricing"
|
|
73
|
+
SNF = "SNF PPS"
|
|
74
|
+
Synthetic = "Synthetic Medicare"
|
|
75
|
+
|
|
76
|
+
|
|
55
77
|
class InpatientPriceDetail(BaseModel):
|
|
56
78
|
"""InpatientPriceDetail contains pricing details for an inpatient claim"""
|
|
57
79
|
|
|
@@ -84,36 +106,42 @@ class InpatientPriceDetail(BaseModel):
|
|
|
84
106
|
value_based_purchasing_amount: Optional[float] = None
|
|
85
107
|
"""Adjustment for hospitals based on quality measures"""
|
|
86
108
|
|
|
109
|
+
wage_index: Optional[float] = None
|
|
110
|
+
"""Wage index used for geographic adjustment"""
|
|
111
|
+
|
|
87
112
|
|
|
88
113
|
class OutpatientPriceDetail(BaseModel):
|
|
89
114
|
"""OutpatientPriceDetail contains pricing details for an outpatient claim"""
|
|
90
115
|
|
|
91
116
|
model_config = camel_case_model_config
|
|
92
117
|
|
|
93
|
-
outlier_amount: float
|
|
118
|
+
outlier_amount: Optional[float] = None
|
|
94
119
|
"""Additional amount paid for high cost cases"""
|
|
95
120
|
|
|
96
|
-
first_passthrough_drug_offset_amount: float
|
|
121
|
+
first_passthrough_drug_offset_amount: Optional[float] = None
|
|
97
122
|
"""Amount built into the APC payment for certain drugs"""
|
|
98
123
|
|
|
99
|
-
second_passthrough_drug_offset_amount: float
|
|
124
|
+
second_passthrough_drug_offset_amount: Optional[float] = None
|
|
100
125
|
"""Amount built into the APC payment for certain drugs"""
|
|
101
126
|
|
|
102
|
-
third_passthrough_drug_offset_amount: float
|
|
127
|
+
third_passthrough_drug_offset_amount: Optional[float] = None
|
|
103
128
|
"""Amount built into the APC payment for certain drugs"""
|
|
104
129
|
|
|
105
|
-
first_device_offset_amount: float
|
|
130
|
+
first_device_offset_amount: Optional[float] = None
|
|
106
131
|
"""Amount built into the APC payment for certain devices"""
|
|
107
132
|
|
|
108
|
-
second_device_offset_amount: float
|
|
133
|
+
second_device_offset_amount: Optional[float] = None
|
|
109
134
|
"""Amount built into the APC payment for certain devices"""
|
|
110
135
|
|
|
111
|
-
full_or_partial_device_credit_offset_amount: float
|
|
136
|
+
full_or_partial_device_credit_offset_amount: Optional[float] = None
|
|
112
137
|
"""Credit for devices that are supplied for free or at a reduced cost"""
|
|
113
138
|
|
|
114
|
-
terminated_device_procedure_offset_amount: float
|
|
139
|
+
terminated_device_procedure_offset_amount: Optional[float] = None
|
|
115
140
|
"""Credit for devices that are not used due to a terminated procedure"""
|
|
116
141
|
|
|
142
|
+
wage_index: Optional[float] = None
|
|
143
|
+
"""Wage index used for geographic adjustment"""
|
|
144
|
+
|
|
117
145
|
|
|
118
146
|
class ProviderDetail(BaseModel):
|
|
119
147
|
"""
|
|
@@ -148,19 +176,47 @@ class ClaimEdits(BaseModel):
|
|
|
148
176
|
|
|
149
177
|
model_config = camel_case_model_config
|
|
150
178
|
|
|
179
|
+
hcp_deny_code: Optional[str] = None
|
|
180
|
+
"""The deny code that will be placed into the HCP13 data element for EDI 837 claims"""
|
|
181
|
+
|
|
151
182
|
claim_overall_disposition: Optional[str] = None
|
|
183
|
+
"""Overall explanation of why the claim edit failed"""
|
|
184
|
+
|
|
152
185
|
claim_rejection_disposition: Optional[str] = None
|
|
186
|
+
"""Explanation of why the claim was rejected"""
|
|
187
|
+
|
|
153
188
|
claim_denial_disposition: Optional[str] = None
|
|
189
|
+
"""Explanation of why the claim was denied"""
|
|
190
|
+
|
|
154
191
|
claim_return_to_provider_disposition: Optional[str] = None
|
|
192
|
+
"""Explanation of why the claim should be returned to provider"""
|
|
193
|
+
|
|
155
194
|
claim_suspension_disposition: Optional[str] = None
|
|
195
|
+
"""Explanation of why the claim was suspended"""
|
|
196
|
+
|
|
156
197
|
line_item_rejection_disposition: Optional[str] = None
|
|
198
|
+
"""Explanation of why the line item was rejected"""
|
|
199
|
+
|
|
157
200
|
line_item_denial_disposition: Optional[str] = None
|
|
201
|
+
"""Explanation of why the line item was denied"""
|
|
202
|
+
|
|
158
203
|
claim_rejection_reasons: Optional[list[str]] = None
|
|
204
|
+
"""Detailed reason(s) describing why the claim was rejected"""
|
|
205
|
+
|
|
159
206
|
claim_denial_reasons: Optional[list[str]] = None
|
|
207
|
+
"""Detailed reason(s) describing why the claim was denied"""
|
|
208
|
+
|
|
160
209
|
claim_return_to_provider_reasons: Optional[list[str]] = None
|
|
210
|
+
"""Detailed reason(s) describing why the claim should be returned to provider"""
|
|
211
|
+
|
|
161
212
|
claim_suspension_reasons: Optional[list[str]] = None
|
|
213
|
+
"""Detailed reason(s) describing why the claim was suspended"""
|
|
214
|
+
|
|
162
215
|
line_item_rejection_reasons: Optional[list[str]] = None
|
|
216
|
+
"""Detailed reason(s) describing why the line item was rejected"""
|
|
217
|
+
|
|
163
218
|
line_item_denial_reasons: Optional[list[str]] = None
|
|
219
|
+
"""Detailed reason(s) describing why the line item was denied"""
|
|
164
220
|
|
|
165
221
|
|
|
166
222
|
class LineEdits(BaseModel):
|
|
@@ -168,16 +224,35 @@ class LineEdits(BaseModel):
|
|
|
168
224
|
|
|
169
225
|
model_config = camel_case_model_config
|
|
170
226
|
|
|
171
|
-
denial_or_rejection_text: str
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
227
|
+
denial_or_rejection_text: Optional[str] = None
|
|
228
|
+
"""The overall explanation for why this line item was denied or rejected by the claim editor"""
|
|
229
|
+
|
|
230
|
+
procedure_edits: Optional[list[str]] = None
|
|
231
|
+
"""Detailed description of each procedure code edit error (from outpatient editor)"""
|
|
232
|
+
|
|
233
|
+
modifier1_edits: Optional[list[str]] = None
|
|
234
|
+
"""Detailed description of each edit error for the first procedure code modifier (from outpatient editor)"""
|
|
235
|
+
|
|
236
|
+
modifier2_edits: Optional[list[str]] = None
|
|
237
|
+
"""Detailed description of each edit error for the second procedure code modifier (from outpatient editor)"""
|
|
238
|
+
|
|
239
|
+
modifier3_edits: Optional[list[str]] = None
|
|
240
|
+
"""Detailed description of each edit error for the third procedure code modifier (from outpatient editor)"""
|
|
241
|
+
|
|
242
|
+
modifier4_edits: Optional[list[str]] = None
|
|
243
|
+
"""Detailed description of each edit error for the fourth procedure code modifier (from outpatient editor)"""
|
|
244
|
+
|
|
245
|
+
modifier5_edits: Optional[list[str]] = None
|
|
246
|
+
"""Detailed description of each edit error for the fifth procedure code modifier (from outpatient editor)"""
|
|
247
|
+
|
|
248
|
+
data_edits: Optional[list[str]] = None
|
|
249
|
+
"""Detailed description of each data edit error (from outpatient editor)"""
|
|
250
|
+
|
|
251
|
+
revenue_edits: Optional[list[str]] = None
|
|
252
|
+
"""Detailed description of each revenue code edit error (from outpatient editor)"""
|
|
253
|
+
|
|
254
|
+
professional_edits: Optional[list[str]] = None
|
|
255
|
+
"""Detailed description of each professional claim edit error"""
|
|
181
256
|
|
|
182
257
|
|
|
183
258
|
class PricedService(BaseModel):
|
|
@@ -218,7 +293,7 @@ class PricedService(BaseModel):
|
|
|
218
293
|
medicare_std_dev: Optional[float] = None
|
|
219
294
|
"""Standard deviation of the estimated Medicare amount (estimates service only)"""
|
|
220
295
|
|
|
221
|
-
medicare_source: Optional[
|
|
296
|
+
medicare_source: Optional[MedicareSource] = None
|
|
222
297
|
"""Source of the Medicare amount (e.g. physician fee schedule, OPPS, etc.)"""
|
|
223
298
|
|
|
224
299
|
pricer_result: Optional[str] = None
|
|
@@ -266,7 +341,7 @@ class Pricing(BaseModel):
|
|
|
266
341
|
medicare_std_dev: Optional[float] = None
|
|
267
342
|
"""The standard deviation of the estimated Medicare amount (estimates service only)"""
|
|
268
343
|
|
|
269
|
-
medicare_source: Optional[
|
|
344
|
+
medicare_source: Optional[MedicareSource] = None
|
|
270
345
|
"""Source of the Medicare amount (e.g. physician fee schedule, OPPS, etc.)"""
|
|
271
346
|
|
|
272
347
|
inpatient_price_detail: Optional[InpatientPriceDetail] = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|