How to Create a Printing Page - hmislk/hmis GitHub Wiki
The system has several receipts / bills to print: OPD Bills, Pharmacy Retail Sale Bills, Pharmacy Adjustment Bills, etc.
The different installations have different printers, paper sizes and configuration requirements.
A new flexible configuration method is introduced to handle the customization efficiently.
CSS styles, headers, and footers are stored as configuration options. They are loaded at the onset of the application. The system now provides:
- Common Default Configurations - Fallback settings used when specific configurations are not available
- Specific Bill Type Configurations - Individual settings for each bill type that can be customized independently
- Automatic Fallback Logic - If a specific configuration is empty, the system automatically uses the common default
-
Pharmacy Common Bill CSS
- Default CSS used by all pharmacy bills -
Pharmacy Common Bill Header
- Default header content -
Pharmacy Common Bill Footer
- Default footer content
For different bill types, you can create specific configurations:
Pharmacy Adjustments:
Pharmacy Adjustment Purchase Rate CSS/Header/Footer
Pharmacy Adjustment Cost Rate CSS/Header/Footer
Pharmacy Adjustment Retail Rate CSS/Header/Footer
Pharmacy Adjustment Stock CSS/Header/Footer
Pharmacy Adjustment Wholesale Rate CSS/Header/Footer
Other Pharmacy Bills:
Pharmacy Issue Receipt CSS/Header/Footer
Pharmacy Transfer Issue Receipt CSS/Header/Footer
Pharmacy Transfer Receive Receipt CSS/Header/Footer
- And many more...
@Named
@ApplicationScoped
public class ConfigOptionApplicationController implements Serializable {
@PostConstruct
public void init() {
loadApplicationOptions();
}
public void loadApplicationOptions() {
applicationOptions = new HashMap<>();
List<ConfigOption> options = getApplicationOptions();
for (ConfigOption option : options) {
applicationOptions.put(option.getOptionKey(), option);
}
loadEmailGatewayConfigurationDefaults();
loadPharmacyConfigurationDefaults();
loadPharmacyIssueReceiptConfigurationDefaults();
loadPharmacyCommonBillConfigurationDefaults(); // NEW: Common defaults
loadPharmacyAdjustmentReceiptConfigurationDefaults(); // NEW: Specific adjustments
}
// NEW: Common default configuration loader
private void loadPharmacyCommonBillConfigurationDefaults() {
getLongTextValueByKey("Pharmacy Common Bill CSS",
".receipt-container {\n"
+ " font-family: Verdana, sans-serif;\n"
+ " font-size: 12px;\n"
+ " color: #000;\n"
+ " width: 21cm;\n"
+ " margin: auto;\n"
+ " page-break-inside: avoid;\n"
+ "}\n"
+ ".receipt-header {\n"
+ " margin-bottom: 15px;\n"
+ " text-align: center;\n"
+ "}\n"
+ ".receipt-institution-name {\n"
+ " font-weight: bold;\n"
+ " font-size: 18px;\n"
+ " margin-bottom: 5px;\n"
+ "}\n"
+ ".receipt-institution-contact {\n"
+ " font-size: 10px;\n"
+ " margin-bottom: 10px;\n"
+ "}\n"
+ ".receipt-title {\n"
+ " text-align: center;\n"
+ " font-size: 16px;\n"
+ " font-weight: bold;\n"
+ " margin: 15px 0;\n"
+ " text-decoration: underline;\n"
+ "}\n"
+ ".receipt-separator {\n"
+ " margin: 10px 0;\n"
+ " border-top: 1px solid #333;\n"
+ "}\n"
+ ".receipt-details-table {\n"
+ " width: 100%;\n"
+ " margin-bottom: 15px;\n"
+ " border-collapse: collapse;\n"
+ "}\n"
+ ".receipt-details-table td {\n"
+ " padding: 3px 5px;\n"
+ " vertical-align: top;\n"
+ "}\n"
+ ".receipt-details-table td:first-child {\n"
+ " font-weight: bold;\n"
+ " width: 20%;\n"
+ "}\n"
+ ".receipt-details-table td:nth-child(2) {\n"
+ " width: 5%;\n"
+ " text-align: center;\n"
+ "}\n"
+ ".noBorder, .noBorder td, .noBorder th {\n"
+ " border: none !important;\n"
+ "}\n"
+ ".normalFont {\n"
+ " font-size: 12px;\n"
+ "}\n"
+ ".text-end {\n"
+ " text-align: right;\n"
+ "}\n"
+ "@media print {\n"
+ " .receipt-container {\n"
+ " margin: 0;\n"
+ " page-break-after: always;\n"
+ " }\n"
+ "}\n"
);
getLongTextValueByKey("Pharmacy Common Bill Header", "");
getLongTextValueByKey("Pharmacy Common Bill Footer", "");
}
// NEW: Specific adjustment configurations (initially empty, can be customized)
private void loadPharmacyAdjustmentReceiptConfigurationDefaults() {
// Purchase Rate Adjustment specific configurations
getLongTextValueByKey("Pharmacy Adjustment Purchase Rate CSS", "");
getLongTextValueByKey("Pharmacy Adjustment Purchase Rate Header", "");
getLongTextValueByKey("Pharmacy Adjustment Purchase Rate Footer", "");
// Cost Rate Adjustment specific configurations
getLongTextValueByKey("Pharmacy Adjustment Cost Rate CSS", "");
getLongTextValueByKey("Pharmacy Adjustment Cost Rate Header", "");
getLongTextValueByKey("Pharmacy Adjustment Cost Rate Footer", "");
// Retail Rate, Stock, Wholesale Rate configurations...
// (All start empty and can be customized independently)
}
// NEW: Fallback helper methods
public String getPharmacyBillCSSWithFallback(String specificKey) {
String specificCSS = getLongTextValueByKey(specificKey);
if (specificCSS != null && !specificCSS.trim().isEmpty()) {
return specificCSS;
}
return getLongTextValueByKey("Pharmacy Common Bill CSS");
}
public String getPharmacyBillHeaderWithFallback(String specificKey) {
String specificHeader = getLongTextValueByKey(specificKey);
if (specificHeader != null && !specificHeader.trim().isEmpty()) {
return specificHeader;
}
return getLongTextValueByKey("Pharmacy Common Bill Header");
}
public String getPharmacyBillFooterWithFallback(String specificKey) {
String specificFooter = getLongTextValueByKey(specificKey);
if (specificFooter != null && !specificFooter.trim().isEmpty()) {
return specificFooter;
}
return getLongTextValueByKey("Pharmacy Common Bill Footer");
}
// Original method for backward compatibility
private void loadPharmacyIssueReceiptConfigurationDefaults() {
getLongTextValueByKey("Pharmacy Issue Receipt CSS",
".receipt-container {\n"
+ " font-family: Verdana, sans-serif;\n"
+ " font-size: 12px;\n"
+ " color: #000;\n"
+ "}\n"
+ ".receipt-header, .receipt-title, .receipt-separator, .receipt-summary {\n"
+ " margin-bottom: 10px;\n"
+ "}\n"
+ ".receipt-institution-name {\n"
+ " font-weight: bold;\n"
+ " font-size: 16px;\n"
+ " text-align: center;\n"
+ "}\n"
+ ".receipt-institution-contact {\n"
+ " text-align: center;\n"
+ " font-size: 11px;\n"
+ "}\n"
+ ".receipt-title {\n"
+ " text-align: center;\n"
+ " font-size: 14px;\n"
+ " font-weight: bold;\n"
+ " text-decoration: underline;\n"
+ "}\n"
+ ".receipt-details-table, .receipt-items-table, .receipt-summary-table {\n"
+ " width: 100%;\n"
+ " border-collapse: collapse;\n"
+ "}\n"
+ ".receipt-items-header {\n"
+ " font-weight: bold;\n"
+ " border-bottom: 1px solid #ccc;\n"
+ "}\n"
+ ".item-name, .item-qty, .item-rate, .item-value {\n"
+ " padding: 4px;\n"
+ " text-align: left;\n"
+ "}\n"
+ ".item-qty, .item-rate, .item-value {\n"
+ " text-align: right;\n"
+ "}\n"
+ ".summary-label {\n"
+ " font-weight: bold;\n"
+ "}\n"
+ ".summary-value {\n"
+ " text-align: right;\n"
+ " font-weight: bold;\n"
+ "}\n"
+ ".total-amount {\n"
+ " font-size: 14px;\n"
+ " font-weight: bold;\n"
+ "}\n"
+ ".receipt-cashier {\n"
+ " margin-top: 20px;\n"
+ " text-align: right;\n"
+ " text-decoration: overline;\n"
+ "}"
);
}
}
This example shows how to use the new flexible configuration system with automatic fallbacks:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<!-- INTERFACE -->
<cc:interface>
<cc:attribute name="bill" />
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<!-- NEW: Use fallback methods for CSS -->
<style>
<h:outputText escape="false"
value="#{configOptionApplicationController.getPharmacyBillCSSWithFallback('Pharmacy Adjustment Purchase Rate CSS')}"/>
</style>
<!-- NEW: Use fallback methods for Header -->
<h:outputText escape="false"
value="#{configOptionApplicationController.getPharmacyBillHeaderWithFallback('Pharmacy Adjustment Purchase Rate Header')}"/>
<div class="receipt-container">
<div class="receipt-header">
<div class="receipt-institution-name">
<h:outputLabel value="#{cc.attrs.bill.department.printingName}" />
</div>
<div class="receipt-institution-contact">
<h:outputLabel value="#{cc.attrs.bill.department.address}" /><br />
<h:outputLabel value="#{cc.attrs.bill.department.telephone1}" />
<h:outputLabel value=" #{cc.attrs.bill.department.telephone2}" /><br />
<h:outputLabel value="#{cc.attrs.bill.department.fax}" />
</div>
</div>
<div class="receipt-title">
<h:outputLabel value="Purchase Rate Adjustment Note" />
</div>
<div class="receipt-separator"><hr /></div>
<!-- Bill content goes here -->
</div>
<!-- NEW: Use fallback methods for Footer -->
<h:outputText escape="false"
value="#{configOptionApplicationController.getPharmacyBillFooterWithFallback('Pharmacy Adjustment Purchase Rate Footer')}"/>
</cc:implementation>
</html>
For existing bills that have specific configurations:
<style>
<h:outputText escape="false"
value="#{configOptionApplicationController.getLongTextValueByKey('Pharmacy Issue Receipt CSS')}"/>
</style>
<h:outputText escape="false"
value="#{configOptionApplicationController.getLongTextValueByKey('Pharmacy Issue Receipt Header')}"/>
- Scalability: Handles hundreds of bill types without requiring individual configuration for each
- Flexibility: Each bill type can be customized independently when needed
- Maintainability: Common defaults reduce duplication and simplify management
- Backward Compatibility: Existing configurations continue to work unchanged
- Automatic Fallback: No need to configure every bill type - common defaults are used automatically
The composite is called from the relevant page like below:
<h:panelGroup id="gpBillPreview">
<phi:pharmacy_issue_receipt bill="#{pharmacyIssueController.printBill}"/>
</h:panelGroup>
For adjustment bills:
<h:panelGroup id="print">
<ph:adjustmentBill_purchase_price bill="#{pharmacyAdjustmentController.deptAdjustmentPreBill}" />
</h:panelGroup>
Administrators can:
- Start with common default configurations that work for all bills
- Customize specific bill types only when needed (e.g., different CSS for purchase rate vs stock adjustments)
- Modify common defaults to affect all uncustomized bills at once
- Override specific configurations for individual bill types when required