feat(invoicing): TAM-6900: inpatient bed fee#10142
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 9188a62. Configure here.
|
🦸 Review Hero Summary Below consensus threshold (8 unique issues not confirmed by majority)
Nitpicks
Local fix prompt (copy to your coding agent)Fix these issues identified on the pull request. One commit per issue fixed.
|
708c381 to
4eb05b7
Compare
5627937 to
8dbaea4
Compare
4eb05b7 to
c4a1071
Compare
fff379e to
199e6e8
Compare
5426da1 to
9cbd524
Compare
199e6e8 to
70633c3
Compare
…usions Add a facility setting (invoicing.inpatientFee.bundledCategories) and an isInpatientFeeBundled helper, then gate the clinical-item auto-add paths: for admission encounters at a facility that bundles a category, lab/imaging items don't auto-add and the administered (MAR) medication portion is excluded. Discharge meds always bill; outpatient/ER and procedures are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ons (lab) Lab items don't auto-add for an admission encounter when the facility bundles lab into the admission fee, but still auto-add for a non-admission (clinic) encounter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tion split Add a medication case to the inclusions suite: for an admission encounter at a facility that bundles medications, the administered (MAR) portion is excluded from the invoice while discharge dispensing is still billed (quantity = dispensed only). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9cbd524 to
47b62ad
Compare
70633c3 to
4f4ad90
Compare
…elper - Type the category arg as the InpatientBundledCategory union (was string), so a typo at a call site fails at compile time instead of silently returning false. - Skip the bundling lookup when there's no MAR quantity to exclude (marQty === 0), avoiding a wasted DB round-trip on pure discharge dispenses. - Reduce the helper's comment to one line. Kept the encounterId-based fetch (rather than passing the encounter object) because one call site passes an association-loaded encounter whose locationId isn't guaranteed; the self-sufficient re-fetch keeps bundling correct there. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the BED_FEE invoice category with each Location as a priceable product (InvoiceProduct.sourceLocationRecord), the facility overnight-charge-time setting, a pure computeBedFeeChargeInstants helper (facility-local night counting, unit-tested), and Invoice.recalculateBedFee which reconciles one bed-fee line per location (quantity = nights, location at each overnight check, soft-delete-aware). Wiring to the admission trigger and nightly job follows. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the BedFeeCharger scheduled task (hourly; recomputes bed fees for all currently- admitted patients, relying on the idempotent per-facility-local recompute) plus its config, and charge the admission night immediately when an admission encounter is created. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ischarge-day bed fee Decision A: a same-day overnight check (early-hours admission) counts — charge the night admitted in (pinned by a unit test). And the BedFeeCharger now also recomputes recently- discharged admission encounters (endDate within ~25h), so the final discharge-day night lands even for off-hour check times and death discharges. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drive Invoice.recalculateBedFee against the DB: one night for a same-day admission, one night per overnight check for a multi-night stay, and no charge for a location without a bed-fee product (placeholder ward). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… a ward move Add a case where the patient moves wards mid-stay: each overnight check is attributed to the location occupied at that time, so the invoice carries one line per location with the right night counts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n bed-fee helper Mirror the encounter-fee selector cleanup (Review Hero nit) in computeBedFeeChargeInstants: use ?? for the timezone fallback and drop the dead primaryTimeZone ternary. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4f4ad90 to
c6a386a
Compare
…-inpatient-encounter-fees
…ne string orderDate is a dateType (string) column storing ISO 9075 in the primary timezone; passing a JS Date serialised to UTC ISO-8601. Use getCurrentDateTimeString() to match the datetime storage convention. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
recalculateBedFee issued one EncounterHistory query per charge instant (a query per night, hourly, per admitted patient). Load the encounter's location history once and walk the sorted rows in memory instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
recalculateBedFee ran only on admission creation and in the hourly job for still-admitted/recently-discharged encounters. With no discharge-time recompute, nights accrued between the last hourly run and discharge were absent from the invoice until the next run — and lost permanently if the invoice was finalised in that window (recalc only touches in-progress invoices). Recompute on the encounter update path when endDate or locationId changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Changes
Implements the inpatient bed fee (TAM-6900). Stacked on #10141 (TAM-6901) → #10137 (TAM-6898) — review/merge those first (base is the 6901 branch). No DB migration — BED_FEE is a category string and Location-as-product reuses
InvoiceProduct.sourceRecordId.BED_FEEinvoice category with each Location as a priceable product (InvoiceProduct.sourceLocationRecord); rate via price lists.invoicing.bedFee.overnightChargeTime(default02:00, facility-local).computeBedFeeChargeInstantshelper (facility-local night counting, unit-tested) +Invoice.recalculateBedFee— reconciles one bed-fee line per location (quantity = nights, attributed to the location at each overnight check; placeholder wards without a product are skipped; recompute sets quantity and won't resurrect a cashier-removed line).BedFeeChargeraccrues later nights for all admitted patients. The recompute is idempotent and computes facility-local timing internally, so the job just runs hourly — no per-facility cron needed.Verified:
@tamanu/database+@tamanu/central-serverbuild pass, lint clean, night-counting unit tests (5/5). Open items (seespecs/invoicing/inpatient-encounter-fees-plan.md): the PRD worked-example looks off by a day — confirm the night-counting rule (an N-night stay bills N nights); discharge-day finalisation has a narrow edge for non-hour-aligned check times; integration tests (location attribution, batching) not yet run.Auto-Deploy
Options
Tests
Review Hero
.github/review-hero/suppressions.yml. Also runs automatically at the end of any auto-fix run.Remember to...