Skip to content

Conversation

@damithdeshan98
Copy link
Collaborator

@damithdeshan98 damithdeshan98 commented Jan 19, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Ward Admission and Local Surgery diagnosis card templates with dynamic content generation and customizable placeholders
    • Implemented VAT (Value Added Tax) configuration and automatic calculation for billable charges
    • Enhanced clinical card preview functionality with template selection and print-to-PDF capabilities
    • Introduced template-driven diagnosis card system with variable substitution for patient and clinical data
  • Bug Fixes

    • Improved handling of cancelled and refunded bill amounts in financial calculations
    • Enhanced null-checking for missing clinical data during card generation
  • Documentation

    • Updated available document template placeholders to include admission and surgery-specific fields

✏️ Tip: You can customize this high-level summary in your review settings.

Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
Signed-off-by: damithdeshan98 <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 19, 2026

Walkthrough

This pull request introduces template-driven diagnosis card generation (Ward Admission and Local Surgery cards), adds comprehensive VAT calculation support across inward billing controllers, enhances bill management to handle refunded/cancelled items with sign inversion, and updates UI pages to display VAT and render dynamically templated clinical cards with variable substitution.

Changes

Cohort / File(s) Summary
Database & Template Registry
sql-scripts/Ward-Admission-LocalSurgery-Card-Templates.sql
Registers two new document template types (WARD_ADMISSION_CARD, LOCAL_SURGERY_CARD) and creates default HTML templates for each with variable placeholders; includes verification queries to confirm template creation.
Core Data Models
src/main/java/com/divudi/core/data/clinical/DocumentTemplateType.java
Adds two new enum constants: WardAdmissionCard and LocalSurgeryCard.
Core Data Models
src/main/java/com/divudi/core/data/inward/PatientEncounterComponentType.java
Adds new enum constant OTHER to extend component type definitions.
VAT Support in Inward Controllers
src/main/java/com/divudi/bean/inward/BhtSummeryController.java
Introduces comprehensive VAT configuration and calculation methods (isVatEnabled, getVatPercentage, calculateVatAmount, isChargeTypeVatable, etc.); stores calculated VAT during bill save operations; enhances getters with null checks and child encounter fetching.
VAT Recalculation on Bill Updates
src/main/java/com/divudi/bean/inward/InwardReportControllerBht.java
Adds VAT recalculation logic when bill net total is updated; computes selective VAT from bill items and updates bill's vat and vatPlusNetTotal fields.
Bill Cost Aggregation & Fee Collection
src/main/java/com/divudi/bean/inward/InwardBeanController.java
Replaces JPQL net total summation with Java-based calculation applying sign inversion for RefundBill and CancelledBill; adds conditional fee exclusion via config option.
Professional Fee Detection
src/main/java/com/divudi/bean/inward/InwardStaffPaymentBillController.java
Adds hasFeeCollectedByDoctor() helper method to check if any bill fee is marked as collected by doctor.
Surgery Bill Issue Management
src/main/java/com/divudi/bean/inward/SurgeryBillController.java
Implements lazy-loading for store/pharmacy issues and encounter components; enhances createIssueTable with dynamic refund class reference and optional CancelledBill inclusion via feature flag.
Template-Driven Diagnosis Card Generation
src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java
Introduces extensive template selection, loading, and rendering infrastructure; adds initializeWardAdmissionCard(), initializeSurgeryCard(), loadWardAdmissionDiagnosisCard(), loadLocalSurgeryDiagnosisCard(); implements replaceVariablesInHtml() for template variable substitution; adds DiagnosticCardData and WardAdmissionCardData inner classes; integrates DocumentTemplateFacade for template fetching.
Template Documentation Updates
src/main/webapp/emr/settings/document_template.xhtml
Expands placeholder documentation with new sections: Patient Information (NIC/PHN aliases), Admission Details (BHT, dates, room), and Surgery Details (procedure, surgeon, anesthesiologist, dates).
Admission Profile UI
src/main/webapp/inward/admission_profile.xhtml
Adds two new command buttons: Ward Admission Diagnosis Card and Local Surgery Diagnosis Card with corresponding action handlers.
Diagnosis Card Tabs
src/main/webapp/inward/clinical_data_diagnosis_card.xhtml
Adds two new tabs (Diagnostic Card and Ward Admission Card) with template selection, generation, and print/PDF export actions.
Ward Admission Card Page
src/main/webapp/inward/ward_admission_diagnosis_card.xhtml
New page with two-column layout: left column for data entry (admission details, vitals, diagnoses, medications, investigations, procedures); right column for template-driven card preview with generation and print workflow.
Local Surgery Card Page
src/main/webapp/inward/local_surgery_diagnosis_card.xhtml
New page with similar two-column layout for local surgery diagnosis card: left for clinical findings/diagnosis/investigations entry; right for template preview and card generation.
Clinical Cards Template Section
src/main/webapp/sections/clinical_cards_with_template_selection.xhtml
New reusable template section providing collapsible panels for Ward Admission and Local Surgery card template selection, generation, and preview dialogs.
Bill Display with VAT
src/main/webapp/resources/inward/bill/finalBill.xhtml
Consolidates per-charge-type rendering into unified loop; introduces VAT rows conditionally displayed when bill.vat > 0, showing VAT amount and VAT-plus-net-total using pre-calculated bill entity values.
Interim Bill with VAT
src/main/webapp/resources/inward/bill/intrimBill.xhtml
Replaces dual conditional panels with single ui:repeat for bed charges; introduces VAT rows in summary section using pre-calculated bill.vat and bill.vatPlusNetTotal when VAT exists.
Interim Bill Item Visibility
src/main/webapp/inward/inward_bill_intrim.xhtml
Extends row visibility logic to conditionally filter CancelledBill via Separate Medicines and Surgical Supplies Tab flag; negates bill amounts for CancelledBill or RefundBill in total display.
Surgery Payment Bill Updates
src/main/webapp/inward/inward_bill_surgery_payment.xhtml
Updates Surgery autoComplete to use procedureController.completeProcedures; adds controller attribute to bi:staffBill component.
Professional Payment Bill
src/main/webapp/inward/inward_bill_professional_payment.xhtml
Adds controller attribute to bi:staffBill composite component invocation.
Surgery Professional Rendering
src/main/webapp/theater/inward_bill_surgery_professional.xhtml
Removes AJAX render target from autoComplete itemSelect handler, simplifying re-render logic.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as XHTML UI
    participant Controller as InpatientClinicalDataController
    participant Facade as DocumentTemplateFacade
    participant Database as DB (Template)
    participant Renderer as HTML Renderer

    User->>UI: Select template & click Generate
    UI->>Controller: onWardTemplateChange() / loadWardAdmissionDiagnosisCard()
    Controller->>Facade: getTemplateByCodeAndVersion(WARD_ADMISSION_CARD)
    Facade->>Database: Query DocumentTemplate
    Database-->>Facade: Template entity with HTML content
    Facade-->>Controller: DocumentTemplate
    Controller->>Controller: createReplacementsMap(patientEncounter)
    Controller->>Controller: replaceVariablesInHtml(templateHtml, replacements)
    Note over Controller: {{name}}, {{age}}, {{dx}},<br/>{{procedures}}, etc. → actual values
    Controller->>Controller: setWardAdmissionDiagnosisCardHtml(renderedHtml)
    Controller-->>UI: Update diagnosisCardHtml property
    UI->>Renderer: Render HTML (escape=false)
    Renderer-->>User: Display rendered diagnosis card with patient data
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Roseth IP Issues' is vague and does not clearly convey the main changes in this comprehensive pull request spanning VAT calculations, diagnosis card templates, billing logic, and UI enhancements. Revise the title to be more specific and descriptive, such as 'Add VAT support and diagnosis card templates for Roseth Hospital' or 'Implement ward admission and surgery diagnosis cards with VAT enhancements'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.40.5)
src/main/java/com/divudi/bean/inward/BhtSummeryController.java
src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 18

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java (1)

486-526: Captured Ward/Diagnostic card data is never persisted or used in templating.

wardAdmissionCardData/diagnosticCardData are bound in the UI, but createReplacementsMap only uses PatientEncounter values, and the save methods are stubs that only show success messages. Users will lose input and previews won’t reflect entered data. Please either persist these values (e.g., EncounterComponent or a dedicated entity) and include them in replacements, or disable the Save/Preview flow until wired.

If you want, I can help draft the persistence + replacement wiring or propose a minimal “disabled until implemented” patch.

Also applies to: 3895-3968

🤖 Fix all issues with AI agents
In `@src/main/java/com/divudi/bean/inward/BhtSummeryController.java`:
- Around line 1863-1867: The VAT is being computed and persisted before bill
items are populated in saveTempBill() and saveOriginalBill(), causing zero VAT;
move the calls that compute and set VAT (calculateSelectiveVatAmount(...) and
the subsequent getTempBill().setVat(...) / getTempBill().setVatPlusNetTotal(...)
and their getOriginalBill() equivalents) to run after the corresponding
saveTempBillItem() and saveOriginalBillItem() logic so billItems exist (or
alternatively compute VAT from chargeItemTotals if those are already populated);
update both locations referenced around saveTempBill()/saveTempBillItem() and
saveOriginalBill()/saveOriginalBillItem().
- Around line 3423-3604: getAllBillItemsForEncounter() currently always returns
an empty list causing VAT calculations to be zero; implement it to collect real
BillItem objects from the current patientEncounter by iterating
patientEncounter.getBills() (or the equivalent collection of Bill objects), then
for each Bill gather its BillItems into a single list and return that; ensure
you guard for null patientEncounter and null/empty bills, and reuse this same
list for VAT calculations (e.g., calculateSelectiveVatAmount) so methods like
getVatAmount and calculateVatPlusNetTotal see the real items.

In `@src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java`:
- Around line 539-550: The code currently sets anesthesia to "General
Anesthesia" based solely on anesthesiologist presence; update the block in
InpatientClinicalDataController where fetchSurgeryDetails(encounter) is used to
read an actual anesthesia value from surgeryData (e.g.,
surgeryData.getOrDefault("anesthesia", "")) and assign that to the anesthesia
variable, falling back to an empty string if absent, and remove the
logic/comment that infers anesthesia from anesthesiologist; ensure
fetchSurgeryDetails is returning an "anesthesia" key if available.
- Around line 782-787: The replacement loop in replaceVariablesInHtml assumes
keys are wrapped with single braces and constructs "{{name}}" via substring,
missing cases where templates use "{name}" or keys already use "{{name}}";
update replaceVariablesInHtml so for each Map.Entry in replacements you derive a
normalized keyName by removing any leading/trailing braces or double-braces from
replacement.getKey(), then perform replacements for both formats (replace("{" +
keyName + "}", value) and replace("{{" + keyName + "}}", value)) only when
replacement.getValue() != null; reference the method replaceVariablesInHtml and
variables htmlTemplate, replacements, replacement.getKey(),
replacement.getValue() to locate and change the logic.

In `@src/main/java/com/divudi/bean/inward/InwardBeanController.java`:
- Around line 396-407: Replace the incorrect facade call
getBillItemFacade().findByJpql(...) with getBillFacade().findByJpql(...) since
the JPQL returns Bill entities; then fix the accumulation loop so you do not
double-invert refund/cancelled bills—RefundBill and CancelledBill store netTotal
as negative, so change the logic in the loop (the block iterating over bills and
checking instanceof RefundBill/CancelledBill) to add bill.getNetTotal() (use +=)
for those types (or simply always total += bill.getNetTotal()), instead of
subtracting, so totals aggregate correctly.

In `@src/main/java/com/divudi/bean/inward/InwardReportControllerBht.java`:
- Around line 626-635: The updateBillItemAndBill method leaves VAT values
unchanged when bill.getBillItems() is null or empty; update its logic so that
after computing netTotal you add an else branch that sets bill.setVat(0) and
bill.setVatPlusNetTotal(bill.getNetTotal()), ensuring
calculateSelectiveVatAmount is only used when bill.getBillItems() is non-empty
and stale VAT is cleared otherwise.

In `@src/main/java/com/divudi/bean/inward/SurgeryBillController.java`:
- Around line 606-630: The bug is that cancelled bill items (billItems2) are
added to billItems1 but the method returns billItems, so billItems2 never gets
returned; in SurgeryBillController inside the includeCancelledBills block (where
sql is built and billItems2 is produced) ensure the cancelled items are merged
into the actual returned list by adding billItems2 into billItems (or change the
return to billItems1 consistently), e.g., after obtaining billItems2 call
billItems.addAll(billItems2) before the method returns so the returned list
includes cancelled items.

In `@src/main/webapp/inward/admission_profile.xhtml`:
- Around line 355-370: The Ward and Local Surgery commandButtons (wardCardBtn,
localSurgeryCardBtn) navigate directly to views via
action="ward_admission_diagnosis_card" and action="local_surgery_diagnosis_card"
without initializing controller state; change them to invoke the controller
initialization method used by the existing Diagnosis Card flow (or add a
setPropertyActionListener) so the controller populates currentEncounter,
template lists and generated HTML before navigation—i.e., route through the same
backing bean action/method that prepares the model (or call that method from a
new action) rather than directly navigating to the XHTML.

In `@src/main/webapp/inward/clinical_data_diagnosis_card.xhtml`:
- Around line 728-729: The diagnosis and ward admission templates render HTML
with escape="false", so user-entered fields (e.g., comments, diagnosis names,
ward details) must be HTML-escaped before substitution; update
createReplacementsMap() to call CommonFunctions.escapeHtml() on every
user-provided value placed into the replacements map (or alternatively perform
escaping inside replaceVariablesInHtml() just before inserting values) so that
all dynamic entries (comments, diagnosis names, ward admission fields) are
sanitized before being injected into the template.

In `@src/main/webapp/inward/inward_bill_surgery_payment.xhtml`:
- Around line 52-56: The autocomplete in inward_bill_surgery_payment.xhtml is
bound to procedureController.completeProcedures which returns
List<ClinicalEntity>, but the page/model property
inwardSurgeryPaymentBillController.surgery is typed as BillItem causing a type
mismatch; fix by either changing completeProcedures to return List<BillItem>, or
changing the surgery property to type ClinicalEntity (or its compatible
interface), or add a JSF converter that converts between ClinicalEntity and
BillItem and register it on the autocomplete (referencing
procedureController.completeProcedures,
inwardSurgeryPaymentBillController.surgery, ClinicalEntity, and BillItem in your
change).

In `@src/main/webapp/inward/local_surgery_diagnosis_card.xhtml`:
- Around line 41-50: The Generate Preview button (p:commandButton
id="btnGeneratePreview") currently only submits and updates cardPreviewPanel but
doesn't invoke the backing action; add the JSF action binding to call the
local-surgery load action (e.g. action="#{localSurgery.load}" or the correct
method on the localSurgery bean) so clicking the button invokes the generation
method and refreshes cardPreviewPanel; keep process="@form" and
update="cardPreviewPanel" as-is and ensure the referenced method exists and
returns the appropriate navigation/outcome if needed.
- Around line 305-330: The local surgery page is incorrectly using diagnosis
template bindings instead of local surgery template bindings. Replace the
diagnosis-related property and method references with their local surgery
equivalents: change selectedDiagnosisTemplate to selectedLocalSurgeryTemplate in
the p:selectOneMenu value binding, change availableDiagnosisTemplates to
availableLocalSurgeryTemplates in the f:selectItems value binding, change the
loadDiagnosisCard action to the appropriate local surgery action method, and
change diagnosisCardHtml to the local surgery equivalent in both the
h:outputText value and rendered conditions. Ensure all references in the
cardPreviewPanel and cardContentArea use consistent local surgery template
naming.

In `@src/main/webapp/inward/ward_admission_diagnosis_card.xhtml`:
- Around line 1078-1108: The `@media` print CSS block in the
ward_admission_diagnosis_card.xhtml snippet is missing closing braces for the
"form, form *" rule and the overall "@media print" block; fix it by adding the
missing closing brace to terminate the "form, form *" rule and then another to
close the "@media print" block so selectors like `#docPrescreption`,
`#txtPrescriptionDoc` and form rules are valid and applied.
- Around line 558-565: The icon-only delete button with id "clRemoveDx" (action
"#{patientEncounterController.removeEncounterDiagnoses()}" and property listener
setting "#{patientEncounterController.removingCfv}") is missing an accessible
label; add a descriptive accessible label by adding either title and aria-label
attributes (e.g., title="Remove diagnosis" aria-label="Remove diagnosis") or
attach a <p:tooltip> to that <p:commandButton> so screen readers announce the
action; apply the same change to the other icon-only trash buttons referenced in
this view (the other remove buttons noted in the review).

In `@src/main/webapp/resources/inward/bill/intrimBill.xhtml`:
- Around line 202-228: The Due line currently uses cc.attrs.bill.total which
undercounts when VAT rows are rendered (cc.attrs.bill.vat > 0); update the
h:outputLabel with id="due" to compute due as (cc.attrs.bill.vat > 0 ?
cc.attrs.bill.vatPlusNetTotal : cc.attrs.bill.total) - cc.attrs.bill.paidAmount
so the component uses vatPlusNetTotal when VAT applies and keep the existing
<f:convertNumber> pattern.

In `@src/main/webapp/sections/clinical_cards_with_template_selection.xhtml`:
- Around line 32-39: The PF('...') calls fail because the <p:dialog> components
lack widgetVar attributes; add widgetVar="wardCardDialog" to the Ward Admission
Card dialog (the <p:dialog> with header="Ward Admission Card") and add the
matching widgetVar to the other dialog referenced by PF(...) so each
PF('widgetName') matches the dialog's widgetVar value, ensuring
PF('wardCardDialog').show() can resolve and open the dialog.
- Around line 1-5: Remove the CDATA wrapper around the XML declaration at the
top of the file (and the similar CDATA block at lines 110-111) so the XML
declaration appears at the document start; specifically, delete the <![CDATA[
... ]]> markers that enclose "<?xml version='1.0' encoding='UTF-8' ?>" and
ensure the declaration is the very first thing in the file so Facelets can parse
it correctly.
- Around line 41-42: The page references non-existent EL methods
generateWardAdmissionCard() and generateLocalSurgeryCard() and also binds to
properties that lack public getters; update the EL to use an existing readable
property or add getters: either change the h:outputText value to reference the
controller property that actually exists (e.g. getDiagnosisCardHtml -> use
#{inpatientClinicalDataController.diagnosisCardHtml}) or add public getters for
wardAdmissionDiagnosisCardHtml and localSurgeryDiagnosisCardHtml in
InpatientClinicalDataController so
#{inpatientClinicalDataController.wardAdmissionDiagnosisCardHtml} and
#{inpatientClinicalDataController.localSurgeryDiagnosisCardHtml} resolve; ensure
the p:ajax listeners loadWardAdmissionDiagnosisCard() and
loadLocalSurgeryDiagnosisCard() remain unchanged and return/prepare the same
properties for rendering.
🧹 Nitpick comments (6)
src/main/webapp/resources/inward/bill/intrimBill.xhtml (1)

170-183: Prefer a user‑facing charge type label.

Using inwardChargeType.name exposes enum identifiers. Consider the configurable label helper.

♻️ Suggested tweak
-    <h:outputLabel  value="#{bip.inwardChargeType.name}" />
+    <h:outputLabel value="#{bhtSummeryController.getChargeTypeLabel(bip.inwardChargeType)}" />
src/main/webapp/resources/inward/bill/finalBill.xhtml (1)

426-515: Consider consolidating bed-related charge rendering to reduce repetition.

There are five separate ui:repeat passes over the same list with identical markup. A single pass driven by a small helper (e.g., a filtered/ordered list of bed-related charge items from the controller) would reduce duplication and future update overhead.

src/main/webapp/inward/clinical_data_diagnosis_card.xhtml (1)

744-749: “Save as PDF” currently just prints and submits the form.
onclick="window.print()" plus ajax="true" triggers a server request and doesn’t actually save a PDF. Consider using a pure client-side button (type="button") or renaming the label to “Print”.

🔧 Low-impact UI tweak
- <p:commandButton 
-     value="Save as PDF" 
-     ajax="true" 
-     icon="pi pi-download"
-     onclick="window.print()"
-     styleClass="ui-button-warning"
-     rendered="#{...}" />
+ <p:commandButton 
+     value="Print" 
+     type="button"
+     icon="pi pi-print"
+     onclick="window.print()"
+     styleClass="ui-button-warning"
+     rendered="#{...}" />

Also applies to: 803-808

sql-scripts/Ward-Admission-LocalSurgery-Card-Templates.sql (1)

4-35: Consider making the seed script idempotent.
These inserts will fail or duplicate data if the script is rerun (common across environments). If code is unique, a re-run will error. Consider guarding with WHERE NOT EXISTS or using INSERT ... SELECT with a NOT EXISTS clause.

🔧 Example pattern (template type)
INSERT INTO document_template_type (id, code, name, created_date, created_user, modified_date, modified_user, retired, retired_date, retired_user, description)
SELECT UUID(), 'WARD_ADMISSION_CARD', 'Ward Admission Card', NOW(), 'system', NOW(), 'system', false, NULL, NULL,
       'Document template for ward admission records with patient, clinical, and discharge information'
WHERE NOT EXISTS (
  SELECT 1 FROM document_template_type WHERE code = 'WARD_ADMISSION_CARD'
);

Also applies to: 36-281

src/main/webapp/inward/ward_admission_diagnosis_card.xhtml (1)

667-708: Replace raw <label> tags with h:outputLabel for JSF accessibility.

This block uses plain HTML <label> without JSF binding. Prefer h:outputLabel with for to ensure proper association.

💡 Suggested fix (apply across this block)
-<label for="acMedicine" class="w-100">Medicine:</label>
+<h:outputLabel for="acMedicine" value="Medicine:" styleClass="w-100"/>

-<label>Dose:</label>
+<h:outputLabel value="Dose:"/>

As per coding guidelines, ...

src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java (1)

673-715: Replace System.out.println/printStackTrace with a logger.

Use Logger with appropriate levels to keep logs structured and avoid noisy stdout in production.

Also applies to: 734-776, 3748-3788

Comment on lines +1863 to +1867
// Calculate and save VAT for temp bill to avoid recalculation in preview
double vatAmount = calculateSelectiveVatAmount(getTempBill().getBillItems());
getTempBill().setVat(vatAmount);
getTempBill().setVatPlusNetTotal(getTempBill().getNetTotal() + vatAmount);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

VAT saved before bill items exist.

saveTempBill()/saveOriginalBill() calculate VAT from billItems before save*BillItem() populates them, so VAT is persisted as 0. Move VAT calculation after bill items are added (or compute from chargeItemTotals).

🐛 Suggested fix (move VAT calc after items are added)
-        // Calculate and save VAT for temp bill to avoid recalculation in preview
-        double vatAmount = calculateSelectiveVatAmount(getTempBill().getBillItems());
-        getTempBill().setVat(vatAmount);
-        getTempBill().setVatPlusNetTotal(getTempBill().getNetTotal() + vatAmount);
...
-        // Calculate and save VAT for original bill to avoid recalculation in preview
-        double vatAmount = calculateSelectiveVatAmount(getOriginalBill().getBillItems());
-        getOriginalBill().setVat(vatAmount);
-        getOriginalBill().setVatPlusNetTotal(getOriginalBill().getNetTotal() + vatAmount);
// After saveTempBillItem()
double vatAmount = calculateSelectiveVatAmount(getTempBill().getBillItems());
getTempBill().setVat(vatAmount);
getTempBill().setVatPlusNetTotal(getTempBill().getNetTotal() + vatAmount);

// After saveOriginalBillItem()
double vatAmount = calculateSelectiveVatAmount(getOriginalBill().getBillItems());
getOriginalBill().setVat(vatAmount);
getOriginalBill().setVatPlusNetTotal(getOriginalBill().getNetTotal() + vatAmount);

Also applies to: 1897-1901

🤖 Prompt for AI Agents
In `@src/main/java/com/divudi/bean/inward/BhtSummeryController.java` around lines
1863 - 1867, The VAT is being computed and persisted before bill items are
populated in saveTempBill() and saveOriginalBill(), causing zero VAT; move the
calls that compute and set VAT (calculateSelectiveVatAmount(...) and the
subsequent getTempBill().setVat(...) / getTempBill().setVatPlusNetTotal(...) and
their getOriginalBill() equivalents) to run after the corresponding
saveTempBillItem() and saveOriginalBillItem() logic so billItems exist (or
alternatively compute VAT from chargeItemTotals if those are already populated);
update both locations referenced around saveTempBill()/saveTempBillItem() and
saveOriginalBill()/saveOriginalBillItem().

Comment on lines +3423 to +3604
/**
* Check if VAT is enabled via application option
* Default: false (VAT disabled)
*/
public boolean isVatEnabled() {
return configOptionApplicationController.getBooleanValueByKey("Enable VAT in Bills", false);
}

/**
* Get VAT percentage from application option
* Default: 18
*/
public double getVatPercentage() {
try {
Double vatPercent = configOptionApplicationController.getDoubleValueByKey("VAT Percentage", 18.0);
return vatPercent != null ? vatPercent : 18.0;
} catch (Exception e) {
return 18.0;
}
}

/**
* Get VAT percentage for a specific charge type
* Application option format: "VAT Percentage For [ChargeTypeName]"
* Falls back to global VAT Percentage if not found
*/
public double getVatPercentageForChargeType(InwardChargeType chargeType) {
if (chargeType == null) {
return getVatPercentage();
}

try {
String optionKey = "VAT Percentage For " + chargeType.name();
Double vatPercent = configOptionApplicationController.getDoubleValueByKey(optionKey, null);

// If charge-type-specific percentage exists, use it
if (vatPercent != null && vatPercent > 0) {
return vatPercent;
}

// Otherwise fall back to global VAT percentage
return getVatPercentage();
} catch (Exception e) {
return getVatPercentage();
}
}

/**
* Calculate VAT amount based on vatable charge types in bill items
* Only includes charges marked as vatable
*/
public double calculateVatAmount(List<BillItem> billItems) {
return calculateSelectiveVatAmount(billItems);
}

/**
* Calculate total with VAT (Net Total + Selective VAT)
* VAT is only applied to vatable charge types
*/
public double calculateVatPlusNetTotal(double netTotal, List<BillItem> billItems) {
if (!isVatEnabled()) {
return netTotal;
}
return netTotal + calculateSelectiveVatAmount(billItems);
}

/**
* Get VAT label from application option
* Default: "VAT"
*/
public String getVatLabel() {
String label = configOptionApplicationController.getLongTextValueByKey("VAT Label", "VAT");
return label != null ? label : "VAT";
}

/**
* Check if a specific InwardChargeType should have VAT applied
* Application option format: "VAT Enabled For [ChargeTypeName]"
* Default: false (VAT disabled for specific charge type)
*/
public boolean isChargeTypeVatable(InwardChargeType chargeType) {
if (chargeType == null || !isVatEnabled()) {
return false;
}
String optionKey = "VAT Enabled For " + chargeType.name();
return configOptionApplicationController.getBooleanValueByKey(optionKey, false);
}

/**
* Calculate VAT amount for a specific charge type
* Only applies VAT if that charge type is marked as vatable
* Uses charge-type-specific VAT percentage if configured
*/
public double calculateVatAmountForChargeType(double amount, InwardChargeType chargeType) {
if (!isChargeTypeVatable(chargeType) || amount <= 0) {
return 0.0;
}
double vatPercent = getVatPercentageForChargeType(chargeType);
return amount * (vatPercent / 100.0);
}

/**
* Calculate VAT amount only for specified charge types from bill items
* Sums VAT for items whose charge type is marked as vatable
*/
public double calculateSelectiveVatAmount(List<BillItem> billItems) {
if (!isVatEnabled() || billItems == null || billItems.isEmpty()) {
return 0.0;
}
double totalVat = 0.0;
for (BillItem item : billItems) {
if (item.getAdjustedValue() != 0 && item.getInwardChargeType() != null) {
if (isChargeTypeVatable(item.getInwardChargeType())) {
totalVat += calculateVatAmountForChargeType(item.getAdjustedValue(), item.getInwardChargeType());
}
}
}
return totalVat;
}

/**
* Get the name/label for a specific charge type (supports customization via application option)
* Format: "Inward Charge Type - Name For [ChargeTypeName]"
* Default: charge type's label
*/
public String getChargeTypeLabel(InwardChargeType chargeType) {
if (chargeType == null) {
return "";
}
try {
String label = configOptionApplicationController.getLongTextValueByKey(
"Inward Charge Type - Name For " + chargeType.name(),
chargeType.getLabel()
);
return label != null ? label : chargeType.getLabel();
} catch (Exception e) {
return chargeType.getLabel();
}
}

/**
* Calculate VAT amount - public method that can be called from templates
* Returns 0 if VAT is not enabled or no items to calculate
*/
public double getVatAmount() {
try {
// If not enabled, return 0
if (!isVatEnabled()) {
return 0.0;
}

// If no patient encounter, return 0
if (patientEncounter == null) {
return 0.0;
}

// Calculate VAT from charge item totals (more reliable for interim bills)
double totalVat = 0.0;
if (chargeItemTotals != null && !chargeItemTotals.isEmpty()) {
for (ChargeItemTotal cit : chargeItemTotals) {
if (cit.getInwardChargeType() != null && isChargeTypeVatable(cit.getInwardChargeType())) {
totalVat += calculateVatAmountForChargeType(cit.getAdjustedTotal(), cit.getInwardChargeType());
}
}
}

return totalVat;
} catch (Exception e) {
return 0.0;
}
}

/**
* Get all bill items for the current patient encounter
* Used for VAT calculation in interim and final bills
*/
public List<BillItem> getAllBillItemsForEncounter() {
if (patientEncounter == null) {
return new ArrayList<>();
}
return new ArrayList<>();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

getAllBillItemsForEncounter() always returns empty.

Any VAT/template logic that uses this will show zero VAT/items. Implement a real fetch (or remove if unused).

🐛 Suggested fix
     public List<BillItem> getAllBillItemsForEncounter() {
         if (patientEncounter == null) {
             return new ArrayList<>();
         }
-        return new ArrayList<>();
+        String jpql = "select bi from BillItem bi where bi.retired=false and bi.bill.patientEncounter=:pe";
+        Map<String, Object> params = new HashMap<>();
+        params.put("pe", patientEncounter);
+        return getBillItemFacade().findByJpql(jpql, params);
     }
🤖 Prompt for AI Agents
In `@src/main/java/com/divudi/bean/inward/BhtSummeryController.java` around lines
3423 - 3604, getAllBillItemsForEncounter() currently always returns an empty
list causing VAT calculations to be zero; implement it to collect real BillItem
objects from the current patientEncounter by iterating
patientEncounter.getBills() (or the equivalent collection of Bill objects), then
for each Bill gather its BillItems into a single list and return that; ensure
you guard for null patientEncounter and null/empty bills, and reuse this same
list for VAT calculations (e.g., calculateSelectiveVatAmount) so methods like
getVatAmount and calculateVatPlusNetTotal see the real items.

Comment on lines +539 to +550
// Fetch surgery details from EncounterComponent records
try {
Map<String, String> surgeryData = fetchSurgeryDetails(encounter);
if (surgeryData != null) {
surgeryName = surgeryData.getOrDefault("procedure", "");
surgeryProcedure = surgeryData.getOrDefault("procedure", "");
surgeryPerformedBy = surgeryData.getOrDefault("surgeon", "");
surgeryAssistant = surgeryData.getOrDefault("assistant", "");
anesthesiologist = surgeryData.getOrDefault("anesthesiologist", "");
// For anesthesia type, we use the same anesthesiologist info (can be extended if more data exists)
anesthesia = anesthesiologist.isEmpty() ? "" : "General Anesthesia";
surgeryDate = surgeryData.getOrDefault("date", "");
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t hardcode anesthesia type to “General Anesthesia.”

Setting anesthesia based solely on anesthesiologist presence can produce inaccurate clinical data. Use an actual captured value or leave it blank until sourced.

💡 Suggested fix
-                anesthesia = anesthesiologist.isEmpty() ? "" : "General Anesthesia";
+                anesthesia = surgeryData.getOrDefault("anesthesia", "");
🤖 Prompt for AI Agents
In `@src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java`
around lines 539 - 550, The code currently sets anesthesia to "General
Anesthesia" based solely on anesthesiologist presence; update the block in
InpatientClinicalDataController where fetchSurgeryDetails(encounter) is used to
read an actual anesthesia value from surgeryData (e.g.,
surgeryData.getOrDefault("anesthesia", "")) and assign that to the anesthesia
variable, falling back to an empty string if absent, and remove the
logic/comment that infers anesthesia from anesthesiologist; ensure
fetchSurgeryDetails is returning an "anesthesia" key if available.

Comment on lines +782 to +787
public String replaceVariablesInHtml(String htmlTemplate, Map<String, String> replacements) {
String result = htmlTemplate;
for (Map.Entry<String, String> replacement : replacements.entrySet()) {
if (replacement.getValue() != null) {
result = result.replace("{{" + replacement.getKey().substring(1, replacement.getKey().length() - 1) + "}}", replacement.getValue());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Placeholder replacement only matches {{var}}, but your keys are {var}.

replaceVariablesInHtml transforms {name} into {{name}}, so existing single‑brace templates won’t be replaced. Either standardize on one format or support both.

💡 Suggested fix (support both)
-            if (replacement.getValue() != null) {
-                result = result.replace("{{" + replacement.getKey().substring(1, replacement.getKey().length() - 1) + "}}", replacement.getValue());
-            }
+            if (replacement.getValue() != null) {
+                result = result
+                        .replace(replacement.getKey(), replacement.getValue())
+                        .replace("{{" + replacement.getKey().substring(1, replacement.getKey().length() - 1) + "}}", replacement.getValue());
+            }
🤖 Prompt for AI Agents
In `@src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java`
around lines 782 - 787, The replacement loop in replaceVariablesInHtml assumes
keys are wrapped with single braces and constructs "{{name}}" via substring,
missing cases where templates use "{name}" or keys already use "{{name}}";
update replaceVariablesInHtml so for each Map.Entry in replacements you derive a
normalized keyName by removing any leading/trailing braces or double-braces from
replacement.getKey(), then perform replacements for both formats (replace("{" +
keyName + "}", value) and replace("{{" + keyName + "}}", value)) only when
replacement.getValue() != null; reference the method replaceVariablesInHtml and
variables htmlTemplate, replacements, replacement.getKey(),
replacement.getValue() to locate and change the logic.

Comment on lines +396 to +407
List<Bill> bills = getBillItemFacade().findByJpql(sql, hm);
double total = 0;

// Calculate total with sign inversion for cancelled and refund bills
for (Bill bill : bills) {
// For RefundBill and CancelledBill, invert the value (deduct instead of add)
if (bill instanceof RefundBill || bill instanceof CancelledBill) {
total -= bill.getNetTotal();
} else {
total += bill.getNetTotal();
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, find and examine the exact code at lines 396-407 in InwardBeanController.java
find . -name "InwardBeanController.java" -type f

Repository: hmislk/hmis

Length of output: 119


🏁 Script executed:

#!/bin/bash
# Examine the file and show lines around 396
cat -n src/main/java/com/divudi/bean/inward/InwardBeanController.java | sed -n '380,415p'

Repository: hmislk/hmis

Length of output: 1755


🏁 Script executed:

#!/bin/bash
# Search for getBillItemFacade and getBillFacade definitions to understand their types
rg "getBillItemFacade|getBillFacade" --type java -B 2 -A 2 src/main/java/com/divudi/bean/inward/InwardBeanController.java | head -50

Repository: hmislk/hmis

Length of output: 1240


🏁 Script executed:

#!/bin/bash
# Search for how RefundBill and CancelledBill netTotal values are handled in similar contexts
rg "RefundBill|CancelledBill" --type java -B 3 -A 3 | grep -E "(netTotal|getNetTotal|instanceof)" | head -40

Repository: hmislk/hmis

Length of output: 5670


🏁 Script executed:

#!/bin/bash
# Check the facade implementations
rg "class.*BillFacade|class.*BillItemFacade" --type java -A 5 | head -50

Repository: hmislk/hmis

Length of output: 4583


🏁 Script executed:

#!/bin/bash
# Search for how RefundBill and CancelledBill netTotal values are set or calculated
rg "RefundBill|CancelledBill" --type java -B 5 -A 5 | grep -E "(setNetTotal|netTotal\s*=|getNetTotal)" | head -50

Repository: hmislk/hmis

Length of output: 7760


🏁 Script executed:

#!/bin/bash
# Look for other methods in InwardBeanController that handle RefundBill/CancelledBill
rg -n "RefundBill|CancelledBill" src/main/java/com/divudi/bean/inward/InwardBeanController.java -B 5 -A 5

Repository: hmislk/hmis

Length of output: 4257


🏁 Script executed:

#!/bin/bash
# Check if getBillFacade exists in InwardBeanController
rg "getBillFacade\(\)" --type java src/main/java/com/divudi/bean/inward/InwardBeanController.java

Repository: hmislk/hmis

Length of output: 1167


🏁 Script executed:

#!/bin/bash
# Find similar bill total calculation patterns in this controller
rg "instanceof.*Bill" --type java -B 3 -A 3 src/main/java/com/divudi/bean/inward/InwardBeanController.java | head -60

Repository: hmislk/hmis

Length of output: 699


Critical: Wrong facade used for Bill entity query.

Line 396 uses getBillItemFacade() to execute a query that selects Bill entities. This is incorrect and will cause runtime issues.

The query "SELECT b FROM Bill b ..." returns Bill entities, so it must use getBillFacade().

Additionally, the sign inversion logic for RefundBill and CancelledBill appears incorrect. Based on codebase patterns (e.g., DealorPaymentBillSearch.java, InwardRefundController.java), refund and cancelled bills store netTotal as negative values. Subtracting a negative value adds instead of subtracts. The logic should likely use += for these bill types to correctly deduct their values, or the values should be stored as positive before subtraction.

🐛 Proposed fix for facade
-        List<Bill> bills = getBillItemFacade().findByJpql(sql, hm);
+        List<Bill> bills = getBillFacade().findByJpql(sql, hm);
🤖 Prompt for AI Agents
In `@src/main/java/com/divudi/bean/inward/InwardBeanController.java` around lines
396 - 407, Replace the incorrect facade call getBillItemFacade().findByJpql(...)
with getBillFacade().findByJpql(...) since the JPQL returns Bill entities; then
fix the accumulation loop so you do not double-invert refund/cancelled
bills—RefundBill and CancelledBill store netTotal as negative, so change the
logic in the loop (the block iterating over bills and checking instanceof
RefundBill/CancelledBill) to add bill.getNetTotal() (use +=) for those types (or
simply always total += bill.getNetTotal()), instead of subtracting, so totals
aggregate correctly.

Comment on lines +1078 to +1108
<style>
@media print {
/* Target the ui-texteditor container and its children */
#docPrescreption .ui-texteditor,
#docPrescreption .ui-texteditor *,
#docPrescreption .ui-texteditor *::after,
#docPrescreption .ui-texteditor *::before {
border: none !important;
box-sizing: content-box !important; /* Reset box-sizing */
/* Additional styles to reset other properties if needed */
}

/* Ensure that the specific ids are targeted */
#txtPrescriptionDoc,
#txtPrescriptionDoc * {
border: none !important;
box-sizing: content-box !important;
/* Reset other styles, if necessary */
}

/* If there are iframes or other embedded elements, target them too */
#txtPrescriptionDoc iframe,
#txtPrescriptionDoc iframe * {
border: none !important;
box-sizing: content-box !important;
/* Reset other styles, if necessary */
}

form, form * {
border: none !important;
</style>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and get its total line count
wc -l src/main/webapp/inward/ward_admission_diagnosis_card.xhtml

Repository: hmislk/hmis

Length of output: 118


🏁 Script executed:

# Read the actual lines 1078-1108 and some context before and after
sed -n '1070,1115p' src/main/webapp/inward/ward_admission_diagnosis_card.xhtml | cat -n

Repository: hmislk/hmis

Length of output: 3344


CSS @media print block is missing closing braces.

The print styles are unterminated. The form, form * rule and @media print block lack closing braces, creating invalid CSS that will prevent the styles from being applied.

💡 Suggested fix
                                                        form, form * {
                                                            border: none !important;
+                                                        }
+                                                    }
                                                </style>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<style>
@media print {
/* Target the ui-texteditor container and its children */
#docPrescreption .ui-texteditor,
#docPrescreption .ui-texteditor *,
#docPrescreption .ui-texteditor *::after,
#docPrescreption .ui-texteditor *::before {
border: none !important;
box-sizing: content-box !important; /* Reset box-sizing */
/* Additional styles to reset other properties if needed */
}
/* Ensure that the specific ids are targeted */
#txtPrescriptionDoc,
#txtPrescriptionDoc * {
border: none !important;
box-sizing: content-box !important;
/* Reset other styles, if necessary */
}
/* If there are iframes or other embedded elements, target them too */
#txtPrescriptionDoc iframe,
#txtPrescriptionDoc iframe * {
border: none !important;
box-sizing: content-box !important;
/* Reset other styles, if necessary */
}
form, form * {
border: none !important;
</style>
<style>
`@media` print {
/* Target the ui-texteditor container and its children */
`#docPrescreption` .ui-texteditor,
`#docPrescreption` .ui-texteditor *,
`#docPrescreption` .ui-texteditor *::after,
`#docPrescreption` .ui-texteditor *::before {
border: none !important;
box-sizing: content-box !important; /* Reset box-sizing */
/* Additional styles to reset other properties if needed */
}
/* Ensure that the specific ids are targeted */
`#txtPrescriptionDoc`,
`#txtPrescriptionDoc` * {
border: none !important;
box-sizing: content-box !important;
/* Reset other styles, if necessary */
}
/* If there are iframes or other embedded elements, target them too */
`#txtPrescriptionDoc` iframe,
`#txtPrescriptionDoc` iframe * {
border: none !important;
box-sizing: content-box !important;
/* Reset other styles, if necessary */
}
form, form * {
border: none !important;
}
}
</style>
🤖 Prompt for AI Agents
In `@src/main/webapp/inward/ward_admission_diagnosis_card.xhtml` around lines 1078
- 1108, The `@media` print CSS block in the ward_admission_diagnosis_card.xhtml
snippet is missing closing braces for the "form, form *" rule and the overall
"@media print" block; fix it by adding the missing closing brace to terminate
the "form, form *" rule and then another to close the "@media print" block so
selectors like `#docPrescreption`, `#txtPrescriptionDoc` and form rules are valid
and applied.

Comment on lines +202 to +228
<!-- VAT Row (Selective - only for vatable charges) - Uses pre-calculated value from bill entity -->
<h:panelGroup rendered="#{cc.attrs.bill.vat > 0}">
<tr>
<td style="text-align: left; font-size: 12px!important;">
<h:outputLabel value="#{bhtSummeryController.getVatLabel()} (#{bhtSummeryController.getVatPercentage()}%)" />
</td>
<td style="text-align: right; font-size: 12px!important;">
<h:outputLabel value="#{cc.attrs.bill.vat}" >
<f:convertNumber pattern="#,##0.00" />
</h:outputLabel>
</td>
</tr>
</h:panelGroup>

<!-- VAT Plus Total Row (Selective) - Uses pre-calculated value from bill entity -->
<h:panelGroup rendered="#{cc.attrs.bill.vat > 0}">
<tr style="width: 100%;">
<td style="text-align: left; font-size: 13px!important;font-weight: bold!important;">
<h:outputLabel value="#{bhtSummeryController.getVatLabel()} + Total"/>
</td>
<td style="text-align: right;font-size: 13px!important;font-weight: bold!important;">
<h:outputLabel value="#{cc.attrs.bill.vatPlusNetTotal}" >
<f:convertNumber pattern="#,##0.00" />
</h:outputLabel>
</td>
</tr>
</h:panelGroup>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Due amount ignores VAT when VAT rows are shown.

You now show VAT and VAT+Total, but the Due line below still uses bill.total. That under‑reports when VAT applies. Base Due on vatPlusNetTotal when vat > 0.

<h:outputLabel id="due"
    value="#{(cc.attrs.bill.vat > 0 ? cc.attrs.bill.vatPlusNetTotal : cc.attrs.bill.total) - cc.attrs.bill.paidAmount}">
    <f:convertNumber pattern="#,##0.00"/>
</h:outputLabel>
🤖 Prompt for AI Agents
In `@src/main/webapp/resources/inward/bill/intrimBill.xhtml` around lines 202 -
228, The Due line currently uses cc.attrs.bill.total which undercounts when VAT
rows are rendered (cc.attrs.bill.vat > 0); update the h:outputLabel with
id="due" to compute due as (cc.attrs.bill.vat > 0 ?
cc.attrs.bill.vatPlusNetTotal : cc.attrs.bill.total) - cc.attrs.bill.paidAmount
so the component uses vatPlusNetTotal when VAT applies and keep the existing
<f:convertNumber> pattern.

Comment on lines +1 to +5
<![CDATA[<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and read the relevant lines
cd src/main/webapp/sections && head -15 clinical_cards_with_template_selection.xhtml

Repository: hmislk/hmis

Length of output: 746


🏁 Script executed:

# Also check lines 110-111
cd src/main/webapp/sections && sed -n '105,115p' clinical_cards_with_template_selection.xhtml

Repository: hmislk/hmis

Length of output: 194


🌐 Web query:

Facelets CDATA wrapper XML declaration parsing behavior

💡 Result:

Short answer
Facelets (XHTML/JSF) must not emit an XML declaration () anywhere except at the very start of the overall XML/XHTML document. If a CDATA-wrapped snippet or included Facelets file contains a the XML parser will error with "XML or text declaration not at start of entity" because declarations inside content (including inside CDATA output) are not allowed. Fix: remove the extra from fragments (use ui:composition or omit the declaration) or ensure the fragment is treated as plain text (not a separate XML prolog). [1][2]

References

  • Stack Overflow: "XML or text declaration not at start of entity" — explains the error and shows that included Facelets must be wrapped in ui:composition and must not contain extra prologs. [1]
  • Facelets/JSF guidance on using CDATA for script/content and avoiding parser problems (use CDATA for script or place scripts externally; avoid stray XML declarations in includes). [2]

Remove the CDATA wrapper; it breaks Facelets parsing.

Wrapping the XML declaration in CDATA prevents the XML parser from recognizing it as a declaration (declarations must appear at the document start, not inside CDATA content). This causes "XML or text declaration not at start of entity" parser errors in Facelets.

💡 Suggested fix
-<![CDATA[<?xml version='1.0' encoding='UTF-8' ?>
+<?xml version='1.0' encoding='UTF-8' ?>
 <!DOCTYPE composition PUBLIC
     "-//W3C//DTD XHTML 1.0 Transitional//EN"
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
 <ui:composition xmlns="http://www.w3.org/1999/xhtml"
-...
-</ui:composition>
-]]>
+...
+</ui:composition>

Also applies to: lines 110-111

🤖 Prompt for AI Agents
In `@src/main/webapp/sections/clinical_cards_with_template_selection.xhtml` around
lines 1 - 5, Remove the CDATA wrapper around the XML declaration at the top of
the file (and the similar CDATA block at lines 110-111) so the XML declaration
appears at the document start; specifically, delete the <![CDATA[ ... ]]>
markers that enclose "<?xml version='1.0' encoding='UTF-8' ?>" and ensure the
declaration is the very first thing in the file so Facelets can parse it
correctly.

Comment on lines +32 to +39
onclick="PF('wardCardDialog').show();"
styleClass="ui-button-success"/>
</h:panelGrid>

<!-- Ward Admission Card Dialog -->
<p:dialog id="wardCardDialog" header="Ward Admission Card"
modal="true" width="900" height="600" maximizable="true"
closable="true" resizable="true">
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd "clinical_cards_with_template_selection.xhtml" --type f

Repository: hmislk/hmis

Length of output: 124


🏁 Script executed:

cat -n src/main/webapp/sections/clinical_cards_with_template_selection.xhtml | sed -n '25,95p'

Repository: hmislk/hmis

Length of output: 4277


Add widgetVar attributes to both dialog components; PrimeFaces requires it to resolve PF('...') references.

Both p:dialog elements use PF() in their onclick handlers but lack the required widgetVar attribute. Without it, the dialogs cannot be opened or closed.

Suggested fix
-<p:dialog id="wardCardDialog" header="Ward Admission Card"
+<p:dialog id="wardCardDialog" widgetVar="wardCardDialog" header="Ward Admission Card"
 modal="true" width="900" height="600" maximizable="true"
 closable="true" resizable="true">
-<p:dialog id="surgeryCardDialog" header="Surgical Procedure Record"
+<p:dialog id="surgeryCardDialog" widgetVar="surgeryCardDialog" header="Surgical Procedure Record"
 modal="true" width="900" height="600" maximizable="true"
 closable="true" resizable="true">
🤖 Prompt for AI Agents
In `@src/main/webapp/sections/clinical_cards_with_template_selection.xhtml` around
lines 32 - 39, The PF('...') calls fail because the <p:dialog> components lack
widgetVar attributes; add widgetVar="wardCardDialog" to the Ward Admission Card
dialog (the <p:dialog> with header="Ward Admission Card") and add the matching
widgetVar to the other dialog referenced by PF(...) so each PF('widgetName')
matches the dialog's widgetVar value, ensuring PF('wardCardDialog').show() can
resolve and open the dialog.

Comment on lines +41 to +42
<h:outputText value="#{inpatientClinicalDataController.generateWardAdmissionCard()}"
escape="false"/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "InpatientClinicalDataController.java" | head -20

Repository: hmislk/hmis

Length of output: 166


🏁 Script executed:

find . -type f -name "clinical_cards_with_template_selection.xhtml" | head -20

Repository: hmislk/hmis

Length of output: 126


🏁 Script executed:

rg "class InpatientClinicalDataController" -t java

Repository: hmislk/hmis

Length of output: 199


🏁 Script executed:

cat -n ./src/main/webapp/sections/clinical_cards_with_template_selection.xhtml | sed -n '30,100p'

Repository: hmislk/hmis

Length of output: 4263


🏁 Script executed:

wc -l src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 133


🏁 Script executed:

cat -n src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java | grep -A 5 "generateWardAdmissionCard\|generateLocalSurgeryCard"

Repository: hmislk/hmis

Length of output: 37


🏁 Script executed:

rg "wardAdmissionDiagnosisCardHtml|localSurgeryDiagnosisCardHtml" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 897


🏁 Script executed:

rg "public.*generate|public.*load|public.*ward|public.*surgery" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 1512


🏁 Script executed:

rg "public.*getWardAdmissionDiagnosisCardHtml|public.*getLocalSurgeryDiagnosisCardHtml" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 37


🏁 Script executed:

rg "getWardAdmissionDiagnosisCardHtml|getLocalSurgeryDiagnosisCardHtml" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 37


🏁 Script executed:

rg "^\s+public\s+String\s+get" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java | head -30

Repository: hmislk/hmis

Length of output: 1632


🏁 Script executed:

cat -n src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java | grep -E "^\s*(private|public).*(wardAdmissionDiagnosisCardHtml|localSurgeryDiagnosisCardHtml)" -A 3 -B 1

Repository: hmislk/hmis

Length of output: 37


🏁 Script executed:

rg "wardAdmissionDiagnosisCardHtml|localSurgeryDiagnosisCardHtml" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java -B 2 -A 2

Repository: hmislk/hmis

Length of output: 1540


🏁 Script executed:

sed -n '1,4169p' src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java | grep -E "public\s+(String\s+)?get(WardAdmission|LocalSurgery)" | head -20

Repository: hmislk/hmis

Length of output: 37


🏁 Script executed:

sed -n '1,4169p' src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java | grep -E "^\s*(public|private|protected)\s+(String|void)\s+(get|load|generate)" | grep -i "ward\|surgery"

Repository: hmislk/hmis

Length of output: 299


🏁 Script executed:

sed -n '1,4169p' src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java | grep -n "loadWardAdmissionDiagnosisCard\|loadLocalSurgeryDiagnosisCard" -A 20 | head -60

Repository: hmislk/hmis

Length of output: 2505


🏁 Script executed:

sed -n '1,4169p' src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java | tail -100 | head -50

Repository: hmislk/hmis

Length of output: 2820


🏁 Script executed:

sed -n '1,4169p' src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java | grep -n "public String getWardAdmissionDiagnosisCardHtml\|public String getLocalSurgeryDiagnosisCardHtml"

Repository: hmislk/hmis

Length of output: 37


🏁 Script executed:

sed -n '4100,4169p' src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 3369


🏁 Script executed:

rg "selectedDiagnosisCardTypeHtml|getSelectedDiagnosisCardTypeHtml" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java -B 2 -A 2

Repository: hmislk/hmis

Length of output: 878


🏁 Script executed:

grep -n "public.*getWardAdmission\|public.*getLocalSurgery" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 121


🏁 Script executed:

rg "public String getSelectedDiagnosisCardTypeHtml|public String getDiagnosisCardHtml" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java -B 2 -A 2

Repository: hmislk/hmis

Length of output: 144


🏁 Script executed:

rg "public.*selectedDiagnosisCardTypeHtml|public.*diagnosisCardHtml" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 119


🏁 Script executed:

rg "public String getSelectedDiagnosisCardTypeHtml|selectedDiagnosisCardTypeHtml" src/main/java/com/divudi/bean/inward/InpatientClinicalDataController.java

Repository: hmislk/hmis

Length of output: 247


🏁 Script executed:

cat -n ./src/main/webapp/sections/clinical_cards_with_template_selection.xhtml | sed -n '1,60p'

Repository: hmislk/hmis

Length of output: 3476


🏁 Script executed:

cat -n ./src/main/webapp/sections/clinical_cards_with_template_selection.xhtml | sed -n '60,95p'

Repository: hmislk/hmis

Length of output: 2295


EL methods referenced here don't exist in the controller, and the suggested fix is incomplete.

generateWardAdmissionCard() / generateLocalSurgeryCard() methods don't exist in InpatientClinicalDataController. The suggested binding to wardAdmissionDiagnosisCardHtml and localSurgeryDiagnosisCardHtml is partially correct (these properties exist), but they have no public getters—EL binding would also fail.

The load methods loadWardAdmissionDiagnosisCard() and loadLocalSurgeryDiagnosisCard() exist and are correctly invoked via p:ajax listeners. To fix this, either:

  1. Add public getters for wardAdmissionDiagnosisCardHtml and localSurgeryDiagnosisCardHtml, or
  2. Verify if getDiagnosisCardHtml() is the intended property and bind to that instead.

Also applies to: 91-92

🤖 Prompt for AI Agents
In `@src/main/webapp/sections/clinical_cards_with_template_selection.xhtml` around
lines 41 - 42, The page references non-existent EL methods
generateWardAdmissionCard() and generateLocalSurgeryCard() and also binds to
properties that lack public getters; update the EL to use an existing readable
property or add getters: either change the h:outputText value to reference the
controller property that actually exists (e.g. getDiagnosisCardHtml -> use
#{inpatientClinicalDataController.diagnosisCardHtml}) or add public getters for
wardAdmissionDiagnosisCardHtml and localSurgeryDiagnosisCardHtml in
InpatientClinicalDataController so
#{inpatientClinicalDataController.wardAdmissionDiagnosisCardHtml} and
#{inpatientClinicalDataController.localSurgeryDiagnosisCardHtml} resolve; ensure
the p:ajax listeners loadWardAdmissionDiagnosisCard() and
loadLocalSurgeryDiagnosisCard() remain unchanged and return/prepare the same
properties for rendering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants