feat(sp10): 277CA parser + Payer-Rejected Inbox lane
- Add cyclone.parsers.models_277ca + parse_277ca (X12 005010X214)
- Per-Patient HL ClaimStatus with REF*1K (PCN), REF*EJ (tax ID),
STC category code, amount, service date
- STC classifier: A1-A3 accepted, A4/A6/A7 rejected, A8/A9 pended,
P1-P5 paid, anything else unknown
- Multiple STCs per Patient HL: last wins (canonical pattern for
'first pended, then paid' acknowledgments)
- Subscriber-level STCs surface in unscoped_statuses
- Add apply_277ca_rejections — stamps Claim.payer_rejected_* fields on
matching rows (lookup by patient_control_number, mirrors 999 path)
- New /api/parse-277ca, /api/277ca-acks, /api/277ca-acks/{id} endpoints
- New two77ca_acks table + Two77caAck ORM model
- New Claim columns: payer_rejected_at, _reason, _status_code, _by_277ca_id
- New payer_rejected lane in /api/inbox/lanes (distinct from 999
envelope rejected lane)
- New PayerConfig277CA block in config/payers.yaml + Pydantic model
- Migration 0008 bumps user_version to 8
Tests: 654 -> 688 (parser 22 + apply 6 + API 8 + config 6 + adjustments).
All 688 backend tests pass; 1 pre-existing skipped test class unaffected.
This commit is contained in:
@@ -147,6 +147,38 @@ All CMS POS codes `01`–`99` are accepted. The canonical list lives in
|
||||
`cyclone/parsers/payer.py` as `CMS_PLACE_OF_SERVICE_CODES` and is the
|
||||
source of truth for validation and any UI dropdowns.
|
||||
|
||||
## 277CA Claim Acknowledgment (SP10)
|
||||
|
||||
After Gainwell accepts our 837P file (999 AK5=A) and adjudicates the
|
||||
claims, they send back a 277CA per X12 005010X214. The 277CA carries
|
||||
one `STC` segment per claim with a category code:
|
||||
|
||||
| STC code | Meaning | Cyclone lane |
|
||||
|---|---|---|
|
||||
| A1, A2, A3 | Acknowledged / accepted | (logged, no action) |
|
||||
| A4, A6, A7 | Rejected by payer | **Inbox Payer-Rejected** |
|
||||
| A8, A9 | Pended | (logged for follow-up) |
|
||||
| P1–P5 | Paid | (835 follow-up expected) |
|
||||
|
||||
The Payer-Rejected lane is distinct from the 999 envelope "rejected"
|
||||
lane: a claim can be syntactically valid (999 A) but semantically
|
||||
denied (277CA STC A6).
|
||||
|
||||
To upload a 277CA:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/parse-277ca \
|
||||
-F "file=@TP11525703-837P_M019048402-...-1of1_277.x12"
|
||||
```
|
||||
|
||||
The response includes `matched_claim_ids` (which Cyclone claims were
|
||||
stamped payer-rejected) and `orphan_status_codes` (status entries we
|
||||
couldn't tie to a Cyclone claim — usually because the PCN in REF*1K
|
||||
doesn't match anything we sent).
|
||||
|
||||
The Inbox at `/api/inbox/lanes` returns the new `payer_rejected` lane
|
||||
alongside the existing four.
|
||||
|
||||
## Validation rules Cyclone enforces
|
||||
|
||||
See [837p.md](./837p.md#validation-rules-cyclone-enforces) and the
|
||||
|
||||
Reference in New Issue
Block a user