mphapi 0.4.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mphapi
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: A Python interface to the MyPriceHealth API
5
5
  Author: David Archibald
6
6
  Author-email: davidarchibald@myprice.health
@@ -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: float
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
 
@@ -93,28 +115,28 @@ class OutpatientPriceDetail(BaseModel):
93
115
 
94
116
  model_config = camel_case_model_config
95
117
 
96
- outlier_amount: float
118
+ outlier_amount: Optional[float] = None
97
119
  """Additional amount paid for high cost cases"""
98
120
 
99
- first_passthrough_drug_offset_amount: float
121
+ first_passthrough_drug_offset_amount: Optional[float] = None
100
122
  """Amount built into the APC payment for certain drugs"""
101
123
 
102
- second_passthrough_drug_offset_amount: float
124
+ second_passthrough_drug_offset_amount: Optional[float] = None
103
125
  """Amount built into the APC payment for certain drugs"""
104
126
 
105
- third_passthrough_drug_offset_amount: float
127
+ third_passthrough_drug_offset_amount: Optional[float] = None
106
128
  """Amount built into the APC payment for certain drugs"""
107
129
 
108
- first_device_offset_amount: float
130
+ first_device_offset_amount: Optional[float] = None
109
131
  """Amount built into the APC payment for certain devices"""
110
132
 
111
- second_device_offset_amount: float
133
+ second_device_offset_amount: Optional[float] = None
112
134
  """Amount built into the APC payment for certain devices"""
113
135
 
114
- full_or_partial_device_credit_offset_amount: float
136
+ full_or_partial_device_credit_offset_amount: Optional[float] = None
115
137
  """Credit for devices that are supplied for free or at a reduced cost"""
116
138
 
117
- terminated_device_procedure_offset_amount: float
139
+ terminated_device_procedure_offset_amount: Optional[float] = None
118
140
  """Credit for devices that are not used due to a terminated procedure"""
119
141
 
120
142
  wage_index: Optional[float] = None
@@ -154,19 +176,47 @@ class ClaimEdits(BaseModel):
154
176
 
155
177
  model_config = camel_case_model_config
156
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
+
157
182
  claim_overall_disposition: Optional[str] = None
183
+ """Overall explanation of why the claim edit failed"""
184
+
158
185
  claim_rejection_disposition: Optional[str] = None
186
+ """Explanation of why the claim was rejected"""
187
+
159
188
  claim_denial_disposition: Optional[str] = None
189
+ """Explanation of why the claim was denied"""
190
+
160
191
  claim_return_to_provider_disposition: Optional[str] = None
192
+ """Explanation of why the claim should be returned to provider"""
193
+
161
194
  claim_suspension_disposition: Optional[str] = None
195
+ """Explanation of why the claim was suspended"""
196
+
162
197
  line_item_rejection_disposition: Optional[str] = None
198
+ """Explanation of why the line item was rejected"""
199
+
163
200
  line_item_denial_disposition: Optional[str] = None
201
+ """Explanation of why the line item was denied"""
202
+
164
203
  claim_rejection_reasons: Optional[list[str]] = None
204
+ """Detailed reason(s) describing why the claim was rejected"""
205
+
165
206
  claim_denial_reasons: Optional[list[str]] = None
207
+ """Detailed reason(s) describing why the claim was denied"""
208
+
166
209
  claim_return_to_provider_reasons: Optional[list[str]] = None
210
+ """Detailed reason(s) describing why the claim should be returned to provider"""
211
+
167
212
  claim_suspension_reasons: Optional[list[str]] = None
213
+ """Detailed reason(s) describing why the claim was suspended"""
214
+
168
215
  line_item_rejection_reasons: Optional[list[str]] = None
216
+ """Detailed reason(s) describing why the line item was rejected"""
217
+
169
218
  line_item_denial_reasons: Optional[list[str]] = None
219
+ """Detailed reason(s) describing why the line item was denied"""
170
220
 
171
221
 
172
222
  class LineEdits(BaseModel):
@@ -174,16 +224,35 @@ class LineEdits(BaseModel):
174
224
 
175
225
  model_config = camel_case_model_config
176
226
 
177
- denial_or_rejection_text: str
178
- procedure_edits: list[str]
179
- modifier1_edits: list[str]
180
- modifier2_edits: list[str]
181
- modifier3_edits: list[str]
182
- modifier4_edits: list[str]
183
- modifier5_edits: list[str]
184
- data_edits: list[str]
185
- revenue_edits: list[str]
186
- professional_edits: list[str]
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"""
187
256
 
188
257
 
189
258
  class PricedService(BaseModel):
@@ -224,7 +293,7 @@ class PricedService(BaseModel):
224
293
  medicare_std_dev: Optional[float] = None
225
294
  """Standard deviation of the estimated Medicare amount (estimates service only)"""
226
295
 
227
- medicare_source: Optional[str] = None
296
+ medicare_source: Optional[MedicareSource] = None
228
297
  """Source of the Medicare amount (e.g. physician fee schedule, OPPS, etc.)"""
229
298
 
230
299
  pricer_result: Optional[str] = None
@@ -272,7 +341,7 @@ class Pricing(BaseModel):
272
341
  medicare_std_dev: Optional[float] = None
273
342
  """The standard deviation of the estimated Medicare amount (estimates service only)"""
274
343
 
275
- medicare_source: Optional[str] = None
344
+ medicare_source: Optional[MedicareSource] = None
276
345
  """Source of the Medicare amount (e.g. physician fee schedule, OPPS, etc.)"""
277
346
 
278
347
  inpatient_price_detail: Optional[InpatientPriceDetail] = None
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "mphapi"
3
- version = "0.4.2"
3
+ version = "0.4.3"
4
4
  description = "A Python interface to the MyPriceHealth API"
5
5
  authors = ["David Archibald <davidarchibald@myprice.health>"]
6
6
 
File without changes
File without changes
File without changes
File without changes