Skip to content

qa2#21442

Closed
buddhika75 wants to merge 67 commits into
hims-qa2from
development
Closed

qa2#21442
buddhika75 wants to merge 67 commits into
hims-qa2from
development

Conversation

@buddhika75

Copy link
Copy Markdown
Member

No description provided.

buddhika75 and others added 27 commits June 10, 2026 09:43
…tity

When a bill item's available stock was less than the requested quantity,
the insufficient-stock error message navigated through a minimal ItemBatch
object (built from DTO data without the Item relationship populated) to
retrieve the item name, causing a NullPointerException:

  bi.getPharmaceuticalBillItem().getItemBatch().getItem().getName()
                                                  ^^^^^^^^^^^ null

Root cause: createBillItemFromStockDTO() constructs a minimal ItemBatch
from bulk-query DTO data (id, batchNo, rates, expiry) but never calls
batch.setItem(...), leaving the item field null.

Fix: use bi.getItem().getName() instead — BillItem.item is always set
correctly via newBillItem.setItem(referenceItem.getItem()) during bill
item creation and is updated by replaceSelectedSubstitute() when a
substitute is chosen.

Diagnosed from server log: NullPointerException at
TransferIssueForRequestsController.settle(TransferIssueForRequestsController.java:422)

Closes #20972

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ent NPE

The previous fix replaced getItemBatch().getItem().getName() with
bi.getItem().getName(), but bi.getItem() or getName() can also be null
(e.g. legacy data, Vmpp/Vmp items). Remove the item name reference
entirely and use a safe generic message instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two independent bugs allowed a transfer issue to proceed even when actual
DB stock was insufficient:

1. Stale in-memory stock check
   The validation loop compared bi.getPharmaceuticalBillItem().getStock()
   .getStock() against qty, but that Stock object is constructed at
   page-load time by createBillItemFromStockDTO() with the available qty
   captured from the bulk DTO query. Any stock movement that occurs after
   the page loads (retail sale, concurrent issue) is invisible to this
   check. Fix: replace with a live DB lookup via StockFacade.find() for
   every item immediately before saveBill() is called, so the check always
   reflects the true current stock level.

2. Negated qty passed to isStockAvailable()
   In the post-save processing loop, qty is negated at line 831 before
   isStockAvailable() is called at line 856. The internal check
   (qty > fetchedStock.getStock()) evaluates as e.g. -10 > 2 → false,
   causing the guard to always return true regardless of actual stock.
   Fix: pass Math.abs(tmpPh.getQty()) so the comparison uses the
   magnitude of the quantity.

Also made the error messages null-safe (bi.getItem() null guard) and
added a clearer message telling the user to refresh when live stock check
fails, since the cause is stale page state.

Closes #20972

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…data

When a transfer issue is settled, the PharmaceuticalBillItem carries a
minimal ItemBatch built from a DTO — only id, batchNo, and rates are set;
the item relationship is null. Both addToStock(pbi, qty, Staff) and
deductFromStock(pbi, qty, Staff) create a new Staff Stock row when none
exists, and they attempt to populate that row's metadata from the batch:

  ItemBatch ib = pharmaceuticalBillItem.getItemBatch();
  Item i = ib != null ? ib.getItem() : null;
  if (i != null) { /* set itemName, barcode, longCode, dateOfExpire, retailsaleRate */ }
  else            { s.setItemName("UNKNOWN"); s.setBarcode(""); s.setLongCode(0L); }

Because the DTO batch has no item loaded, i is always null, so every Staff
Stock row created through a transfer issue is stored with:
  - ITEM_NAME = "UNKNOWN"
  - BARCODE   = ""
  - LONGCODE  = 0
  - DATEOFEXPIRE = null
  - RETAILSALE_RATE = 0.0   (skipped in the else branch)

This does not break stock quantity movement — the JPQL lookup key is
(itemBatch, staff) by ID — but it corrupts the metadata fields used by
stock valuation and expiry reports for in-transit staff stock.

Fix: before accessing ib.getItem(), check whether the item relation is
unloaded (null) while the batch has a valid DB id. If so, call
itemBatchFacade.find(ib.getId()) to obtain the full entity. The loaded
entity is used only for metadata population; the FK already stored on
the Stock row is unchanged. The guard (getItem() == null && getId() != null)
ensures no extra query is issued when the full entity is already loaded
(normal receive-side path where ItemBatch is eagerly fetched from DB).

Applied to both:
  - addToStock(PharmaceuticalBillItem, double qty, Staff)
  - deductFromStock(PharmaceuticalBillItem, double qty, Staff)

Closes #20972

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…l optional

Adds "GRN Return - Approval Required" and "Direct Purchase Return -
Approval Required" config keys (default true, preserving current
two-stage Finalize -> Approve behaviour).

When disabled, finalizeRequest() runs the same stock-update, payment
creation, and completed-marking logic that previously only ran in
approve() (extracted into a shared completeApproval() method), so the
return is completed immediately on Finalize without a separate
approval step.

Adds a "Config" button + dialog on procurement_index.xhtml
(PharmacyReturnApprovalConfigController) so these settings are
configurable from the UI instead of requiring direct ConfigOption
edits.

Part of #21404
…on Patient Deposit

The single-payment composite patient_deposit_with_paid_value.xhtml carried a
<p:ajax> copied from the multi-payment variant whose update targeted
balanceDisplay via p:resolveFirstComponentWithId. That component only exists in
multiple_payment_methods.xhtml, so on inward_bill_payment.xhtml the lookup
returned null, the update expression collapsed to ":", and PrimeFaces threw
ComponentNotFoundException while rendering txtMpPd. The listener also referenced
a controller attribute the inward callers never pass.

Removed the offending p:ajax. The amount still commits via the non-ajax Pay
button submit, matching the Cash field on the same page.

Part of #21408
… payment

The Inward Bill Payment Patient Deposit panel showed "Patient not selected"
because the patient was never set on InwardPaymentController when navigating to
the payment page. navigateDoctorPayment() now sets the patient from the
encounter so the deposit balance is available.

InwardPaymentController.setPatient() now resets the patient deposit totalValue
to 0.0 when loading the deposit, so the amount field starts at 0.00 instead of
carrying a stale value.

Part of #21408
…yment-fix

fix(inward): Patient Deposit payment ComponentNotFoundException and missing deposit details (#21408)
…idation hardening

- Persist PharmaceuticalBillItem.stock in approveDirectPurchaseDraft();
  the stock link was set in memory but never written to DB, so Direct
  Purchase Returns against draft-approved bills failed with
  "Stock information not available for item"
- Sync phi.qty/freeQty with auto-corrected fd quantities in GRN and
  Direct Purchase return validateStockAvailability() so a re-finalize
  after auto-correction approves the corrected quantity, not the stale
  oversized one
- Allow zero-quantity return lines with no Stock record to pass
  validation instead of blocking the whole return
- Add "Direct Purchase - Approval Required" toggle to the Procurement
  Return Configuration dialog (maps to existing config key
  "Use Save Finalize Approve Workflow for Direct Purchase")
- Switch finalized Direct Purchase drafts to read-only print preview;
  approval is done only from the Approve Direct Purchase list

Part of #21404
Refs #21266

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(pharmacy): optional procurement approval workflows + direct purchase stock-link and return validation fixes
…t defaultCommand race

The page-level p:defaultCommand target="btnAdd" made Enter anywhere in
the form fire the item Add button. In the item autocomplete (acItem,
forceSelection=true) this raced the itemSelect AJAX commit, so Enter
could click Add while currentBillItem.item was still null server-side,
producing "Please select an item" despite a visually selected item.
The same race silently dropped typed values in the qty/rate/discount
fields, whose recalculation listeners fire on blur, which
defaultCommand bypasses.

Guards applied (same pattern as pharmacy_transfer_request.xhtml):

- acItem, acExpense, distributor and reference-company autocompletes:
  Enter is swallowed unless the suggestion panel is open, in which case
  PrimeFaces handles the selection only
- txtQty, txtFreeQty, txtPrate, txtLineDiscountRate, txtRetailRate,
  batch no: Enter blurs the field first (committing the blur AJAX
  recalculation), then clicks Add after 350 ms
- expense value/description: Enter clicks Add Expense (full-submit
  button, no blur race) instead of the unrelated item Add button

Closes #21415

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-guard

fix(pharmacy): guard Enter key on direct purchase entry fields against defaultCommand race
…zero-qty PBIs

A double-submit race on the purchase order request page (Enter-key
defaultCommand firing btnSave while another save was in flight) persisted
the same in-memory BillItem twice, creating duplicate rows that share one
BillItemFinanceDetails with only one of them owning the
PharmaceuticalBillItem. Removing the visible duplicate could retire the
row holding the real PBI; the survivor then got a lazily created all-zero
PBI, and PO approval/GRN (which reads pbi.qty) showed qty 0 and blocked
the GRN (coop POR/COOP/MP/26/000965, Maxgalin 50mg).

Server side (PurchaseOrderRequestController):
- saveRequestWithoutMessage() and finalizeRequest() are now synchronized
  (same pattern as TransferIssueController.settle()) so concurrent saves
  from one session serialize; the second save sees the assigned id and
  edits instead of creating a duplicate
- resyncPharmaceuticalBillItemIfEmpty() runs for every line in
  saveBillComponent()/finalizeBillComponent(): a live line whose PBI has
  zero qty and free qty while its finance details hold a real quantity is
  rebuilt via calculateLineValues(), healing already-corrupted lines at
  the next save or finalize

Page (pharmacy_purhcase_order_request.xhtml), same guard pattern as
direct purchase (#21415):
- Qty, Free Qty and P Price inputs in the items table swallow Enter and
  blur instead, committing the blur-AJAX recalculation rather than firing
  a full-page Save mid-edit
- Supplier and item autocompletes swallow Enter unless the suggestion
  panel is open, so PrimeFaces handles only the selection

Closes #21417

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pbi-guard

fix(pharmacy): prevent duplicate PO request bill items and self-heal zero-qty PBIs
@
chore: add ad-hoc artifacts and node_modules to .gitignore

Ignore npm package files, node_modules, ad-hoc Playwright scripts, and
Claude Code temp settings files at the project root. These are
non-project artifacts that should not be tracked.
@
@
chore: remove unwanted tracked files and prevent future inclusion

Delete unwanted tracked files from the repository:
- .codex-backup/ — Codex temp backup files (2 files)
- lib/unknown/binary/ — unused EclipseLink SNAPSHOT JARs (8 files)
- 4 .class files accidentally committed in src/main/java/
- clinical_favourite_item_by_weight.xhtml.backup

Add .gitignore patterns for *.class, *.backup, .codex-backup/,
and lib/unknown/ to prevent these from being tracked again.
@
@
chore: move db/ migration README to developer_docs, remove one-time SQL scripts

Move the BigDecimal migration strategy documentation to
developer_docs/database/ where it belongs as reference knowledge.
Remove the one-time SQL migration scripts and production hotfix SQL
from db/ — these are historical artifacts with no enduring value.

Add db/ to .gitignore to prevent future migration scripts from
being committed to the wrong location.
@
@
chore: move healthcare-erp-architect agent to .claude/agents/, remove github-issues/

The agent file was buried under github-issues/.claude/agents/ where it
could not be discovered by Claude Code. Move it to the proper location
and gitignore the github-issues/ scratch workspace directory.
@
@
chore: remove wiki-docs, sql-scripts, pm, temp root files; preserve one user doc

Delete from repository:
- wiki-docs/ — 43 files, wiki now lives in ../hmis.wiki sibling repo
- sql-scripts/ — 2 one-time ALTER TABLE scripts
- pm/ — 1 project management CSV
- 4 root temp files: session transcript, 3 stale fix-summary MDs

Move Patient-Deposit-Department-Level-Management.md from
user_documentation/ to developer_docs/.

Add gitignore patterns for all removed directories and root files.
@
@
chore: remove root SQL/Python ad-hoc scripts and add gitignore patterns

Delete database-indexes-bht-performance.sql (one-off DB index script)
and stock_reset_script.py (contained hardcoded API key — security risk).

Add /*.sql and /*.py to root ad-hoc artifacts gitignore patterns.
@
@
chore: remove docs/ directory (content already in developer_docs/ and wiki)

All 14 files in docs/ are either stale bug-fix strategies, data dumps,
or wiki pages already present identically in ../hmis.wiki. Nothing
unique to preserve.

Add docs/ to .gitignore.
@
@
chore: remove prompts/ directory (one-time AI prompt scratch files)

Delete 19 prompt text/md/codex files. These were one-time use
scratch prompts for AI-assisted development and are no longer needed.

Add prompts/ to .gitignore.
@
chore: add ad-hoc artifacts and node_modules to .gitignore
Add department-wise sale & issue consolidated view with BHT query fixes

- Add DepartmentSaleIssueDTO for consolidated retail/wholesale/inpatient
  by department in pharmacy item history
- Add createDepartmentSaleIssueDto() method with per-category JPQL
  queries using PharmaceuticalBillItem.qty for correct sign handling
- Add "Dept. Sale & Issue" block and tab to history.xhtml, gated behind
  config keys with default true (visible to all institutions by default)
- Fix calDepartmentBhtIssue() to use pharmaceuticalBillItem.qty instead
  of BillItem.qty for correct stock-aware quantity (#21430)
- Add missing cancellation and return bill type atomics to
  createInstitutionBhtIssue() (#21431)
- Guard all findAggregates() results against null (NPE on query failure)

Closes #21428
Closes #21430
Closes #21431

Co-Authored-By: Claude <noreply@anthropic.com>
@
fix(pharmacy): query from PharmaceuticalBillItem, revert BHT issue sign

- Change createDepartmentSaleIssueDto() JPQL to query FROM
  PharmaceuticalBillItem pbi instead of BillItem i — ensures every
  row has a PBI and uses pbi.qty directly without implicit joins
- Revert sign of PBI qty in createInstitutionBhtIssue() when building
  DepartmentSale objects — PBI qty is negative for outgoing issues,
  the BHT Issue tab/block needs positive display quantities
  (Codex review on PR #21439)

Co-Authored-By: Claude <noreply@anthropic.com>
@
Add department-wise pharmacy sale & issue consolidated view, fix BHT issue queries
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5c8b94bb-573d-42e7-9c3f-1f433446699a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch development

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5c71ed4eef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +41 to +42
if (!webUserController.hasPrivilege("PharmacyGrnApprove")
&& !webUserController.hasPrivilege("PharmacyDirectPurchaseApprove")) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require the matching privilege for direct-purchase settings

When a user has only PharmacyGrnApprove, this OR guard lets the request continue and saveConfig() still writes the Direct Purchase Return and Direct Purchase approval-workflow keys below. That allows a GRN approver to disable direct-purchase approval requirements without PharmacyDirectPurchaseApprove; gate each setting by its matching privilege or require a broader/admin privilege for the combined dialog.

Useful? React with 👍 / 👎.

Raw '&' in the config key string inside an EL expression caused an XML
parse error (FaceletException) on any page that includes history.xhtml.
Escaped as '&amp;' to comply with XHTML requirements.
buddhika75 and others added 29 commits June 12, 2026 20:48
…e lines

deductFromStock() already does an atomic UPDATE...WHERE s.stock >= :qty
check (the #20138 TOCTOU-safe guard) and returns false if insufficient,
handled by the existing else branch. The userStockController.isStockAvailable()
check ran after the BillItem/PharmaceuticalBillItem were already persisted,
and on failure only zeroed tmpQty and continued - leaving a saved transfer
issue line with no corresponding stock movement. UserStockContainer
reservations are not populated in this flow, so the check added no real
protection beyond the live stock check already done earlier in settle().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ceuticalBillItem

createEmptyBillItem() (used in generateBillComponent when an item has no
available stock) adds a BillItem with pharmaceuticalBillItem left unset.
Both the live stock validation loop and the zero-qty filter in settle()
dereferenced getPharmaceuticalBillItem() unconditionally, NPEing whenever
such an item was present in the transfer issue.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(pharmacy): prevent NPEs and over-issuing in transfer settlement
…from clinical queue

When an OPD prescription is written in Prescriptions Given on the EMR
visit page (emr/opd_visit.xhtml) and the user clicks Pharmacy Bill on
the clinical queue (clinical/clinical_queue.xhtml), the prescribed
medicines now load automatically onto the retail sale bill - matching
the inward flow where admission prescriptions are converted to pharmacy
dispensing notes.

Root cause: PracticeBookingController.issuePharmacyBill() loaded the
encounter medicines and iterated them with an empty loop body - the
conversion to bill items was never implemented. Only the patient,
referring doctor and prescription text (as a comment) reached the
retail sale page.

Changes:
- PharmacySaleController.addBillItemsFromEncounterMedicines(): converts
  each VisitMedicine prescription to a bill item. Resolves dispensable
  item and quantity via PrescriptionToItemService (qty defaults to 1
  when the prescription is incomplete so the pharmacist adjusts it on
  the page), auto-picks an earliest-expiry (FEFO) in-date stock batch
  from the logged-in user's department, resolving VMP/VTM prescriptions
  to candidate AMPs via PharmacyBean.resolveAmps().
- Items are added through the existing addBillItemSingleItem() so all
  retail-sale safeguards apply unchanged: expiry check, stock quantity
  check, duplicate batch check, UserStock locking and allergy check.
- Dose, frequency, duration and comment are carried onto the bill
  item's prescription so bill descriptions and drug label printing work
  as in the inward discharge issue flow.
- Medicines that cannot be auto-added (no stock, conversion failure,
  duplicate batch) are reported in a visible warning, never silently
  dropped.
- PracticeBookingController.issuePharmacyBill(): replaced the empty
  placeholder loop with a call to the new conversion method.

Mirrors PharmacySaleBhtController.prepareDischargeIssueFromPrescriptions
(issue #21334) for the OPD retail sale path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility

Rework clinical/clinical_queue.xhtml to follow the project UI and
accessibility-first guidelines:

- Replace the h:panelGrid filter layout with a responsive Bootstrap
  row/col grid; labels bound to inputs via p:outputLabel for=...
- Add stable ids to every actionable control (btnProcess, btnVisit,
  btnMarkPresent, btnMarkAbsent, btnEditVisit, btnViewVisit,
  btnOpdBill, btnPharmacyBill) and descriptive title attributes that
  include the patient name and queue number, so Playwright/automation
  can target individual rows.
- Cap both speciality and doctor autocompletes with maxResults="20"
  and add placeholders.
- Date/doctor filter changes now re-render the whole queue form
  (render=":queueForm") instead of a single resolved component id.
- DataTables: add widgetVar and rowKey, pagination (25 rows, bottom,
  hidden when not needed), emptyMessage texts, and a row highlight for
  absent patients in the To Complete tab.
- To Complete tab gains Age, Phone and a Waiting/Absent status badge
  column; both tab titles show live session counts.
- Consistent icon set and button styling (success/info/danger/warning
  variants) across row actions; growl shows message details.

JSF-only change - no Java modifications.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…o favourite medicines API

- Add GET /clinical/favourite_medicines/entities/diagnoses to search
  ClinicalEntity records (Disease_or_Syndrome) for use as forItemName
- Support type=FavouriteMedicine (default) / type=FavouriteDiagnosis on
  create, search, and by-id endpoints
- Resolve forItemName to a diagnosis for FavouriteDiagnosis templates,
  with "did you mean" suggestions on mismatch
- Register the new endpoint and capability in CapabilityStatementResource
  and the AI chat module listing

Closes #21452
…ourite diagnosis/medicine, and channel report cashier summaries

- FavouriteMedicineApiService: add fromKg/toKg weight range fields to templates;
  make age range optional when weight range is provided; validate weight ranges
- PatientEncounterController: add method 4 (no age/weight filter) fallback so
  favourites load even when patient DOB/weight aren't recorded; validate a
  medicine is selected before 'Add Favourite'; fall back to FavouriteDiagnosis
  template directly when no separate FavouriteMedicine config exists
- PastPatientEncounterController: detect legacy prescriptions persisted with
  null or VisitDocument type via DocumentTemplateType.Prescription, default
  new prescriptions to VisitPrescription type
- PracticeBookingController: separate prescriptionHtml (rich text) from plain
  comment via htmlToPlainText(); clear stale prescription when switching
  encounters
- ChannelReportTempController: add fetchBillsTotal, fetchCashiers,
  fetchUserRows, fetchDateRangeRows with WebUser/agency support for
  cashier-based channel reporting
- FavouriteMedicineApi: serialize fromKg/toKg in API responses
- PharmacyBean: fallback VMP lookup via direct VMP.VTM_ID when
  VirtualProductIngredient join table is unpopulated
- Privileges/UserPrivilageController: add PharmacyItemNameEdit privilege
- pharmacy_bill_retail_sale.xhtml: add toggleable prescription preview panel
  rendering prescriptionHtml
- lab_vmp/vtm, store_atm/vtm XHTML: gate Add/Edit/Save buttons behind
  PharmacyItemNameEdit privilege
- opd_visit.xhtml: process acMedicine + dose/frequency/duration fields when
  adding a favourite, so the current selection is captured

Co-Authored-By: Claude <noreply@anthropic.com>
PR validation failed because local JNDI names (jdbc/coop, jdbc/rhAuditDS)
were committed in the branch history instead of the CI/CD placeholders
(${JDBC_DATASOURCE}, ${JDBC_AUDIT_DATASOURCE}).

Co-Authored-By: Claude <noreply@anthropic.com>
- ChannelReportTempController.java: guard b.getClass() calls at lines 251-259
  behind a null check — consistent with the existing null guard at line 280
- clinical_queue.xhtml: add onclick=this.disabled=true on btnOpdBill and
  btnPharmacyBill to prevent accidental double-issue
- clinical_queue.xhtml: bind pharmacySaleController.patient from bsc.bill.patient
  (selected row) rather than the stale practiceBookingController.opdVisit.patient

Co-Authored-By: Claude <noreply@anthropic.com>
fix: discharge notification navigation, removal, filters, real-time push, and UI display

- Navigate to admission profile when clicking discharge notifications (PatientRoom/PatientEncounter)
- Allow removal of PatientRoom/PatientEncounter-based notifications
- Fix NPE in cancel filter for discharge notifications (clear + filter methods)
- Fix today filter date comparison (use midnight truncation instead of equals)
- Add WebSocket listener to user_notifications.xhtml for real-time notification list updates
- Add Room Discharge and Patient Discharge type badges to notification list

Closes #21389
Closes #21390
Closes #21391

Co-Authored-By: Claude <noreply@anthropic.com>
@
fix: replace f:websocket with OmniFaces o:socket in notification page

Co-Authored-By: Claude <noreply@anthropic.com>
@
…ork filters, add clear/restore

- removeUserNotification: PatientEncounter-based (clinical/final discharge)
  notifications silently returned without removing; now removable. Null-safe
  department check (avoids NPE on unmatched bill types) and sets retiredAt/retirer.
- Filters reworked: previously pruned the already-loaded 20-item list in memory
  (compounding, not reversible, contradictory checkboxes). Now a fresh JPQL
  query per filter: Today Only, Seen (All/Unseen/Seen), Status
  (All/Pending/Completed), Cancelled Bills Only.
- Clear button now clears exactly what is listed (filter first, then clear),
  with explicit confirmation and cleared count; previously it only acted on
  checked criteria and did nothing when none were checked.
- New Show Cleared filter with per-row Restore button so cleared notifications
  remain retrievable; Clear is guarded while viewing cleared items.
- Push refresh and row removal refill via the filter-aware query so active
  filters are preserved; filters reset when navigating to the page.

Refs #21389 #21390 #21391

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…m guard

Replace `onclick="this.disabled=true;"` on btnOpdBill and btnPharmacyBill
with `onclick="if (!confirm('…')) return false;"` per the codebase UI
guidelines (developer_docs/ui/comprehensive-ui-guidelines.md §358–363).

Disabling the button synchronously in onclick before the form POST fires
excludes the button's name/value from the request, potentially breaking
JSF action dispatch on ajax=false PrimeFaces command buttons.

Co-Authored-By: Claude <noreply@anthropic.com>
feat(clinical): favourite diagnosis API — weight range support, no-filter fallbacks, and channel report summaries
- navigateToCurrentNotificationRequest: clicking Go now marks the
  notification retired (seen=true, retired=true, retireComments="Viewed")
  so it disappears from the active list and appears under Show Cleared.
  Also adds null guard on un.getNotification() to prevent NPE.
- NotificationController: guard pr.getRoomFacilityCharge() before calling
  getName() to prevent NPE when a PatientRoom has no facility charge set.
- user_notifications.xhtml: add timeZone="Asia/Colombo" to f:convertDateTime
  for consistent timestamp display regardless of JVM default timezone.

Refs #21389 #21390 #21391

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fixes-21389-21390-21391

fix(notifications): restore discharge notification navigation, delete, and filter fixes
…pt, and audit logging (Closes #21257)

- Fix unresponsive Discharge/Cancel buttons on inward_patient_room_details.xhtml by switching from ajax=false to AJAX with process="@this" update="@Form"
- Fix patientRoom vs pR bug in RoomChangeController.dischargeWithCurrentTime() where indexOf used the List field instead of the method parameter
- Add rendered toggle between Discharge and Cancel buttons based on room discharge state
- Add success/error messages after discharge and cancel actions
- Add current room listing to admission_profile.xhtml Room Management panel showing active PatientRoom/GuardianRoom with admitted time and View link
- Add inward_room_discharge_receipt.xhtml receipt page with Print, Print Previous, and Inpatient Dashboard navigation
- Add JS confirmation dialogs (p:confirm) for discharge and cancel actions
- Add audit event logging (AuditEvent) for room discharge and cancel via AuditEventApplicationController
- Fix cancel to properly clear dischargedAt field

Co-Authored-By: Claude <noreply@anthropic.com>
…anagement actions (Closes #21257)

- Add privilege checks to all Room Management buttons on admission_profile.xhtml (InwardRoomRoomChange, InwardRoomGurdianRoomChange, InwardRoomRoomOccupency)
- Add new "Add New Room" and "Add Guardian Room" buttons to dashboard
- Add audit event logging (AuditEvent) to all room operations: admitRoom, change, addNewRoom, changeGurdianRoom, discharge, remove, removeRoom, removeGuardianRoom
- Add notification support for room admit, room change, and discharge cancel via new trigger types INWARD_PATIENT_ROOM_ADDED and INWARD_PATIENT_ROOM_CHANGED
- Extend NotificationController with createInwardRoomAdmitNotifications, createInwardRoomChangeNotifications, createInwardRoomDischargeCancelNotifications

Co-Authored-By: Claude <noreply@anthropic.com>
When the pharmacist clicks Issue on a BHT request, items are now
automatically resolved to concrete AMPs with available stock instead
of falling back to a null-stock placeholder that required full manual
substitution.

- Replace the empty Amp/Vmp/Ampp/Vmpp if-blocks with PharmacyBean.resolveAmps()
  which traverses the full VTM→VPI→VMP→AMP / ATM→AMP hierarchy
- Tiered candidate selection: exact requested AMP first, then same-strength
  sibling AMP, then any available AMP under the same VMP/VTM
- Strength-adjusted quantity for different-strength substitutes:
  ceil(issuableQty × requestedStrength / substituteStrength);
  null strength on either side is treated as equivalent (ratio = 1)
- Add @transient fields autoSubstituted and requestedItemName to BillItem
  to carry substitution state through to the UI without a schema change
- Visual markers on the issue page for auto-substituted rows:
  yellow background, orange exchange icon with tooltip, italic sub-line
  showing "Auto-sub: <original> → <dispensed>"
- Null-stock placeholder rows still appear for items with no stock at all
  so the pharmacist can manually substitute via the existing dialog

Closes #16132

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ceipt page

- Replace non-existent nameWithInitials with name() on WebUser
- Replace non-existent Person.nameOfAgeAndGender with Person.ageAsString
- Remove broken #{now} EL expression, use loggedUser.name for printed-by
- Remove redundant footer printed-by line

Co-Authored-By: Claude <noreply@anthropic.com>
…ement, timezone, button IDs

- Fix duplicate audit event logging: set status/duration before single logAuditEvent call
- Remove h:head script block outside ui:composition (would not render); inline window.print()
- Add timeZone="Asia/Colombo" to all f:convertDateTime in receipt page and dashboard
- Rename "Print Previous" to "Print Copy" since previous retrieval not implemented
- Add stable id attributes to room-management buttons (btnAddNewRoom, btnAddGuardianRoom, btnRoomDetails, btnRoomChange, btnGuardianRoomChange)
- Add JsfUtil error message for failed active room query instead of silent swallow

Co-Authored-By: Claude <noreply@anthropic.com>
- Include VMP siblings in candidate list when requested item is an AMP
  so same-brand-out-of-stock falls through to substitute tiers instead
  of immediately producing a null-stock placeholder
- Update prepareSubstitute() to use pharmacyBean.resolveAmps() instead
  of the instanceof Amp guard — manual substitute dialog now works for
  VMP/VTM placeholder rows too
- Add escape="false" to the Font Awesome icon h:outputText so the glyph
  renders correctly instead of as escaped entity text

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ry failure

- Use existing logger with Level.SEVERE and admission ID context
- Surface recoverable error via JsfUtil.addErrorMessage instead of silent return

Co-Authored-By: Claude <noreply@anthropic.com>
…tion

Co-Authored-By: Claude <noreply@anthropic.com>
The substitute selection loop previously picked the first same-strength
or fallback AMP with any available stock, which depended on the DB order
from findAmpsForVmp() and could select a later-expiring brand ahead of
an earlier-expiring one.

getStockByQty returns batches ORDER BY dateOfExpire, so the first entry
in the returned list is always the earliest-expiring batch for that AMP.
The loop now tracks the earliest expiry per tier and replaces the current
best when a candidate's first batch expires sooner, preserving FIFO
across substitute brands.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…fixes-21389-21390-21391

fix(inward): restore discharge notification fixes, room management enhancements (Closes #21257, #21389, #21390, #21391)
…-improvements

feat(pharmacy): auto-convert BHT request items to AMPs on issue
@buddhika75 buddhika75 closed this Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants