fix: auto-price CDT codes and fix crown/recement code mismatches
- Auto-fill service line price when a recognized CDT code is typed (e.g. D2740), instead of requiring a separate "Map Price" click - Fix chatbot preauth prefill using an empty DOB for price lookup, causing age-tiered codes (D2740) to price as $0 - Re-apply fee-schedule pricing with the loaded patient DOB before MassHealth preauth auto-submit - Add a "Recement Crown" (D2920) combo button distinct from "Crown" (D2740) to avoid picking the wrong code/price - Fix AI note parsing to prioritize "recement" over "crown" regardless of word order or tooth-number format (e.g. "#7 crown recement") Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -354,6 +354,30 @@ function parseSrpCode(input: string): CdtMatch | null {
|
||||
return { code: codeStr, description: row.Description, input, quad: quadrant };
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse re-cement wording regardless of word order or tooth-number format:
|
||||
* "recement crown #7", "#7 crown recement", "recement crown 7". "recement"
|
||||
* outranks "crown" whenever both appear — this is a re-cement (D2920), not
|
||||
* a new crown (D2740).
|
||||
*/
|
||||
function parseRecementCode(input: string): CdtMatch | null {
|
||||
const lower = input.toLowerCase();
|
||||
if (!/\bre[\s-]?cement(?:ed|ing)?\b/.test(lower)) return null;
|
||||
|
||||
let toothNumber: string | undefined;
|
||||
const hashMatch = input.match(/#\s*(\d{1,2})\b/);
|
||||
const toothWordMatch = input.match(/\btooth\s+(\d{1,2})\b/i);
|
||||
const bareNumMatch = input.match(/\b(\d{1,2})\b/);
|
||||
const m = hashMatch ?? toothWordMatch ?? bareNumMatch;
|
||||
if (m) {
|
||||
const n = parseInt(m[1]!, 10);
|
||||
if (n >= 1 && n <= 32) toothNumber = String(n);
|
||||
}
|
||||
|
||||
const row = ALL_CODES.find((r) => r["Procedure Code"] === "D2920");
|
||||
return { code: "D2920", description: row?.Description ?? "D2920", input, ...(toothNumber ? { toothNumber } : {}) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse RCT/root-canal notation like "rct #29", "#14 rct", "root canal #6".
|
||||
* Returns D3310 (anterior), D3320 (premolar), or D3330 (molar) based on tooth number.
|
||||
@@ -545,23 +569,28 @@ export function lookupCdtCodes(
|
||||
return { code, description: row?.Description ?? code, input: name, ...toothInfo };
|
||||
}
|
||||
|
||||
// 2. Multi-PA shorthand: "4PA", "4PA #3 #14 #19 #30", etc.
|
||||
// 2. Re-cement wording — outranks "crown"/etc. elsewhere in the same entry,
|
||||
// regardless of word order or tooth-number format (e.g. "#7 crown recement").
|
||||
const recementMatch = parseRecementCode(name);
|
||||
if (recementMatch) return recementMatch;
|
||||
|
||||
// 3. Multi-PA shorthand: "4PA", "4PA #3 #14 #19 #30", etc.
|
||||
const multiPaMatches = parseMultiPaCode(name);
|
||||
if (multiPaMatches) return multiPaMatches;
|
||||
|
||||
// 3. Composite filling by tooth# and surfaces — also determines CDT code from tooth position
|
||||
// 4. Composite filling by tooth# and surfaces — also determines CDT code from tooth position
|
||||
const compositeMatch = parseCompositeCode(name);
|
||||
if (compositeMatch) return compositeMatch; // already carries toothNumber/toothSurface
|
||||
|
||||
// 4. RCT by tooth# — D3310/D3320/D3330 based on tooth position
|
||||
// 5. RCT by tooth# — D3310/D3320/D3330 based on tooth position
|
||||
const rctMatch = parseRctCode(name);
|
||||
if (rctMatch) return rctMatch;
|
||||
|
||||
// 5. SRP + quadrant — D4341/D4342 with UL/UR/LL/LR
|
||||
// 6. SRP + quadrant — D4341/D4342 with UL/UR/LL/LR
|
||||
const srpMatch = parseSrpCode(name);
|
||||
if (srpMatch) return srpMatch;
|
||||
|
||||
// 6. Hardcoded direct code map (short abbreviations / codes not in MH schedule)
|
||||
// 7. Hardcoded direct code map (short abbreviations / codes not in MH schedule)
|
||||
const directKey = DIRECT_CODE_MAP[cleaned] ? cleaned : DIRECT_CODE_MAP[strippedCleaned] ? strippedCleaned : null;
|
||||
if (directKey) {
|
||||
const code = DIRECT_CODE_MAP[directKey]!;
|
||||
@@ -569,7 +598,7 @@ export function lookupCdtCodes(
|
||||
return { code, description: row?.Description ?? code, input: name, ...toothInfo };
|
||||
}
|
||||
|
||||
// 7. Hardcoded alias + keyword search (try stripped name so tooth# doesn't break matching)
|
||||
// 8. Hardcoded alias + keyword search (try stripped name so tooth# doesn't break matching)
|
||||
const match = matchOne(strippedCleaned !== cleaned ? strippedCleaned : name);
|
||||
if (match) return { ...match, input: name, ...toothInfo };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user