Implement OPD template builder, doctor template selection, and OPD print integration fixes
This commit is contained in:
commit
614713f76b
126
.gitignore
vendored
Normal file
126
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#-------------------------
|
||||
# Operating Specific Junk Files
|
||||
#-------------------------
|
||||
|
||||
# OS X
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# OS X Thumbnails
|
||||
._*
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
# Linux
|
||||
*~
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
#-------------------------
|
||||
# Environment Files
|
||||
#-------------------------
|
||||
# These should never be under version control,
|
||||
# as it poses a security risk.
|
||||
.env
|
||||
.vagrant
|
||||
Vagrantfile
|
||||
|
||||
#-------------------------
|
||||
# Temporary Files
|
||||
#-------------------------
|
||||
writable/cache/*
|
||||
!writable/cache/index.html
|
||||
|
||||
writable/logs/*
|
||||
!writable/logs/index.html
|
||||
|
||||
writable/session/*
|
||||
!writable/session/index.html
|
||||
|
||||
writable/uploads/*
|
||||
!writable/uploads/index.html
|
||||
|
||||
writable/debugbar/*
|
||||
!writable/debugbar/index.html
|
||||
|
||||
php_errors.log
|
||||
|
||||
#-------------------------
|
||||
# User Guide Temp Files
|
||||
#-------------------------
|
||||
user_guide_src/build/*
|
||||
user_guide_src/cilexer/build/*
|
||||
user_guide_src/cilexer/dist/*
|
||||
user_guide_src/cilexer/pycilexer.egg-info/*
|
||||
|
||||
#-------------------------
|
||||
# Test Files
|
||||
#-------------------------
|
||||
tests/coverage*
|
||||
|
||||
# Don't save phpunit under version control.
|
||||
phpunit
|
||||
|
||||
#-------------------------
|
||||
# Composer
|
||||
#-------------------------
|
||||
vendor/
|
||||
|
||||
#-------------------------
|
||||
# IDE / Development Files
|
||||
#-------------------------
|
||||
|
||||
# Modules Testing
|
||||
_modules/*
|
||||
|
||||
# phpenv local config
|
||||
.php-version
|
||||
|
||||
# Jetbrains editors (PHPStorm, etc)
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# NetBeans
|
||||
/nbproject/
|
||||
/build/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/nbactions.xml
|
||||
/nb-configuration.xml
|
||||
/.nb-gradle/
|
||||
|
||||
# Sublime Text
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
*.sublime-workspace
|
||||
*.sublime-project
|
||||
.phpintel
|
||||
/api/
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/
|
||||
|
||||
/results/
|
||||
/phpunit*.xml
|
||||
22
LICENSE
Normal file
22
LICENSE
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
Copyright (c) 2019-present CodeIgniter Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
69
README.md
Normal file
69
README.md
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# CodeIgniter 4 Application Starter
|
||||
|
||||
## What is CodeIgniter?
|
||||
|
||||
CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure.
|
||||
More information can be found at the [official site](https://codeigniter.com).
|
||||
|
||||
This repository holds a composer-installable app starter.
|
||||
It has been built from the
|
||||
[development repository](https://github.com/codeigniter4/CodeIgniter4).
|
||||
|
||||
More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums.
|
||||
|
||||
You can read the [user guide](https://codeigniter.com/user_guide/)
|
||||
corresponding to the latest version of the framework.
|
||||
|
||||
## Installation & updates
|
||||
|
||||
`composer create-project codeigniter4/appstarter` then `composer update` whenever
|
||||
there is a new release of the framework.
|
||||
|
||||
When updating, check the release notes to see if there are any changes you might need to apply
|
||||
to your `app` folder. The affected files can be copied or merged from
|
||||
`vendor/codeigniter4/framework/app`.
|
||||
|
||||
## Setup
|
||||
|
||||
Copy `env` to `.env` and tailor for your app, specifically the baseURL
|
||||
and any database settings.
|
||||
|
||||
## Important Change with index.php
|
||||
|
||||
`index.php` is no longer in the root of the project! It has been moved inside the *public* folder,
|
||||
for better security and separation of components.
|
||||
|
||||
This means that you should configure your web server to "point" to your project's *public* folder, and
|
||||
not to the project root. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the
|
||||
framework are exposed.
|
||||
|
||||
**Please** read the user guide for a better explanation of how CI4 works!
|
||||
|
||||
## Repository Management
|
||||
|
||||
We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages.
|
||||
We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss
|
||||
FEATURE REQUESTS.
|
||||
|
||||
This repository is a "distribution" one, built by our release preparation script.
|
||||
Problems with it can be raised on our forum, or as issues in the main repository.
|
||||
|
||||
## Server Requirements
|
||||
|
||||
PHP version 8.2 or higher is required, with the following extensions installed:
|
||||
|
||||
- [intl](http://php.net/manual/en/intl.requirements.php)
|
||||
- [mbstring](http://php.net/manual/en/mbstring.installation.php)
|
||||
|
||||
> [!WARNING]
|
||||
> - The end of life date for PHP 7.4 was November 28, 2022.
|
||||
> - The end of life date for PHP 8.0 was November 26, 2023.
|
||||
> - The end of life date for PHP 8.1 was December 31, 2025.
|
||||
> - If you are still using below PHP 8.2, you should upgrade immediately.
|
||||
> - The end of life date for PHP 8.2 will be December 31, 2026.
|
||||
|
||||
Additionally, make sure that the following extensions are enabled in your PHP:
|
||||
|
||||
- json (enabled by default - don't turn it off)
|
||||
- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL
|
||||
- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library
|
||||
521
WORKLOG_COPILOT.md
Normal file
521
WORKLOG_COPILOT.md
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
# Worklog - HMS_CI4_OLD
|
||||
|
||||
Date: 2026-02-08
|
||||
|
||||
## Summary
|
||||
Ported OPD Charges, IPD Charges, and Package modules from CI3 to CI4 with consistent NiceAdmin UI, AJAX modal flows, Simple-DataTables, insurance rate handling, and print/Excel exports.
|
||||
|
||||
## OPD Charges
|
||||
- Controller: app/Controllers/Item.php
|
||||
- Model: app/Models/ItemModel.php
|
||||
- Routes: app/Config/Routes.php (group: item)
|
||||
- Views: app/Views/Setting/Charges/OPD_Charges/
|
||||
- item_search_V.php (header buttons: Charge Groups, Add New Charge; filters; print/export)
|
||||
- item_search_adv.php (list partial with DataTable)
|
||||
- item_profile_V.php (modal edit; insurance rates; refresh list on update)
|
||||
- item_create_V.php
|
||||
- item_type_search_v.php / item_type_profile.php / item_type_create.php
|
||||
- item_item_list.php (print layout with heading, borders, base rate fallback)
|
||||
- item_item_excel.php (Excel export)
|
||||
- item_insurance_list.php (insurance rate table partial)
|
||||
- Model joins (no DB views):
|
||||
- items: hc_items + hc_item_type
|
||||
- insurance items: hc_items_insurance + hc_insurance, filter isdelete=0
|
||||
- Print: insurance selection adds Amount + Code; missing insurance uses Base Rate
|
||||
- Excel: output via response headers (no debug toolbar injection)
|
||||
|
||||
## IPD Charges
|
||||
- Controller: app/Controllers/ItemIpd.php
|
||||
- Model: app/Models/ItemIpdModel.php
|
||||
- Routes: app/Config/Routes.php (groups: item-ipd + legacy Item_IPD)
|
||||
- Views: app/Views/Setting/Charges/IPD_Charges/
|
||||
- item_search_V.php, item_search_adv.php
|
||||
- item_profile_V.php, item_create_V.php
|
||||
- item_type_search_v.php / item_type_profile.php / item_type_create.php
|
||||
- item_item_list.php (print)
|
||||
- item_item_excel.php (Excel)
|
||||
- item_insurance_list.php
|
||||
- Model joins (no DB views):
|
||||
- items: ipd_items + ipd_item_type
|
||||
- insurance items: ipd_items_insurance + hc_insurance, filter isdelete=0
|
||||
|
||||
## Package (IPD Package)
|
||||
- Controller: app/Controllers/Package.php
|
||||
- Model: app/Models/PackageModel.php
|
||||
- Routes: app/Config/Routes.php (groups: package + legacy Package + legacy IPD_Package)
|
||||
- Views: app/Views/Setting/Charges/Package/
|
||||
- item_search_V.php, item_search_adv.php
|
||||
- item_profile_V.php, item_create_V.php
|
||||
- item_type_search_v.php / item_type_profile.php / item_type_create.php
|
||||
- item_item_list.php (print)
|
||||
- item_item_excel.php (Excel)
|
||||
- item_insurance_list.php
|
||||
- Model joins (no DB views):
|
||||
- packages: package, package_group
|
||||
- insurance items: package_insurance + hc_insurance, filter isdelete=0
|
||||
- Audit tables: package_update and package_insurance_update
|
||||
- If not present, audit insert skipped (prevents errors)
|
||||
|
||||
## UI + Behavior
|
||||
- Charges tiles updated:
|
||||
- setting/charges -> IPD tile uses item-ipd/search
|
||||
- setting/charges -> Package tile uses package/search
|
||||
- Modal edits refresh list:
|
||||
- OPD: window.refreshChargeList()
|
||||
- IPD: window.refreshChargeList()
|
||||
- Package: window.refreshPackageList()
|
||||
- Print buttons in header next to filter; export Excel added
|
||||
- Print layout: heading with group + insurance; no OPD/IPD or group columns; table borders
|
||||
- Base rate fallback: if insurance-specific rate missing, show base amount and Code column shows "Base Rate"
|
||||
|
||||
## Known Tables Used
|
||||
- OPD: hc_items, hc_item_type, hc_items_insurance, hc_items_update, hc_items_insurance_update
|
||||
- IPD: ipd_items, ipd_item_type, ipd_items_insurance, ipd_items_update, ipd_items_insurance_update
|
||||
- Package: package, package_group, package_insurance, package_update, package_insurance_update
|
||||
- Insurance: hc_insurance
|
||||
|
||||
## Notes for Next Session
|
||||
- If audit tables for Package are required, create migrations for package_update and package_insurance_update.
|
||||
- If isdelete column missing on insurance tables, remove filter.
|
||||
- Debug toolbar can break Excel; keep response headers to avoid injection.
|
||||
- Legacy routes are supported for old JS paths.
|
||||
|
||||
---
|
||||
|
||||
Date: 2026-02-16
|
||||
|
||||
## Diagnosis CI3 → CI4 Endpoint Mapping (Lab_Report parity)
|
||||
|
||||
### Fully mapped in CI4
|
||||
- `lab_master` → `Diagnosis::labMaster` via `Lab_Report/lab_master`
|
||||
- `lab_path/{lab_type}` → `Diagnosis::labPathLegacy` via `Lab_Report/lab_path/(:num)`
|
||||
- `search_lab_4/{lab_type}` → `Diagnosis::searchLab` via `Lab_Report/search_lab_4/(:num)`
|
||||
- `search_lab_4_srno/{lab_type}` → `Diagnosis::searchLabBySrno` via `Lab_Report/search_lab_4_srno/(:num)`
|
||||
- `search_lab_4_labno/{lab_type}` → `Diagnosis::searchLabByLabno` via `Lab_Report/search_lab_4_labno/(:num)`
|
||||
- `select_lab_invoice/{inv_id}/{lab_type}` → `Diagnosis::selectLabInvoicePath`
|
||||
- `select_lab_invoice_path/{inv_id}/{lab_type}` → `Diagnosis::selectLabInvoicePath`
|
||||
- `lab_date_show/{inv_id}/{lab_type}` → `Diagnosis::labDateShow`
|
||||
- `test_list/{inv_id}/{lab_type}` → `Diagnosis::testList`
|
||||
- `xray_test_list/{inv_id}/{lab_type}` → `Diagnosis::testList`
|
||||
- `lab_tab_1_process/{test_id}/{lab_type}` → `Diagnosis::labTab1Process`
|
||||
- `create_report_xray/{req_id}` → `Diagnosis::createReportXray`
|
||||
- `show_report_final/{req_id}` → `Diagnosis::showReportFinalXray`
|
||||
- `get_template_xray/{id}` → `Diagnosis::getTemplateXray`
|
||||
- `Final_Update_xray/{req_id}` → `Diagnosis::finalUpdateXray`
|
||||
- `confirm_report_xray/{req_id}` → `Diagnosis::confirmReportXray`
|
||||
|
||||
### Missing legacy endpoints (not yet mapped)
|
||||
- `report_file_list/{inv_id}/{lab_type}/{delete?}`
|
||||
- `select_lab_radiology/{inv_id}/{lab_type}`
|
||||
|
||||
### Notes
|
||||
- Current CI4 radiology flow uses `Diagnosis::selectLabInvoicePath` for detail screen and does not require a separate `select_lab_radiology` endpoint in active views.
|
||||
- File upload/list actions in CI4 diagnosis view are currently placeholders (`uploadFiles`, `showFiles`) and do not yet have controller endpoints.
|
||||
|
||||
## Future Backlog: AI-assisted Image Diagnosis (Ultrasound / X-Ray / CT)
|
||||
|
||||
### Goal
|
||||
- Add a professional image workspace where users can upload/scan images, review them, run AI-assisted analysis, and move AI draft findings into radiology report editor with doctor review.
|
||||
|
||||
### Phase 1 (MVP - internal)
|
||||
- Build one modal workspace in diagnosis detail screen:
|
||||
- Left panel: image preview, next/previous, zoom.
|
||||
- Right panel: AI findings, AI impression, confidence, doctor editable text.
|
||||
- Wire existing action buttons:
|
||||
- Upload Files -> open workspace + upload image.
|
||||
- Scan -> open workspace + scan image flow.
|
||||
- Show Files -> list previously uploaded/scanned images.
|
||||
- Add backend APIs in Diagnosis controller:
|
||||
- uploadImage(reqId)
|
||||
- listImages(reqId)
|
||||
- scanImage(reqId)
|
||||
- analyzeImageAi(reqId, fileId)
|
||||
- saveAiDraft(reqId, fileId)
|
||||
- acceptAiToReport(reqId)
|
||||
- Add DB table for AI result tracking (suggested: diagnosis_image_ai):
|
||||
- id, req_id, file_id, ai_findings, ai_impression, confidence,
|
||||
- model_name, model_version, status, reviewed_by, reviewed_at,
|
||||
- created_at, updated_at.
|
||||
- Add visible safety label: AI Suggestion - Doctor Review Required.
|
||||
|
||||
### Phase 2 (real AI integration)
|
||||
- Integrate external AI service endpoint (Python/FastAPI or equivalent).
|
||||
- Send selected image path to AI service and store structured response.
|
||||
- Add timeout/error handling and retry button in UI.
|
||||
|
||||
### Phase 3 (clinical workflow hardening)
|
||||
- Add audit trail for accepted/edited AI content before final report verify.
|
||||
- Add role check so only authorized users can accept AI output.
|
||||
- Keep final confirm manual; AI never auto-verifies reports.
|
||||
|
||||
### UI/Workflow Notes
|
||||
- AI output should prefill radiology editor, not directly replace final report.
|
||||
- Show per-image history for repeat review and comparison.
|
||||
- Keep terminology consistent with current imaging workflow labels.
|
||||
|
||||
---
|
||||
|
||||
Date: 2026-02-16
|
||||
|
||||
## Pharmacy Module Kickoff (Legacy Medical)
|
||||
|
||||
### What was verified
|
||||
- Legacy pharmacy dashboard source is in old code:
|
||||
- `old_code_ci3/views/Medical/Dashboard.php`
|
||||
- Main legacy pharmacy controller is very large and feature-rich:
|
||||
- `old_code_ci3/controllers/Medical.php` (~5k lines)
|
||||
- Related legacy controllers:
|
||||
- `old_code_ci3/controllers/Medical_backpanel.php`
|
||||
- `old_code_ci3/controllers/Medical_Report.php`
|
||||
- `old_code_ci3/controllers/Medical_Print.php`
|
||||
- `old_code_ci3/controllers/Payment_Medical.php`
|
||||
|
||||
### Important routing finding
|
||||
- Current CI4 improved auto-routing is disabled (`app/Config/Routing.php` has `autoRoute = false`).
|
||||
- No explicit CI4 `/Medical` routes found in `app/Config/Routes.php`.
|
||||
- No current CI4 Medical controller files found under `app/Controllers`.
|
||||
|
||||
### Legacy dashboard button map (from old Dashboard.php)
|
||||
- OPD Sale -> `/Medical/search_customer`
|
||||
- Invoice -> `/Medical/Invoice_Med_Draft`
|
||||
- IPD/Credit -> `/Medical/list_org_ipd`
|
||||
- Org. Credit -> `/Medical/list_org`
|
||||
- Return Counter Sale -> `/Medical/Invoice_Med_Return`
|
||||
- Day Report -> `/Medical_Report/Report_2`
|
||||
- Sale Day Report -> `/Medical_Report/Report_1`
|
||||
- Payment Report -> `/Medical_Report/Report_Payment_Recieved`
|
||||
- Store Stock -> `/Medical_backpanel/store_stock`
|
||||
- Store Main -> `/Medical/main_store`
|
||||
- Master -> `/Medical_backpanel`
|
||||
|
||||
### Suggested migration order (phase wise)
|
||||
1. Dashboard + navigation tiles.
|
||||
2. OPD Sale + Invoice Draft list.
|
||||
3. Return invoice flow.
|
||||
4. Store stock and stock statement.
|
||||
5. Reports (day/sale/payment).
|
||||
6. Backpanel master screens.
|
||||
|
||||
### SQL views received from user (confirmed)
|
||||
- `v_med_item_return`
|
||||
- `v_med_item_with_return`
|
||||
- `v_ipd_list`
|
||||
- `v_med_short_list`
|
||||
- `v_product_stock`
|
||||
- `v_product_stock_sub`
|
||||
- `v_sale_item`
|
||||
- `v_sale_item_sub`
|
||||
|
||||
### Dependency note
|
||||
- `v_ipd_list` depends on `v_ipd_doc_list` (seen in view body join).
|
||||
- Before CI4 pharmacy migration, ensure `v_ipd_doc_list` exists in target DB with compatible schema.
|
||||
|
||||
### Next implementation start point
|
||||
- Begin CI4 Pharmacy phase-1 with dashboard route/controller/view parity for `/Medical` tiles, then wire OPD Sale + Draft Invoice list endpoints.
|
||||
|
||||
### Phase-1 implementation done (CI4)
|
||||
- Added controller: app/Controllers/Medical.php
|
||||
- Added routes:
|
||||
- Medical
|
||||
- Medical/search_customer
|
||||
- Medical/Invoice_Med_Draft
|
||||
- Medical/Invoice_Med_Return
|
||||
- Medical/list_org_ipd
|
||||
- Medical/list_org
|
||||
- Medical/main_store
|
||||
- Medical/store_stock
|
||||
- Medical/master
|
||||
- Added views:
|
||||
- app/Views/medical/dashboard.php
|
||||
- app/Views/medical/search_customer.php
|
||||
- app/Views/medical/invoice_med_draft.php
|
||||
- app/Views/medical/placeholder.php
|
||||
- Status:
|
||||
- Dashboard works at /Medical.
|
||||
- OPD Sale and Invoice Draft panels are functional.
|
||||
- Remaining tiles currently show migration placeholder pending deeper CI3 parity port.
|
||||
|
||||
---
|
||||
|
||||
Date: 2026-02-19
|
||||
|
||||
## Pharmacy -> Master continuation
|
||||
|
||||
### Fix completed
|
||||
- Module: `Drug Sale Customer Wise Report`
|
||||
- Endpoint: `Medical::drug_patient_distribute`
|
||||
- Root-cause fixed in `getDrugPatientDistributeRows()`:
|
||||
- Legacy behavior: when Drug Name is blank and Schedule filter is blank, show all matching date-range records.
|
||||
- CI4 regression: returned empty result unless at least one schedule was selected.
|
||||
- Fix: schedule condition is now applied only when schedules are selected; blank schedule no longer forces empty result.
|
||||
|
||||
### Validation
|
||||
- `php -l app/Controllers/Medical.php` passed (no syntax errors).
|
||||
|
||||
### Step done: Med. Payment Edit Logs (legacy links)
|
||||
- Implemented legacy page endpoint: `Payment_Medical/payment_log`
|
||||
- Implemented legacy result endpoint: `Payment_Medical/payment_log_data`
|
||||
- Added CI4 controller methods in `app/Controllers/Payment_Medical.php`:
|
||||
- `payment_log()` for filter page
|
||||
- `payment_log_data()` for date-range log result table
|
||||
- Added CI4 views:
|
||||
- `app/Views/medical/payment_log.php`
|
||||
- `app/Views/medical/payment_log_data.php`
|
||||
- Updated routes in `app/Config/Routes.php`:
|
||||
- `GET Payment_Medical/payment_log -> Payment_Medical::payment_log`
|
||||
- `GET|POST Payment_Medical/payment_log_data -> Payment_Medical::payment_log_data`
|
||||
- Updated Master menu link in `app/Views/medical/master.php`:
|
||||
- `Med. Payment Edit Logs` now opens `Payment_Medical/payment_log`
|
||||
|
||||
### Step fix: Med. Payment Edit action buttons not working
|
||||
- Root cause: `payment_edit` HTML was injected using `innerHTML` in `payment_search`, so inline `<script>` inside the injected response did not execute.
|
||||
- Fix applied in `app/Views/medical/payment_search.php`:
|
||||
- Added delegated click handlers for:
|
||||
- `#btn_update_bank` -> `Payment_Medical/change_to_bank`
|
||||
- `#btn_update_cash` -> `Payment_Medical/change_to_cash`
|
||||
- `#btn_update_user` -> `Payment_Medical/change_user`
|
||||
- `#btn_update_amount` -> `Payment_Medical/update_amount`
|
||||
- Replaced direct result assignment with shared render helper to consistently update `#searchresult`.
|
||||
- Validation: `php -l app/Views/medical/payment_search.php` passed.
|
||||
|
||||
### Step fix: Med. Payment Edit duplicate submit (2x POST)
|
||||
- Evidence: HAR showed two POST requests for single button action (first with payload, second empty/no payload).
|
||||
- Root cause: both handlers were active:
|
||||
- Inline click handlers inside `app/Views/medical/payment_edit.php`
|
||||
- Delegated click handlers in `app/Views/medical/payment_search.php`
|
||||
- Fix:
|
||||
- Removed inline `<script>` handlers from `payment_edit.php`.
|
||||
- Kept `payment_search.php` delegated handlers as single source of action binding.
|
||||
- Added `actionInFlight` guard in `payment_search.php` to prevent rapid duplicate action posts.
|
||||
- Validation:
|
||||
- `php -l app/Views/medical/payment_edit.php` passed.
|
||||
- `php -l app/Views/medical/payment_search.php` passed.
|
||||
|
||||
### Step fix: Med. Payment Edit Logs showing blank
|
||||
- Symptom: `Payment_Medical/payment_log` displayed 0 rows for date range where legacy HMS showed logs.
|
||||
- Fix in `app/Controllers/Payment_Medical.php` (`payment_log_data`):
|
||||
- Replaced Query Builder date condition with raw SQL function filter:
|
||||
- `DATE(l.insert_datetime) BETWEEN 'from' AND 'to'`
|
||||
- Added fallback fetch (latest 500 logs, unfiltered) when filtered rows are empty, to handle schema/date-field drift gracefully.
|
||||
- Validation: `php -l app/Controllers/Payment_Medical.php` passed.
|
||||
|
||||
### Step update: log table name compatibility
|
||||
- User confirmed legacy expectation to store Med Payment Edit logs in `payment_history_log`.
|
||||
- Updated `app/Controllers/Payment_Medical.php`:
|
||||
- Added resolver to choose log table in this order:
|
||||
1) `payment_history_log`
|
||||
2) `paymentmedical_history_log`
|
||||
- Applied resolver to both:
|
||||
- write path (`insertPaymentLog`)
|
||||
- read path (`payment_log_data` joins/field detection)
|
||||
- Result: CI4 now reads/writes the same legacy table name where available, while still supporting older schema names.
|
||||
|
||||
### Step update: Update Log text population
|
||||
- User requested visible log text like: `Amount value Change 120 to 100`.
|
||||
- Updated `app/Controllers/Payment_Medical.php`:
|
||||
- `update_amount()` now writes explicit log text:
|
||||
- `Amount value Change <old> to <new>`
|
||||
- `insertPaymentLog()` now writes to `update_remark` when `update_log` column is missing.
|
||||
- `payment_log_data()` now reads `update_log` with fallback/coalesce from `update_remark`.
|
||||
- Validation: `php -l app/Controllers/Payment_Medical.php` passed.
|
||||
|
||||
### Step update: explicit logs for Bank/CASH/User actions
|
||||
- Added readable `update_log` text for:
|
||||
- `change_to_bank`: `Payment mode Change <old> to BANK [source] TranID:<id>`
|
||||
- `change_to_cash`: `Payment mode Change <old> to CASH`
|
||||
- `change_user`: `Update User Change <old_user> to <new_user>`
|
||||
- Also validates payment row existence before update in bank/cash actions.
|
||||
- Validation: `php -l app/Controllers/Payment_Medical.php` passed.
|
||||
|
||||
### Step done: Med. Invoice Item Update Logs (legacy parity)
|
||||
- Target legacy endpoints:
|
||||
- `Medical_backpanel/invoice_item_log`
|
||||
- `Medical_backpanel/invoice_item_log_data`
|
||||
- Updates applied:
|
||||
- Added route alias in `app/Config/Routes.php`:
|
||||
- `GET|POST Medical_backpanel/invoice_item_log_data -> Medical::invoice_item_log_data`
|
||||
- Updated `Medical::invoice_item_log_data` in `app/Controllers/Medical.php`:
|
||||
- Accepts both modern fields (`date_from`, `date_to`) and legacy `opd_date_range`.
|
||||
- Uses payment log table fallback:
|
||||
- `payment_history_log` first
|
||||
- `paymentmedical_history_log` fallback
|
||||
- Reads payment update text from `update_log` with fallback to `update_remark`.
|
||||
- Updated `app/Views/medical/invoice_item_log.php`:
|
||||
- Sends legacy `opd_date_range` token and posts to legacy URL `Medical_backpanel/invoice_item_log_data`.
|
||||
- Updated `app/Views/medical/invoice_item_log_data.php`:
|
||||
- Added DataTable initialization for search/pagination parity.
|
||||
- Validation:
|
||||
- `php -l app/Controllers/Medical.php` passed.
|
||||
- `php -l app/Config/Routes.php` passed.
|
||||
- `php -l app/Views/medical/invoice_item_log.php` passed.
|
||||
- `php -l app/Views/medical/invoice_item_log_data.php` passed.
|
||||
|
||||
---
|
||||
|
||||
Date: 2026-02-22
|
||||
|
||||
## OPD Upgrade - AI Requirements (User Confirmed)
|
||||
|
||||
### Mandatory AI behavior to keep in upgraded OPD
|
||||
- Use AI-assisted **Autotype** in OPD prescription text areas (fast drafting while doctor types).
|
||||
- Support **Hinglish -> English** conversion in complaint/diagnosis style inputs.
|
||||
- Show **Patient History Alerts** during OPD prescribing (old complaints/diagnosis/risk context visible before final save).
|
||||
|
||||
### Implementation direction (parity + enhancement)
|
||||
- Keep old familiar OPD workflow/tabs while adding AI features inline (no disruptive screen redesign).
|
||||
- Reuse current CI4 OPD AI foundation already present in `Opd_prescription`:
|
||||
- `complaints_search`
|
||||
- `complaints_parse`
|
||||
- `complaints_ai_draft`
|
||||
- Add history alert feed from patient prior OPD records and remarks in the prescription screen header/side context.
|
||||
|
||||
### Acceptance criteria
|
||||
- Doctor can type Hinglish symptoms and get normalized English complaint text quickly.
|
||||
- Doctor can trigger AI draft/autotype suggestion and then edit before save.
|
||||
- High-value history (past Rx trend / prior diagnosis / patient remarks / key vitals trend) appears as alert cards in OPD screen.
|
||||
- AI output is assistive only; final clinical decision remains manual.
|
||||
|
||||
---
|
||||
|
||||
Date: 2026-02-23
|
||||
|
||||
## OPD Prescription Session Checkpoint (Saved)
|
||||
|
||||
### Completed in this session
|
||||
- Rx-Group medicine parity improvements:
|
||||
- Dose master dropdowns integrated (Dose/When/Frequency/Where).
|
||||
- Human-readable dose labels shown in list (ID -> label mapping).
|
||||
- Rx-Group badge now shows group name (not only row ID).
|
||||
- Salt/Generic fallback improved in Rx-Group medicine list.
|
||||
- OPD medicine workspace data quality display:
|
||||
- Generic column fallback added (`genericname` -> `salt_name`) for blank generic values.
|
||||
- Clinical Templates bootstrap for fresh systems:
|
||||
- Added seeder `ClinicalTemplateWorkspaceSeeder` with practical master templates across all OPD sections.
|
||||
- Integrated into `OpdDemoMasterSeeder` so one command seeds templates.
|
||||
- OPD Prescription template UX enhancement:
|
||||
- Load Template modal now has suggested top templates.
|
||||
- Apply mode added: `Replace` or `Append`.
|
||||
- Quick suggestion chips added inside modal.
|
||||
- Doctor-wise learning behavior:
|
||||
- Added usage tracking endpoint for template apply action.
|
||||
- Added usage table auto-create: `opd_clinical_template_usage`.
|
||||
- `section_template_list` now prioritizes by doctor usage count, then scope/recency.
|
||||
|
||||
### Files changed (key)
|
||||
- `app/Controllers/Opd_prescription.php`
|
||||
- `app/Views/billing/opd_prescription_basic.php`
|
||||
- `app/Views/billing/rx_group_medicine_workspace.php`
|
||||
- `app/Config/Routes.php`
|
||||
- `app/Database/Seeds/ClinicalTemplateWorkspaceSeeder.php`
|
||||
- `app/Database/Seeds/OpdDemoMasterSeeder.php`
|
||||
|
||||
### Validation status
|
||||
- PHP lint passed for all modified files during session.
|
||||
- VS Code diagnostics reported no errors in changed files.
|
||||
|
||||
### Resume point for next OPD session
|
||||
- Continue with OPD Prescription optimization:
|
||||
- add doctor-level analytics panel for template usage trends,
|
||||
- optional specialty-wise template suggestions,
|
||||
- optional safety-check prompts before final save.
|
||||
|
||||
---
|
||||
|
||||
Date: 2026-02-25
|
||||
|
||||
## OPD Consult + Scan Workflow Checkpoint (Saved)
|
||||
|
||||
### Completed in this session
|
||||
- OPD queue behavior corrections:
|
||||
- Upload/scan no longer auto-moves OPD to Visited status.
|
||||
- Queue/tabs kept consistent for Waiting/Visited/Cancelled flow.
|
||||
- Visit completion action retained via explicit button workflow.
|
||||
- Language/readability cleanup:
|
||||
- Label text and spelling normalized in OPD UI areas.
|
||||
- Code comments/doc intent improved in touched controller/view sections.
|
||||
- Visited list mismatch fix:
|
||||
- Corrected query join behavior so Visited count and list data match.
|
||||
- Scan AI output enhancement:
|
||||
- Detailed multi-line diagnosis/report text generation added.
|
||||
- Report rendering updated to preserve line breaks in scan cards.
|
||||
- Consult scan visibility:
|
||||
- Current OPD uploaded scans and reports now visible in consult page.
|
||||
- `Use Report` actions wired for consult text usage.
|
||||
- Patient historical scan support:
|
||||
- Async panel for all patient OPD scan history added.
|
||||
- Manual `Run AI` action enabled for historical files.
|
||||
- Expand/Minimize image behavior added in history cards.
|
||||
- Missing history endpoint route added and fixed.
|
||||
- Consult layout UX:
|
||||
- Left and right consult panes now scroll independently on desktop.
|
||||
- Investigation + Advice flow alignment:
|
||||
- Investigation section compacted (profile/manual + Select2 search + Remove All).
|
||||
- Old-style Advice flow restored in consult:
|
||||
- Advice section moved to last block,
|
||||
- Next Visit and Refer To shown after Advice,
|
||||
- predefined advice list with `+Add` restored,
|
||||
- quick Next Visit chips restored.
|
||||
|
||||
### Files changed (key)
|
||||
- `app/Controllers/Opd.php`
|
||||
- `app/Controllers/Opd_prescription.php`
|
||||
- `app/Config/Routes.php`
|
||||
- `app/Views/billing/opd_appointment_dashboard.php`
|
||||
- `app/Views/billing/opd_appointment_list.php`
|
||||
- `app/Views/billing/opd_appointment_list_table.php`
|
||||
- `app/Views/billing/opd_prescription_basic.php`
|
||||
- `app/Views/billing/opd_scan_history_panel.php` (new)
|
||||
- `app/Views/billing/opd_scan_last_list.php`
|
||||
|
||||
### Validation status
|
||||
- VS Code diagnostics showed no errors for edited files after final patches.
|
||||
|
||||
### Next session focus
|
||||
- Start with print workflow updates (layout and output parity).
|
||||
|
||||
## Pinned Reminder for Next Session
|
||||
- First task: OPD print workflow.
|
||||
- Start with print layout parity and field order verification.
|
||||
- Then validate print output content for Advice, Next Visit, Investigation, and scan report sections.
|
||||
|
||||
---
|
||||
|
||||
Date: 2026-02-26
|
||||
|
||||
## OPD Consult UI + Rx-Group Workflow Checkpoint (Saved)
|
||||
|
||||
### Completed in this session
|
||||
- Print actions cleanup:
|
||||
- Replaced multiple print buttons with a single grouped `Print` dropdown in consult toolbar.
|
||||
- Kept all existing print routes/behavior unchanged under grouped menu.
|
||||
- Predefined Advice space optimization:
|
||||
- `Pre define Advise` section changed to compact mode.
|
||||
- Added show/hide toggle and fixed-height scroll list to prevent long-page expansion.
|
||||
- Legacy Rx-Group compatibility restored:
|
||||
- Added support for legacy URL access pattern:
|
||||
- `Opd_prescription/save_rx_group_list/{doc_id}`
|
||||
- Added backend apply endpoint to copy Rx-Group template medicines into current OPD session.
|
||||
- Rx-Group modal workflow implemented (old-system style):
|
||||
- Added `Rx Group` button in medicine section to open modal.
|
||||
- Modal lists all Rx groups.
|
||||
- Each group has dropdown preview of medicine list before add.
|
||||
- `+ Add` from modal injects medicines directly into current list.
|
||||
- Selected group label shown in medicine panel.
|
||||
- Rx-Group search and filtering (medicine-like UX):
|
||||
- Added modal search input for Rx-Group name.
|
||||
- Added filter scopes: `Active`, `Favorites`, `All`.
|
||||
- Added star toggle (`☆/★`) for favorites.
|
||||
- Favorites persisted in browser local storage.
|
||||
|
||||
### Files changed (key)
|
||||
- `app/Views/billing/opd_prescription_basic.php`
|
||||
- `app/Controllers/Opd_prescription.php`
|
||||
- `app/Config/Routes.php`
|
||||
|
||||
### Validation status
|
||||
- VS Code diagnostics reported no errors in modified files after final patches.
|
||||
|
||||
### Resume point for tomorrow
|
||||
- Continue with print parity fine tuning (spacing/font/line layout) against old HMS PDFs.
|
||||
- Optional polish: persist Rx-Group scope (`Active/Favorites/All`) per user session/profile.
|
||||
|
||||
6
app/.htaccess
Normal file
6
app/.htaccess
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<IfModule authz_core_module>
|
||||
Require all denied
|
||||
</IfModule>
|
||||
<IfModule !authz_core_module>
|
||||
Deny from all
|
||||
</IfModule>
|
||||
37
app/Commands/BridgeSync.php
Normal file
37
app/Commands/BridgeSync.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Libraries\BridgeSyncService;
|
||||
use CodeIgniter\CLI\BaseCommand;
|
||||
use CodeIgniter\CLI\CLI;
|
||||
|
||||
class BridgeSync extends BaseCommand
|
||||
{
|
||||
protected $group = 'Bridge';
|
||||
protected $name = 'bridge:sync';
|
||||
protected $description = 'Process queued bridge sync records and push to central server.';
|
||||
protected $usage = 'bridge:sync [--limit 50]';
|
||||
protected $arguments = [];
|
||||
protected $options = [
|
||||
'--limit' => 'Maximum records to process per run (default: 50).',
|
||||
];
|
||||
|
||||
public function run(array $params)
|
||||
{
|
||||
$limit = (int) (CLI::getOption('limit') ?? 50);
|
||||
if ($limit <= 0) {
|
||||
$limit = 50;
|
||||
}
|
||||
|
||||
$service = new BridgeSyncService();
|
||||
$summary = $service->processPending($limit, 'spark-bridge-sync');
|
||||
|
||||
CLI::write('Bridge Sync Result', 'yellow');
|
||||
CLI::write('Processed: ' . (int) ($summary['processed'] ?? 0));
|
||||
CLI::write('Sent: ' . (int) ($summary['sent'] ?? 0), 'green');
|
||||
CLI::write('Failed: ' . (int) ($summary['failed'] ?? 0), ((int) ($summary['failed'] ?? 0) > 0 ? 'red' : 'green'));
|
||||
CLI::write('Skipped: ' . (int) ($summary['skipped'] ?? 0));
|
||||
CLI::write('Message: ' . (string) ($summary['message'] ?? ''));
|
||||
}
|
||||
}
|
||||
15
app/Common.php
Normal file
15
app/Common.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* The goal of this file is to allow developers a location
|
||||
* where they can overwrite core procedural functions and
|
||||
* replace them with their own. This file is loaded during
|
||||
* the bootstrap process and is called during the framework's
|
||||
* execution.
|
||||
*
|
||||
* This can be looked at as a `master helper` file that is
|
||||
* loaded early on, and may also contain additional functions
|
||||
* that you'd like to use throughout your entire application
|
||||
*
|
||||
* @see: https://codeigniter.com/user_guide/extending/common.html
|
||||
*/
|
||||
202
app/Config/App.php
Normal file
202
app/Config/App.php
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class App extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Base Site URL
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* URL to your CodeIgniter root. Typically, this will be your base URL,
|
||||
* WITH a trailing slash:
|
||||
*
|
||||
* E.g., http://example.com/
|
||||
*/
|
||||
public string $baseURL = 'http://localhost:8080/';
|
||||
|
||||
/**
|
||||
* Allowed Hostnames in the Site URL other than the hostname in the baseURL.
|
||||
* If you want to accept multiple Hostnames, set this.
|
||||
*
|
||||
* E.g.,
|
||||
* When your site URL ($baseURL) is 'http://example.com/', and your site
|
||||
* also accepts 'http://media.example.com/' and 'http://accounts.example.com/':
|
||||
* ['media.example.com', 'accounts.example.com']
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $allowedHostnames = [];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Index File
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Typically, this will be your `index.php` file, unless you've renamed it to
|
||||
* something else. If you have configured your web server to remove this file
|
||||
* from your site URIs, set this variable to an empty string.
|
||||
*/
|
||||
public string $indexPage = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* URI PROTOCOL
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This item determines which server global should be used to retrieve the
|
||||
* URI string. The default setting of 'REQUEST_URI' works for most servers.
|
||||
* If your links do not seem to work, try one of the other delicious flavors:
|
||||
*
|
||||
* 'REQUEST_URI': Uses $_SERVER['REQUEST_URI']
|
||||
* 'QUERY_STRING': Uses $_SERVER['QUERY_STRING']
|
||||
* 'PATH_INFO': Uses $_SERVER['PATH_INFO']
|
||||
*
|
||||
* WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
|
||||
*/
|
||||
public string $uriProtocol = 'REQUEST_URI';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Allowed URL Characters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This lets you specify which characters are permitted within your URLs.
|
||||
| When someone tries to submit a URL with disallowed characters they will
|
||||
| get a warning message.
|
||||
|
|
||||
| As a security measure you are STRONGLY encouraged to restrict URLs to
|
||||
| as few characters as possible.
|
||||
|
|
||||
| By default, only these are allowed: `a-z 0-9~%.:_-`
|
||||
|
|
||||
| Set an empty string to allow all characters -- but only if you are insane.
|
||||
|
|
||||
| The configured value is actually a regular expression character group
|
||||
| and it will be used as: '/\A[<permittedURIChars>]+\z/iu'
|
||||
|
|
||||
| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
|
||||
|
|
||||
*/
|
||||
public string $permittedURIChars = 'a-z 0-9~%.:_\-';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Default Locale
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The Locale roughly represents the language and location that your visitor
|
||||
* is viewing the site from. It affects the language strings and other
|
||||
* strings (like currency markers, numbers, etc), that your program
|
||||
* should run under for this request.
|
||||
*/
|
||||
public string $defaultLocale = 'en';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Negotiate Locale
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If true, the current Request object will automatically determine the
|
||||
* language to use based on the value of the Accept-Language header.
|
||||
*
|
||||
* If false, no automatic detection will be performed.
|
||||
*/
|
||||
public bool $negotiateLocale = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Supported Locales
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If $negotiateLocale is true, this array lists the locales supported
|
||||
* by the application in descending order of priority. If no match is
|
||||
* found, the first locale will be used.
|
||||
*
|
||||
* IncomingRequest::setLocale() also uses this list.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $supportedLocales = ['en'];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Application Timezone
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The default timezone that will be used in your application to display
|
||||
* dates with the date helper, and can be retrieved through app_timezone()
|
||||
*
|
||||
* @see https://www.php.net/manual/en/timezones.php for list of timezones
|
||||
* supported by PHP.
|
||||
*/
|
||||
public string $appTimezone = 'UTC';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Default Character Set
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This determines which character set is used by default in various methods
|
||||
* that require a character set to be provided.
|
||||
*
|
||||
* @see http://php.net/htmlspecialchars for a list of supported charsets.
|
||||
*/
|
||||
public string $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Force Global Secure Requests
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If true, this will force every request made to this application to be
|
||||
* made via a secure connection (HTTPS). If the incoming request is not
|
||||
* secure, the user will be redirected to a secure version of the page
|
||||
* and the HTTP Strict Transport Security (HSTS) header will be set.
|
||||
*/
|
||||
public bool $forceGlobalSecureRequests = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Reverse Proxy IPs
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If your server is behind a reverse proxy, you must whitelist the proxy
|
||||
* IP addresses from which CodeIgniter should trust headers such as
|
||||
* X-Forwarded-For or Client-IP in order to properly identify
|
||||
* the visitor's IP address.
|
||||
*
|
||||
* You need to set a proxy IP address or IP address with subnets and
|
||||
* the HTTP header for the client IP address.
|
||||
*
|
||||
* Here are some examples:
|
||||
* [
|
||||
* '10.0.1.200' => 'X-Forwarded-For',
|
||||
* '192.168.5.0/24' => 'X-Real-IP',
|
||||
* ]
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $proxyIPs = [];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Content Security Policy
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Enables the Response's Content Secure Policy to restrict the sources that
|
||||
* can be used for images, scripts, CSS files, audio, video, etc. If enabled,
|
||||
* the Response object will populate default values for the policy from the
|
||||
* `ContentSecurityPolicy.php` file. Controllers can always add to those
|
||||
* restrictions at run time.
|
||||
*
|
||||
* For a better understanding of CSP, see these documents:
|
||||
*
|
||||
* @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/
|
||||
* @see http://www.w3.org/TR/CSP/
|
||||
*/
|
||||
public bool $CSPEnabled = false;
|
||||
}
|
||||
519
app/Config/Auth.php
Normal file
519
app/Config/Auth.php
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter Shield.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Shield\Config\Auth as ShieldAuth;
|
||||
use CodeIgniter\Shield\Authentication\Actions\ActionInterface;
|
||||
use CodeIgniter\Shield\Authentication\AuthenticatorInterface;
|
||||
use CodeIgniter\Shield\Authentication\Authenticators\AccessTokens;
|
||||
use CodeIgniter\Shield\Authentication\Authenticators\HmacSha256;
|
||||
use CodeIgniter\Shield\Authentication\Authenticators\JWT;
|
||||
use CodeIgniter\Shield\Authentication\Authenticators\Session;
|
||||
use CodeIgniter\Shield\Authentication\Passwords\CompositionValidator;
|
||||
use CodeIgniter\Shield\Authentication\Passwords\DictionaryValidator;
|
||||
use CodeIgniter\Shield\Authentication\Passwords\NothingPersonalValidator;
|
||||
use CodeIgniter\Shield\Authentication\Passwords\PwnedValidator;
|
||||
use CodeIgniter\Shield\Authentication\Passwords\ValidatorInterface;
|
||||
use CodeIgniter\Shield\Models\UserModel;
|
||||
|
||||
class Auth extends ShieldAuth
|
||||
{
|
||||
/**
|
||||
* ////////////////////////////////////////////////////////////////////
|
||||
* AUTHENTICATION
|
||||
* ////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
// Constants for Record Login Attempts. Do not change.
|
||||
public const RECORD_LOGIN_ATTEMPT_NONE = 0; // Do not record at all
|
||||
public const RECORD_LOGIN_ATTEMPT_FAILURE = 1; // Record only failures
|
||||
public const RECORD_LOGIN_ATTEMPT_ALL = 2; // Record all login attempts
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* View files
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
public array $views = [
|
||||
'login' => 'auth/login',
|
||||
'register' => 'auth/register',
|
||||
'layout' => '\CodeIgniter\Shield\Views\layout',
|
||||
'action_email_2fa' => '\CodeIgniter\Shield\Views\email_2fa_show',
|
||||
'action_email_2fa_verify' => '\CodeIgniter\Shield\Views\email_2fa_verify',
|
||||
'action_email_2fa_email' => '\CodeIgniter\Shield\Views\Email\email_2fa_email',
|
||||
'action_email_activate_show' => '\CodeIgniter\Shield\Views\email_activate_show',
|
||||
'action_email_activate_email' => '\CodeIgniter\Shield\Views\Email\email_activate_email',
|
||||
'magic-link-login' => '\CodeIgniter\Shield\Views\magic_link_form',
|
||||
'magic-link-message' => '\CodeIgniter\Shield\Views\magic_link_message',
|
||||
'magic-link-email' => '\CodeIgniter\Shield\Views\Email\magic_link_email',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Redirect URLs
|
||||
* --------------------------------------------------------------------
|
||||
* The default URL that a user will be redirected to after various auth
|
||||
* actions. This can be either of the following:
|
||||
*
|
||||
* 1. An absolute URL. E.g. http://example.com OR https://example.com
|
||||
* 2. A named route that can be accessed using `route_to()` or `url_to()`
|
||||
* 3. A URI path within the application. e.g 'admin', 'login', 'expath'
|
||||
*
|
||||
* If you need more flexibility you can override the `getUrl()` method
|
||||
* to apply any logic you may need.
|
||||
*/
|
||||
public array $redirects = [
|
||||
'register' => '/',
|
||||
'login' => '/',
|
||||
'logout' => 'login',
|
||||
'force_reset' => '/',
|
||||
'permission_denied' => '/',
|
||||
'group_denied' => '/',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Authentication Actions
|
||||
* --------------------------------------------------------------------
|
||||
* Specifies the class that represents an action to take after
|
||||
* the user logs in or registers a new account at the site.
|
||||
*
|
||||
* You must register actions in the order of the actions to be performed.
|
||||
*
|
||||
* Available actions with Shield:
|
||||
* - register: \CodeIgniter\Shield\Authentication\Actions\EmailActivator::class
|
||||
* - login: \CodeIgniter\Shield\Authentication\Actions\Email2FA::class
|
||||
*
|
||||
* Custom Actions and Requirements:
|
||||
*
|
||||
* - All actions must implement \CodeIgniter\Shield\Authentication\Actions\ActionInterface.
|
||||
* - Custom actions for "register" must have a class name that ends with the suffix "Activator" (e.g., `CustomSmsActivator`) ensure proper functionality.
|
||||
*
|
||||
* @var array<string, class-string<ActionInterface>|null>
|
||||
*/
|
||||
public array $actions = [
|
||||
'register' => null,
|
||||
'login' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Authenticators
|
||||
* --------------------------------------------------------------------
|
||||
* The available authentication systems, listed
|
||||
* with alias and class name. These can be referenced
|
||||
* by alias in the auth helper:
|
||||
* auth('tokens')->attempt($credentials);
|
||||
*
|
||||
* @var array<string, class-string<AuthenticatorInterface>>
|
||||
*/
|
||||
public array $authenticators = [
|
||||
'tokens' => AccessTokens::class,
|
||||
'session' => Session::class,
|
||||
'hmac' => HmacSha256::class,
|
||||
// 'jwt' => JWT::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Default Authenticator
|
||||
* --------------------------------------------------------------------
|
||||
* The Authenticator to use when none is specified.
|
||||
* Uses the $key from the $authenticators array above.
|
||||
*/
|
||||
public string $defaultAuthenticator = 'session';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Authentication Chain
|
||||
* --------------------------------------------------------------------
|
||||
* The Authenticators to test logged in status against
|
||||
* when using the 'chain' filter. Each Authenticator listed will be checked.
|
||||
* If no match is found, then the next in the chain will be checked.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $authenticationChain = [
|
||||
'session',
|
||||
'tokens',
|
||||
'hmac',
|
||||
// 'jwt',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Allow Registration
|
||||
* --------------------------------------------------------------------
|
||||
* Determines whether users can register for the site.
|
||||
*/
|
||||
public bool $allowRegistration = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Record Last Active Date
|
||||
* --------------------------------------------------------------------
|
||||
* If true, will always update the `last_active` datetime for the
|
||||
* logged-in user on every page request.
|
||||
* This feature only works when session/tokens/hmac/chain/jwt filter is active.
|
||||
*
|
||||
* @see https://codeigniter4.github.io/shield/quick_start_guide/using_session_auth/#protecting-pages for set filters.
|
||||
*/
|
||||
public bool $recordActiveDate = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Allow Magic Link Logins
|
||||
* --------------------------------------------------------------------
|
||||
* If true, will allow the use of "magic links" sent via the email
|
||||
* as a way to log a user in without the need for a password.
|
||||
* By default, this is used in place of a password reset flow, but
|
||||
* could be modified as the only method of login once an account
|
||||
* has been set up.
|
||||
*/
|
||||
public bool $allowMagicLinkLogins = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Magic Link Lifetime
|
||||
* --------------------------------------------------------------------
|
||||
* Specifies the amount of time, in seconds, that a magic link is valid.
|
||||
* You can use Time Constants or any desired number.
|
||||
*/
|
||||
public int $magicLinkLifetime = HOUR;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Session Authenticator Configuration
|
||||
* --------------------------------------------------------------------
|
||||
* These settings only apply if you are using the Session Authenticator
|
||||
* for authentication.
|
||||
*
|
||||
* - field The name of the key the current user info is stored in session
|
||||
* - allowRemembering Does the system allow use of "remember-me"
|
||||
* - rememberCookieName The name of the cookie to use for "remember-me"
|
||||
* - rememberLength The length of time, in seconds, to remember a user.
|
||||
*
|
||||
* @var array<string, bool|int|string>
|
||||
*/
|
||||
public array $sessionConfig = [
|
||||
'field' => 'user',
|
||||
'allowRemembering' => true,
|
||||
'rememberCookieName' => 'remember',
|
||||
'rememberLength' => 30 * DAY,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* The validation rules for username
|
||||
* --------------------------------------------------------------------
|
||||
*
|
||||
* Do not use string rules like `required|valid_email`.
|
||||
*
|
||||
* @var array<string, array<int, string>|string>
|
||||
*/
|
||||
public array $usernameValidationRules = [
|
||||
'label' => 'Auth.username',
|
||||
'rules' => [
|
||||
'required',
|
||||
'max_length[30]',
|
||||
'min_length[3]',
|
||||
'regex_match[/\A[a-zA-Z0-9\.]+\z/]',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* The validation rules for email
|
||||
* --------------------------------------------------------------------
|
||||
*
|
||||
* Do not use string rules like `required|valid_email`.
|
||||
*
|
||||
* @var array<string, array<int, string>|string>
|
||||
*/
|
||||
public array $emailValidationRules = [
|
||||
'label' => 'Auth.email',
|
||||
'rules' => [
|
||||
'required',
|
||||
'max_length[254]',
|
||||
'valid_email',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Minimum Password Length
|
||||
* --------------------------------------------------------------------
|
||||
* The minimum length that a password must be to be accepted.
|
||||
* Recommended minimum value by NIST = 8 characters.
|
||||
*/
|
||||
public int $minimumPasswordLength = 8;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Password Check Helpers
|
||||
* --------------------------------------------------------------------
|
||||
* The PasswordValidator class runs the password through all of these
|
||||
* classes, each getting the opportunity to pass/fail the password.
|
||||
* You can add custom classes as long as they adhere to the
|
||||
* CodeIgniter\Shield\Authentication\Passwords\ValidatorInterface.
|
||||
*
|
||||
* @var list<class-string<ValidatorInterface>>
|
||||
*/
|
||||
public array $passwordValidators = [
|
||||
CompositionValidator::class,
|
||||
// NothingPersonalValidator::class,
|
||||
DictionaryValidator::class,
|
||||
// PwnedValidator::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Valid login fields
|
||||
* --------------------------------------------------------------------
|
||||
* Fields that are available to be used as credentials for login.
|
||||
*/
|
||||
public array $validFields = [
|
||||
'username',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Additional Fields for "Nothing Personal"
|
||||
* --------------------------------------------------------------------
|
||||
* The NothingPersonalValidator prevents personal information from
|
||||
* being used in passwords. The email and username fields are always
|
||||
* considered by the validator. Do not enter those field names here.
|
||||
*
|
||||
* An extended User Entity might include other personal info such as
|
||||
* first and/or last names. $personalFields is where you can add
|
||||
* fields to be considered as "personal" by the NothingPersonalValidator.
|
||||
* For example:
|
||||
* $personalFields = ['firstname', 'lastname'];
|
||||
*/
|
||||
public array $personalFields = [];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Password / Username Similarity
|
||||
* --------------------------------------------------------------------
|
||||
* Among other things, the NothingPersonalValidator checks the
|
||||
* amount of sameness between the password and username.
|
||||
* Passwords that are too much like the username are invalid.
|
||||
*
|
||||
* The value set for $maxSimilarity represents the maximum percentage
|
||||
* of similarity at which the password will be accepted. In other words, any
|
||||
* calculated similarity equal to, or greater than $maxSimilarity
|
||||
* is rejected.
|
||||
*
|
||||
* The accepted range is 0-100, with 0 (zero) meaning don't check similarity.
|
||||
* Using values at either extreme of the *working range* (1-100) is
|
||||
* not advised. The low end is too restrictive and the high end is too permissive.
|
||||
* The suggested value for $maxSimilarity is 50.
|
||||
*
|
||||
* You may be thinking that a value of 100 should have the effect of accepting
|
||||
* everything like a value of 0 does. That's logical and probably true,
|
||||
* but is unproven and untested. Besides, 0 skips the work involved
|
||||
* making the calculation unlike when using 100.
|
||||
*
|
||||
* The (admittedly limited) testing that's been done suggests a useful working range
|
||||
* of 50 to 60. You can set it lower than 50, but site users will probably start
|
||||
* to complain about the large number of proposed passwords getting rejected.
|
||||
* At around 60 or more it starts to see pairs like 'captain joe' and 'joe*captain' as
|
||||
* perfectly acceptable which clearly they are not.
|
||||
*
|
||||
* To disable similarity checking set the value to 0.
|
||||
* public $maxSimilarity = 0;
|
||||
*/
|
||||
public int $maxSimilarity = 50;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Hashing Algorithm to use
|
||||
* --------------------------------------------------------------------
|
||||
* Valid values are
|
||||
* - PASSWORD_DEFAULT (default)
|
||||
* - PASSWORD_BCRYPT
|
||||
* - PASSWORD_ARGON2I - As of PHP 7.2 only if compiled with support for it
|
||||
* - PASSWORD_ARGON2ID - As of PHP 7.3 only if compiled with support for it
|
||||
*/
|
||||
public string $hashAlgorithm = PASSWORD_DEFAULT;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* ARGON2I/ARGON2ID Algorithm options
|
||||
* --------------------------------------------------------------------
|
||||
* The ARGON2I method of hashing allows you to define the "memory_cost",
|
||||
* the "time_cost" and the number of "threads", whenever a password hash is
|
||||
* created.
|
||||
*/
|
||||
public int $hashMemoryCost = 65536; // PASSWORD_ARGON2_DEFAULT_MEMORY_COST;
|
||||
|
||||
public int $hashTimeCost = 4; // PASSWORD_ARGON2_DEFAULT_TIME_COST;
|
||||
public int $hashThreads = 1; // PASSWORD_ARGON2_DEFAULT_THREADS;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* BCRYPT Algorithm options
|
||||
* --------------------------------------------------------------------
|
||||
* The BCRYPT method of hashing allows you to define the "cost"
|
||||
* or number of iterations made, whenever a password hash is created.
|
||||
* This defaults to a value of 12 which is an acceptable number.
|
||||
* However, depending on the security needs of your application
|
||||
* and the power of your hardware, you might want to increase the
|
||||
* cost. This makes the hashing process takes longer.
|
||||
*
|
||||
* Valid range is between 4 - 31.
|
||||
*/
|
||||
public int $hashCost = 12;
|
||||
|
||||
/**
|
||||
* ////////////////////////////////////////////////////////////////////
|
||||
* OTHER SETTINGS
|
||||
* ////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Customize the DB group used for each model
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
public ?string $DBGroup = null;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Customize Name of Shield Tables
|
||||
* --------------------------------------------------------------------
|
||||
* Only change if you want to rename the default Shield table names
|
||||
*
|
||||
* It may be necessary to change the names of the tables for
|
||||
* security reasons, to prevent the conflict of table names,
|
||||
* the internal policy of the companies or any other reason.
|
||||
*
|
||||
* - users Auth Users Table, the users info is stored.
|
||||
* - auth_identities Auth Identities Table, Used for storage of passwords, access tokens, social login identities, etc.
|
||||
* - auth_logins Auth Login Attempts, Table records login attempts.
|
||||
* - auth_token_logins Auth Token Login Attempts Table, Records Bearer Token type login attempts.
|
||||
* - auth_remember_tokens Auth Remember Tokens (remember-me) Table.
|
||||
* - auth_groups_users Groups Users Table.
|
||||
* - auth_permissions_users Users Permissions Table.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $tables = [
|
||||
'users' => 'users',
|
||||
'identities' => 'auth_identities',
|
||||
'logins' => 'auth_logins',
|
||||
'token_logins' => 'auth_token_logins',
|
||||
'remember_tokens' => 'auth_remember_tokens',
|
||||
'groups_users' => 'auth_groups_users',
|
||||
'permissions_users' => 'auth_permissions_users',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* User Provider
|
||||
* --------------------------------------------------------------------
|
||||
* The name of the class that handles user persistence.
|
||||
* By default, this is the included UserModel, which
|
||||
* works with any of the database engines supported by CodeIgniter.
|
||||
* You can change it as long as they adhere to the
|
||||
* CodeIgniter\Shield\Models\UserModel.
|
||||
*
|
||||
* @var class-string<UserModel>
|
||||
*/
|
||||
public string $userProvider = UserModel::class;
|
||||
|
||||
/**
|
||||
* Returns the URL that a user should be redirected
|
||||
* to after a successful login.
|
||||
*/
|
||||
public function loginRedirect(): string
|
||||
{
|
||||
$session = session();
|
||||
$url = $session->getTempdata('beforeLoginUrl') ?? setting('Auth.redirects')['login'];
|
||||
|
||||
return $this->getUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL that a user should be redirected
|
||||
* to after they are logged out.
|
||||
*/
|
||||
public function logoutRedirect(): string
|
||||
{
|
||||
$url = setting('Auth.redirects')['logout'];
|
||||
|
||||
return $this->getUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL the user should be redirected to
|
||||
* after a successful registration.
|
||||
*/
|
||||
public function registerRedirect(): string
|
||||
{
|
||||
$url = setting('Auth.redirects')['register'];
|
||||
|
||||
return $this->getUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL the user should be redirected to
|
||||
* if force_reset identity is set to true.
|
||||
*/
|
||||
public function forcePasswordResetRedirect(): string
|
||||
{
|
||||
$url = setting('Auth.redirects')['force_reset'];
|
||||
|
||||
return $this->getUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL the user should be redirected to
|
||||
* if permission denied.
|
||||
*/
|
||||
public function permissionDeniedRedirect(): string
|
||||
{
|
||||
$url = setting('Auth.redirects')['permission_denied'];
|
||||
|
||||
return $this->getUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL the user should be redirected to
|
||||
* if group denied.
|
||||
*/
|
||||
public function groupDeniedRedirect(): string
|
||||
{
|
||||
$url = setting('Auth.redirects')['group_denied'];
|
||||
|
||||
return $this->getUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a string which can be an absolute URL or
|
||||
* a named route or just a URI path, and returns the
|
||||
* full path.
|
||||
*
|
||||
* @param string $url an absolute URL or a named route or just URI path
|
||||
*/
|
||||
protected function getUrl(string $url): string
|
||||
{
|
||||
return match (true) {
|
||||
str_starts_with($url, 'http://') || str_starts_with($url, 'https://') => $url,
|
||||
route_to($url) !== false => rtrim(url_to($url), '/ '),
|
||||
default => rtrim(site_url($url), '/ '),
|
||||
};
|
||||
}
|
||||
}
|
||||
149
app/Config/AuthGroups.php
Normal file
149
app/Config/AuthGroups.php
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter Shield.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Shield\Config\AuthGroups as ShieldAuthGroups;
|
||||
|
||||
class AuthGroups extends ShieldAuthGroups
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Default Group
|
||||
* --------------------------------------------------------------------
|
||||
* The group that a newly registered user is added to.
|
||||
*/
|
||||
public string $defaultGroup = 'user';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Groups
|
||||
* --------------------------------------------------------------------
|
||||
* An associative array of the available groups in the system, where the keys
|
||||
* are the group names and the values are arrays of the group info.
|
||||
*
|
||||
* Whatever value you assign as the key will be used to refer to the group
|
||||
* when using functions such as:
|
||||
* $user->addGroup('superadmin');
|
||||
*
|
||||
* @var array<string, array<string, string>>
|
||||
*
|
||||
* @see https://codeigniter4.github.io/shield/quick_start_guide/using_authorization/#change-available-groups for more info
|
||||
*/
|
||||
public array $groups = [
|
||||
'superadmin' => [
|
||||
'title' => 'Super Admin',
|
||||
'description' => 'Complete control of the site.',
|
||||
],
|
||||
'admin' => [
|
||||
'title' => 'Admin',
|
||||
'description' => 'Day to day administrators of the site.',
|
||||
],
|
||||
'developer' => [
|
||||
'title' => 'Developer',
|
||||
'description' => 'Site programmers.',
|
||||
],
|
||||
'user' => [
|
||||
'title' => 'User',
|
||||
'description' => 'General users of the site. Often customers.',
|
||||
],
|
||||
'beta' => [
|
||||
'title' => 'Beta User',
|
||||
'description' => 'Has access to beta-level features.',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Permissions
|
||||
* --------------------------------------------------------------------
|
||||
* The available permissions in the system.
|
||||
*
|
||||
* If a permission is not listed here it cannot be used.
|
||||
*/
|
||||
public array $permissions = [
|
||||
'admin.access' => 'Can access the sites admin area',
|
||||
'admin.settings' => 'Can access the main site settings',
|
||||
'users.manage-admins' => 'Can manage other admins',
|
||||
'users.create' => 'Can create new non-admin users',
|
||||
'users.edit' => 'Can edit existing non-admin users',
|
||||
'users.delete' => 'Can delete existing non-admin users',
|
||||
'beta.access' => 'Can access beta-level features',
|
||||
'billing.access' => 'Can access billing module',
|
||||
'opd.doctor-panel.access' => 'Can access OPD doctor work panel (doctor-only)',
|
||||
'billing.opd.edit' => 'Can edit OPD registrations',
|
||||
'billing.opd.pay' => 'Can confirm OPD payments',
|
||||
'billing.charges.view' => 'Can view charges invoices',
|
||||
'billing.charges.edit' => 'Can edit charges invoices',
|
||||
'billing.charges.date-edit' => 'Can edit charges invoice date',
|
||||
'billing.charges.pay' => 'Can confirm charges payments',
|
||||
'billing.charges.cancel' => 'Can cancel charges invoices',
|
||||
'billing.charges.correct' => 'Can apply charges corrections',
|
||||
'billing.ipd.access' => 'Can access IPD billing module',
|
||||
'billing.ipd.current-admission' => 'Can view IPD current admissions',
|
||||
'billing.ipd.invoice' => 'Can view IPD invoice list',
|
||||
'billing.ipd.cash-balance' => 'Can view IPD cash balance report',
|
||||
'billing.ipd.export' => 'Can export IPD cash balance report',
|
||||
'pharmacy.access' => 'Can access pharmacy module',
|
||||
'pharmacy.purchase.status-update' => 'Can update pharmacy purchase invoice status',
|
||||
'template.pathology' => 'Can access pathology templates',
|
||||
'template.ultrasound' => 'Can access ultrasound templates',
|
||||
'template.xray' => 'Can access x-ray templates',
|
||||
'template.ct' => 'Can access CT templates',
|
||||
'template.mri' => 'Can access MRI templates',
|
||||
'template.echo' => 'Can access ECHO templates',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Permissions Matrix
|
||||
* --------------------------------------------------------------------
|
||||
* Maps permissions to groups.
|
||||
*
|
||||
* This defines group-level permissions.
|
||||
*/
|
||||
public array $matrix = [
|
||||
'superadmin' => [
|
||||
'admin.*',
|
||||
'users.*',
|
||||
'beta.*',
|
||||
'billing.*',
|
||||
'pharmacy.*',
|
||||
'template.*',
|
||||
],
|
||||
'admin' => [
|
||||
'admin.access',
|
||||
'users.create',
|
||||
'users.edit',
|
||||
'users.delete',
|
||||
'beta.access',
|
||||
'billing.*',
|
||||
'pharmacy.*',
|
||||
'template.*',
|
||||
],
|
||||
'developer' => [
|
||||
'admin.access',
|
||||
'admin.settings',
|
||||
'users.create',
|
||||
'users.edit',
|
||||
'beta.access',
|
||||
'billing.*',
|
||||
'pharmacy.*',
|
||||
'template.*',
|
||||
],
|
||||
'user' => [],
|
||||
'beta' => [
|
||||
'beta.access',
|
||||
],
|
||||
];
|
||||
}
|
||||
138
app/Config/AuthToken.php
Normal file
138
app/Config/AuthToken.php
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter Shield.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Shield\Config\AuthToken as ShieldAuthToken;
|
||||
|
||||
/**
|
||||
* Configuration for Token Auth and HMAC Auth
|
||||
*/
|
||||
class AuthToken extends ShieldAuthToken
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Record Login Attempts for Token Auth and HMAC Auth
|
||||
* --------------------------------------------------------------------
|
||||
* Specify which login attempts are recorded in the database.
|
||||
*
|
||||
* Valid values are:
|
||||
* - Auth::RECORD_LOGIN_ATTEMPT_NONE
|
||||
* - Auth::RECORD_LOGIN_ATTEMPT_FAILURE
|
||||
* - Auth::RECORD_LOGIN_ATTEMPT_ALL
|
||||
*/
|
||||
public int $recordLoginAttempt = Auth::RECORD_LOGIN_ATTEMPT_FAILURE;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Name of Authenticator Header
|
||||
* --------------------------------------------------------------------
|
||||
* The name of Header that the Authorization token should be found.
|
||||
* According to the specs, this should be `Authorization`, but rare
|
||||
* circumstances might need a different header.
|
||||
*/
|
||||
public array $authenticatorHeader = [
|
||||
'tokens' => 'Authorization',
|
||||
'hmac' => 'Authorization',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Unused Token Lifetime for Token Auth and HMAC Auth
|
||||
* --------------------------------------------------------------------
|
||||
* Determines the amount of time, in seconds, that an unused token can
|
||||
* be used.
|
||||
*/
|
||||
public int $unusedTokenLifetime = YEAR;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* Secret2 storage character limit
|
||||
* --------------------------------------------------------------------
|
||||
* Database size limit for the identities 'secret2' field.
|
||||
*/
|
||||
public int $secret2StorageLimit = 255;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* HMAC secret key byte size
|
||||
* --------------------------------------------------------------------
|
||||
* Specify in integer the desired byte size of the
|
||||
* HMAC SHA256 byte size
|
||||
*/
|
||||
public int $hmacSecretKeyByteSize = 32;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* HMAC encryption Keys
|
||||
* --------------------------------------------------------------------
|
||||
* This sets the key to be used when encrypting a user's HMAC Secret Key.
|
||||
*
|
||||
* 'keys' is an array of keys which will facilitate key rotation. Valid
|
||||
* keyTitles must include only [a-zA-Z0-9_] and should be kept to a
|
||||
* max of 8 characters.
|
||||
*
|
||||
* Each keyTitle is an associative array containing the required 'key'
|
||||
* value, and the optional 'driver' and 'digest' values. If the
|
||||
* 'driver' and 'digest' values are not specified, the default 'driver'
|
||||
* and 'digest' values will be used.
|
||||
*
|
||||
* Old keys will are used to decrypt existing Secret Keys. It is encouraged
|
||||
* to run 'php spark shield:hmac reencrypt' to update existing Secret
|
||||
* Key encryptions.
|
||||
*
|
||||
* @see https://codeigniter.com/user_guide/libraries/encryption.html
|
||||
*
|
||||
* @var array<string, array{key: string, driver?: string, digest?: string}>|string
|
||||
*
|
||||
* NOTE: The value becomes temporarily a string when setting value as JSON
|
||||
* from environment variable.
|
||||
*
|
||||
* [key_name => ['key' => key_value]]
|
||||
* or [key_name => ['key' => key_value, 'driver' => driver, 'digest' => digest]]
|
||||
*/
|
||||
public $hmacEncryptionKeys = [
|
||||
'k1' => [
|
||||
'key' => '',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* HMAC Current Encryption Key Selector
|
||||
* --------------------------------------------------------------------
|
||||
* This specifies which of the encryption keys should be used.
|
||||
*/
|
||||
public string $hmacEncryptionCurrentKey = 'k1';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* HMAC Encryption Key Driver
|
||||
* --------------------------------------------------------------------
|
||||
* This specifies which of the encryption drivers should be used.
|
||||
*
|
||||
* Available drivers:
|
||||
* - OpenSSL
|
||||
* - Sodium
|
||||
*/
|
||||
public string $hmacEncryptionDefaultDriver = 'OpenSSL';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------
|
||||
* HMAC Encryption Key Driver
|
||||
* --------------------------------------------------------------------
|
||||
* THis specifies the type of encryption to be used.
|
||||
* e.g. 'SHA512' or 'SHA256'.
|
||||
*/
|
||||
public string $hmacEncryptionDefaultDigest = 'SHA512';
|
||||
}
|
||||
92
app/Config/Autoload.php
Normal file
92
app/Config/Autoload.php
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\AutoloadConfig;
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* AUTOLOADER CONFIGURATION
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* This file defines the namespaces and class maps so the Autoloader
|
||||
* can find the files as needed.
|
||||
*
|
||||
* NOTE: If you use an identical key in $psr4 or $classmap, then
|
||||
* the values in this file will overwrite the framework's values.
|
||||
*
|
||||
* NOTE: This class is required prior to Autoloader instantiation,
|
||||
* and does not extend BaseConfig.
|
||||
*/
|
||||
class Autoload extends AutoloadConfig
|
||||
{
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Namespaces
|
||||
* -------------------------------------------------------------------
|
||||
* This maps the locations of any namespaces in your application to
|
||||
* their location on the file system. These are used by the autoloader
|
||||
* to locate files the first time they have been instantiated.
|
||||
*
|
||||
* The 'Config' (APPPATH . 'Config') and 'CodeIgniter' (SYSTEMPATH) are
|
||||
* already mapped for you.
|
||||
*
|
||||
* You may change the name of the 'App' namespace if you wish,
|
||||
* but this should be done prior to creating any namespaced classes,
|
||||
* else you will need to modify all of those classes for this to work.
|
||||
*
|
||||
* @var array<string, list<string>|string>
|
||||
*/
|
||||
public $psr4 = [
|
||||
APP_NAMESPACE => APPPATH,
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Class Map
|
||||
* -------------------------------------------------------------------
|
||||
* The class map provides a map of class names and their exact
|
||||
* location on the drive. Classes loaded in this manner will have
|
||||
* slightly faster performance because they will not have to be
|
||||
* searched for within one or more directories as they would if they
|
||||
* were being autoloaded through a namespace.
|
||||
*
|
||||
* Prototype:
|
||||
* $classmap = [
|
||||
* 'MyClass' => '/path/to/class/file.php'
|
||||
* ];
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $classmap = [];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Files
|
||||
* -------------------------------------------------------------------
|
||||
* The files array provides a list of paths to __non-class__ files
|
||||
* that will be autoloaded. This can be useful for bootstrap operations
|
||||
* or for loading functions.
|
||||
*
|
||||
* Prototype:
|
||||
* $files = [
|
||||
* '/path/to/my/file.php',
|
||||
* ];
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public $files = [];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Helpers
|
||||
* -------------------------------------------------------------------
|
||||
* Prototype:
|
||||
* $helpers = [
|
||||
* 'form',
|
||||
* ];
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public $helpers = ['auth', 'setting'];
|
||||
}
|
||||
34
app/Config/Boot/development.php
Normal file
34
app/Config/Boot/development.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ERROR DISPLAY
|
||||
|--------------------------------------------------------------------------
|
||||
| In development, we want to show as many errors as possible to help
|
||||
| make sure they don't make it to production. And save us hours of
|
||||
| painful debugging.
|
||||
|
|
||||
| If you set 'display_errors' to '1', CI4's detailed error report will show.
|
||||
*/
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG BACKTRACES
|
||||
|--------------------------------------------------------------------------
|
||||
| If true, this constant will tell the error screens to display debug
|
||||
| backtraces along with the other error information. If you would
|
||||
| prefer to not see this, set this value to false.
|
||||
*/
|
||||
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG MODE
|
||||
|--------------------------------------------------------------------------
|
||||
| Debug mode is an experimental flag that can allow changes throughout
|
||||
| the system. This will control whether Kint is loaded, and a few other
|
||||
| items. It can always be used within your own application too.
|
||||
*/
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', true);
|
||||
25
app/Config/Boot/production.php
Normal file
25
app/Config/Boot/production.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ERROR DISPLAY
|
||||
|--------------------------------------------------------------------------
|
||||
| Don't show ANY in production environments. Instead, let the system catch
|
||||
| it and display a generic error message.
|
||||
|
|
||||
| If you set 'display_errors' to '1', CI4's detailed error report will show.
|
||||
*/
|
||||
error_reporting(E_ALL & ~E_DEPRECATED);
|
||||
// If you want to suppress more types of errors.
|
||||
// error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT & ~E_USER_NOTICE & ~E_USER_DEPRECATED);
|
||||
ini_set('display_errors', '0');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG MODE
|
||||
|--------------------------------------------------------------------------
|
||||
| Debug mode is an experimental flag that can allow changes throughout
|
||||
| the system. It's not widely used currently, and may not survive
|
||||
| release of the framework.
|
||||
*/
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', false);
|
||||
38
app/Config/Boot/testing.php
Normal file
38
app/Config/Boot/testing.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* The environment testing is reserved for PHPUnit testing. It has special
|
||||
* conditions built into the framework at various places to assist with that.
|
||||
* You can’t use it for your development.
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ERROR DISPLAY
|
||||
|--------------------------------------------------------------------------
|
||||
| In development, we want to show as many errors as possible to help
|
||||
| make sure they don't make it to production. And save us hours of
|
||||
| painful debugging.
|
||||
*/
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG BACKTRACES
|
||||
|--------------------------------------------------------------------------
|
||||
| If true, this constant will tell the error screens to display debug
|
||||
| backtraces along with the other error information. If you would
|
||||
| prefer to not see this, set this value to false.
|
||||
*/
|
||||
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG MODE
|
||||
|--------------------------------------------------------------------------
|
||||
| Debug mode is an experimental flag that can allow changes throughout
|
||||
| the system. It's not widely used currently, and may not survive
|
||||
| release of the framework.
|
||||
*/
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', true);
|
||||
36
app/Config/CURLRequest.php
Normal file
36
app/Config/CURLRequest.php
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class CURLRequest extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CURLRequest Share Connection Options
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Share connection options between requests.
|
||||
*
|
||||
* @var list<int>
|
||||
*
|
||||
* @see https://www.php.net/manual/en/curl.constants.php#constant.curl-lock-data-connect
|
||||
*/
|
||||
public array $shareConnectionOptions = [
|
||||
CURL_LOCK_DATA_CONNECT,
|
||||
CURL_LOCK_DATA_DNS,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CURLRequest Share Options
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Whether share options between requests or not.
|
||||
*
|
||||
* If true, all the options won't be reset between requests.
|
||||
* It may cause an error request with unnecessary headers.
|
||||
*/
|
||||
public bool $shareOptions = false;
|
||||
}
|
||||
198
app/Config/Cache.php
Normal file
198
app/Config/Cache.php
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Cache\CacheInterface;
|
||||
use CodeIgniter\Cache\Handlers\ApcuHandler;
|
||||
use CodeIgniter\Cache\Handlers\DummyHandler;
|
||||
use CodeIgniter\Cache\Handlers\FileHandler;
|
||||
use CodeIgniter\Cache\Handlers\MemcachedHandler;
|
||||
use CodeIgniter\Cache\Handlers\PredisHandler;
|
||||
use CodeIgniter\Cache\Handlers\RedisHandler;
|
||||
use CodeIgniter\Cache\Handlers\WincacheHandler;
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class Cache extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Primary Handler
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The name of the preferred handler that should be used. If for some reason
|
||||
* it is not available, the $backupHandler will be used in its place.
|
||||
*/
|
||||
public string $handler = 'file';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Backup Handler
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The name of the handler that will be used in case the first one is
|
||||
* unreachable. Often, 'file' is used here since the filesystem is
|
||||
* always available, though that's not always practical for the app.
|
||||
*/
|
||||
public string $backupHandler = 'dummy';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Key Prefix
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This string is added to all cache item names to help avoid collisions
|
||||
* if you run multiple applications with the same cache engine.
|
||||
*/
|
||||
public string $prefix = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Default TTL
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The default number of seconds to save items when none is specified.
|
||||
*
|
||||
* WARNING: This is not used by framework handlers where 60 seconds is
|
||||
* hard-coded, but may be useful to projects and modules. This will replace
|
||||
* the hard-coded value in a future release.
|
||||
*/
|
||||
public int $ttl = 60;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Reserved Characters
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* A string of reserved characters that will not be allowed in keys or tags.
|
||||
* Strings that violate this restriction will cause handlers to throw.
|
||||
* Default: {}()/\@:
|
||||
*
|
||||
* NOTE: The default set is required for PSR-6 compliance.
|
||||
*/
|
||||
public string $reservedCharacters = '{}()/\@:';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* File settings
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Your file storage preferences can be specified below, if you are using
|
||||
* the File driver.
|
||||
*
|
||||
* @var array{storePath?: string, mode?: int}
|
||||
*/
|
||||
public array $file = [
|
||||
'storePath' => WRITEPATH . 'cache/',
|
||||
'mode' => 0640,
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------------
|
||||
* Memcached settings
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* Your Memcached servers can be specified below, if you are using
|
||||
* the Memcached drivers.
|
||||
*
|
||||
* @see https://codeigniter.com/user_guide/libraries/caching.html#memcached
|
||||
*
|
||||
* @var array{host?: string, port?: int, weight?: int, raw?: bool}
|
||||
*/
|
||||
public array $memcached = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
'weight' => 1,
|
||||
'raw' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------------
|
||||
* Redis settings
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* Your Redis server can be specified below, if you are using
|
||||
* the Redis or Predis drivers.
|
||||
*
|
||||
* @var array{
|
||||
* host?: string,
|
||||
* password?: string|null,
|
||||
* port?: int,
|
||||
* timeout?: int,
|
||||
* async?: bool,
|
||||
* persistent?: bool,
|
||||
* database?: int
|
||||
* }
|
||||
*/
|
||||
public array $redis = [
|
||||
'host' => '127.0.0.1',
|
||||
'password' => null,
|
||||
'port' => 6379,
|
||||
'timeout' => 0,
|
||||
'async' => false, // specific to Predis and ignored by the native Redis extension
|
||||
'persistent' => false,
|
||||
'database' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Available Cache Handlers
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is an array of cache engine alias' and class names. Only engines
|
||||
* that are listed here are allowed to be used.
|
||||
*
|
||||
* @var array<string, class-string<CacheInterface>>
|
||||
*/
|
||||
public array $validHandlers = [
|
||||
'apcu' => ApcuHandler::class,
|
||||
'dummy' => DummyHandler::class,
|
||||
'file' => FileHandler::class,
|
||||
'memcached' => MemcachedHandler::class,
|
||||
'predis' => PredisHandler::class,
|
||||
'redis' => RedisHandler::class,
|
||||
'wincache' => WincacheHandler::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Web Page Caching: Cache Include Query String
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Whether to take the URL query string into consideration when generating
|
||||
* output cache files. Valid options are:
|
||||
*
|
||||
* false = Disabled
|
||||
* true = Enabled, take all query parameters into account.
|
||||
* Please be aware that this may result in numerous cache
|
||||
* files generated for the same page over and over again.
|
||||
* ['q'] = Enabled, but only take into account the specified list
|
||||
* of query parameters.
|
||||
*
|
||||
* @var bool|list<string>
|
||||
*/
|
||||
public $cacheQueryString = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Web Page Caching: Cache Status Codes
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* HTTP status codes that are allowed to be cached. Only responses with
|
||||
* these status codes will be cached by the PageCache filter.
|
||||
*
|
||||
* Default: [] - Cache all status codes (backward compatible)
|
||||
*
|
||||
* Recommended: [200] - Only cache successful responses
|
||||
*
|
||||
* You can also use status codes like:
|
||||
* [200, 404, 410] - Cache successful responses and specific error codes
|
||||
* [200, 201, 202, 203, 204] - All 2xx successful responses
|
||||
*
|
||||
* WARNING: Using [] may cache temporary error pages (404, 500, etc).
|
||||
* Consider restricting to [200] for production applications to avoid
|
||||
* caching errors that should be temporary.
|
||||
*
|
||||
* @var list<int>
|
||||
*/
|
||||
public array $cacheStatusCodes = [];
|
||||
}
|
||||
79
app/Config/Constants.php
Normal file
79
app/Config/Constants.php
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
| --------------------------------------------------------------------
|
||||
| App Namespace
|
||||
| --------------------------------------------------------------------
|
||||
|
|
||||
| This defines the default Namespace that is used throughout
|
||||
| CodeIgniter to refer to the Application directory. Change
|
||||
| this constant to change the namespace that all application
|
||||
| classes should use.
|
||||
|
|
||||
| NOTE: changing this will require manually modifying the
|
||||
| existing namespaces of App\* namespaced-classes.
|
||||
*/
|
||||
defined('APP_NAMESPACE') || define('APP_NAMESPACE', 'App');
|
||||
|
||||
/*
|
||||
| --------------------------------------------------------------------------
|
||||
| Composer Path
|
||||
| --------------------------------------------------------------------------
|
||||
|
|
||||
| The path that Composer's autoload file is expected to live. By default,
|
||||
| the vendor folder is in the Root directory, but you can customize that here.
|
||||
*/
|
||||
defined('COMPOSER_PATH') || define('COMPOSER_PATH', ROOTPATH . 'vendor/autoload.php');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Timing Constants
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Provide simple ways to work with the myriad of PHP functions that
|
||||
| require information to be in seconds.
|
||||
*/
|
||||
defined('SECOND') || define('SECOND', 1);
|
||||
defined('MINUTE') || define('MINUTE', 60);
|
||||
defined('HOUR') || define('HOUR', 3600);
|
||||
defined('DAY') || define('DAY', 86400);
|
||||
defined('WEEK') || define('WEEK', 604800);
|
||||
defined('MONTH') || define('MONTH', 2_592_000);
|
||||
defined('YEAR') || define('YEAR', 31_536_000);
|
||||
defined('DECADE') || define('DECADE', 315_360_000);
|
||||
|
||||
/*
|
||||
| --------------------------------------------------------------------------
|
||||
| Exit Status Codes
|
||||
| --------------------------------------------------------------------------
|
||||
|
|
||||
| Used to indicate the conditions under which the script is exit()ing.
|
||||
| While there is no universal standard for error codes, there are some
|
||||
| broad conventions. Three such conventions are mentioned below, for
|
||||
| those who wish to make use of them. The CodeIgniter defaults were
|
||||
| chosen for the least overlap with these conventions, while still
|
||||
| leaving room for others to be defined in future versions and user
|
||||
| applications.
|
||||
|
|
||||
| The three main conventions used for determining exit status codes
|
||||
| are as follows:
|
||||
|
|
||||
| Standard C/C++ Library (stdlibc):
|
||||
| http://www.gnu.org/software/libc/manual/html_node/Exit-Status.html
|
||||
| (This link also contains other GNU-specific conventions)
|
||||
| BSD sysexits.h:
|
||||
| http://www.gsp.com/cgi-bin/man.cgi?section=3&topic=sysexits
|
||||
| Bash scripting:
|
||||
| http://tldp.org/LDP/abs/html/exitcodes.html
|
||||
|
|
||||
*/
|
||||
defined('EXIT_SUCCESS') || define('EXIT_SUCCESS', 0); // no errors
|
||||
defined('EXIT_ERROR') || define('EXIT_ERROR', 1); // generic error
|
||||
defined('EXIT_CONFIG') || define('EXIT_CONFIG', 3); // configuration error
|
||||
defined('EXIT_UNKNOWN_FILE') || define('EXIT_UNKNOWN_FILE', 4); // file not found
|
||||
defined('EXIT_UNKNOWN_CLASS') || define('EXIT_UNKNOWN_CLASS', 5); // unknown class
|
||||
defined('EXIT_UNKNOWN_METHOD') || define('EXIT_UNKNOWN_METHOD', 6); // unknown class member
|
||||
defined('EXIT_USER_INPUT') || define('EXIT_USER_INPUT', 7); // invalid user input
|
||||
defined('EXIT_DATABASE') || define('EXIT_DATABASE', 8); // database error
|
||||
defined('EXIT__AUTO_MIN') || define('EXIT__AUTO_MIN', 9); // lowest automatically-assigned error code
|
||||
defined('EXIT__AUTO_MAX') || define('EXIT__AUTO_MAX', 125); // highest automatically-assigned error code
|
||||
216
app/Config/ContentSecurityPolicy.php
Normal file
216
app/Config/ContentSecurityPolicy.php
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* Stores the default settings for the ContentSecurityPolicy, if you
|
||||
* choose to use it. The values here will be read in and set as defaults
|
||||
* for the site. If needed, they can be overridden on a page-by-page basis.
|
||||
*
|
||||
* Suggested reference for explanations:
|
||||
*
|
||||
* @see https://www.html5rocks.com/en/tutorials/security/content-security-policy/
|
||||
*/
|
||||
class ContentSecurityPolicy extends BaseConfig
|
||||
{
|
||||
// -------------------------------------------------------------------------
|
||||
// Broadbrush CSP management
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Default CSP report context
|
||||
*/
|
||||
public bool $reportOnly = false;
|
||||
|
||||
/**
|
||||
* Specifies a URL where a browser will send reports
|
||||
* when a content security policy is violated.
|
||||
*/
|
||||
public ?string $reportURI = null;
|
||||
|
||||
/**
|
||||
* Specifies a reporting endpoint to which violation reports ought to be sent.
|
||||
*/
|
||||
public ?string $reportTo = null;
|
||||
|
||||
/**
|
||||
* Instructs user agents to rewrite URL schemes, changing
|
||||
* HTTP to HTTPS. This directive is for websites with
|
||||
* large numbers of old URLs that need to be rewritten.
|
||||
*/
|
||||
public bool $upgradeInsecureRequests = false;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// CSP DIRECTIVES SETTINGS
|
||||
// NOTE: once you set a policy to 'none', it cannot be further restricted
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Will default to `'self'` if not overridden
|
||||
*
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
public $defaultSrc;
|
||||
|
||||
/**
|
||||
* Lists allowed scripts' URLs.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public $scriptSrc = 'self';
|
||||
|
||||
/**
|
||||
* Specifies valid sources for JavaScript <script> elements.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $scriptSrcElem = 'self';
|
||||
|
||||
/**
|
||||
* Specifies valid sources for JavaScript inline event
|
||||
* handlers and JavaScript URLs.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $scriptSrcAttr = 'self';
|
||||
|
||||
/**
|
||||
* Lists allowed stylesheets' URLs.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public $styleSrc = 'self';
|
||||
|
||||
/**
|
||||
* Specifies valid sources for stylesheets <link> elements.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $styleSrcElem = 'self';
|
||||
|
||||
/**
|
||||
* Specifies valid sources for stylesheets inline
|
||||
* style attributes and `<style>` elements.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $styleSrcAttr = 'self';
|
||||
|
||||
/**
|
||||
* Defines the origins from which images can be loaded.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public $imageSrc = 'self';
|
||||
|
||||
/**
|
||||
* Restricts the URLs that can appear in a page's `<base>` element.
|
||||
*
|
||||
* Will default to self if not overridden
|
||||
*
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
public $baseURI;
|
||||
|
||||
/**
|
||||
* Lists the URLs for workers and embedded frame contents
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public $childSrc = 'self';
|
||||
|
||||
/**
|
||||
* Limits the origins that you can connect to (via XHR,
|
||||
* WebSockets, and EventSource).
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public $connectSrc = 'self';
|
||||
|
||||
/**
|
||||
* Specifies the origins that can serve web fonts.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public $fontSrc;
|
||||
|
||||
/**
|
||||
* Lists valid endpoints for submission from `<form>` tags.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public $formAction = 'self';
|
||||
|
||||
/**
|
||||
* Specifies the sources that can embed the current page.
|
||||
* This directive applies to `<frame>`, `<iframe>`, `<embed>`,
|
||||
* and `<applet>` tags. This directive can't be used in
|
||||
* `<meta>` tags and applies only to non-HTML resources.
|
||||
*
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
public $frameAncestors;
|
||||
|
||||
/**
|
||||
* The frame-src directive restricts the URLs which may
|
||||
* be loaded into nested browsing contexts.
|
||||
*
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
public $frameSrc;
|
||||
|
||||
/**
|
||||
* Restricts the origins allowed to deliver video and audio.
|
||||
*
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
public $mediaSrc;
|
||||
|
||||
/**
|
||||
* Allows control over Flash and other plugins.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public $objectSrc = 'self';
|
||||
|
||||
/**
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
public $manifestSrc;
|
||||
|
||||
/**
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $workerSrc = [];
|
||||
|
||||
/**
|
||||
* Limits the kinds of plugins a page may invoke.
|
||||
*
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
public $pluginTypes;
|
||||
|
||||
/**
|
||||
* List of actions allowed.
|
||||
*
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
public $sandbox;
|
||||
|
||||
/**
|
||||
* Nonce placeholder for style tags.
|
||||
*/
|
||||
public string $styleNonceTag = '{csp-style-nonce}';
|
||||
|
||||
/**
|
||||
* Nonce placeholder for script tags.
|
||||
*/
|
||||
public string $scriptNonceTag = '{csp-script-nonce}';
|
||||
|
||||
/**
|
||||
* Replace nonce tag automatically?
|
||||
*/
|
||||
public bool $autoNonce = true;
|
||||
}
|
||||
107
app/Config/Cookie.php
Normal file
107
app/Config/Cookie.php
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use DateTimeInterface;
|
||||
|
||||
class Cookie extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Prefix
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Set a cookie name prefix if you need to avoid collisions.
|
||||
*/
|
||||
public string $prefix = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Expires Timestamp
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Default expires timestamp for cookies. Setting this to `0` will mean the
|
||||
* cookie will not have the `Expires` attribute and will behave as a session
|
||||
* cookie.
|
||||
*
|
||||
* @var DateTimeInterface|int|string
|
||||
*/
|
||||
public $expires = 0;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Path
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Typically will be a forward slash.
|
||||
*/
|
||||
public string $path = '/';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Domain
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Set to `.your-domain.com` for site-wide cookies.
|
||||
*/
|
||||
public string $domain = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Secure
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Cookie will only be set if a secure HTTPS connection exists.
|
||||
*/
|
||||
public bool $secure = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie HTTPOnly
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Cookie will only be accessible via HTTP(S) (no JavaScript).
|
||||
*/
|
||||
public bool $httponly = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie SameSite
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Configure cookie SameSite setting. Allowed values are:
|
||||
* - None
|
||||
* - Lax
|
||||
* - Strict
|
||||
* - ''
|
||||
*
|
||||
* Alternatively, you can use the constant names:
|
||||
* - `Cookie::SAMESITE_NONE`
|
||||
* - `Cookie::SAMESITE_LAX`
|
||||
* - `Cookie::SAMESITE_STRICT`
|
||||
*
|
||||
* Defaults to `Lax` for compatibility with modern browsers. Setting `''`
|
||||
* (empty string) means default SameSite attribute set by browsers (`Lax`)
|
||||
* will be set on cookies. If set to `None`, `$secure` must also be set.
|
||||
*
|
||||
* @var ''|'Lax'|'None'|'Strict'
|
||||
*/
|
||||
public string $samesite = 'Lax';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Cookie Raw
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This flag allows setting a "raw" cookie, i.e., its name and value are
|
||||
* not URL encoded using `rawurlencode()`.
|
||||
*
|
||||
* If this is set to `true`, cookie names should be compliant of RFC 2616's
|
||||
* list of allowed characters.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes
|
||||
* @see https://tools.ietf.org/html/rfc2616#section-2.2
|
||||
*/
|
||||
public bool $raw = false;
|
||||
}
|
||||
105
app/Config/Cors.php
Normal file
105
app/Config/Cors.php
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* Cross-Origin Resource Sharing (CORS) Configuration
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
||||
*/
|
||||
class Cors extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* The default CORS configuration.
|
||||
*
|
||||
* @var array{
|
||||
* allowedOrigins: list<string>,
|
||||
* allowedOriginsPatterns: list<string>,
|
||||
* supportsCredentials: bool,
|
||||
* allowedHeaders: list<string>,
|
||||
* exposedHeaders: list<string>,
|
||||
* allowedMethods: list<string>,
|
||||
* maxAge: int,
|
||||
* }
|
||||
*/
|
||||
public array $default = [
|
||||
/**
|
||||
* Origins for the `Access-Control-Allow-Origin` header.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
*
|
||||
* E.g.:
|
||||
* - ['http://localhost:8080']
|
||||
* - ['https://www.example.com']
|
||||
*/
|
||||
'allowedOrigins' => [],
|
||||
|
||||
/**
|
||||
* Origin regex patterns for the `Access-Control-Allow-Origin` header.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
||||
*
|
||||
* NOTE: A pattern specified here is part of a regular expression. It will
|
||||
* be actually `#\A<pattern>\z#`.
|
||||
*
|
||||
* E.g.:
|
||||
* - ['https://\w+\.example\.com']
|
||||
*/
|
||||
'allowedOriginsPatterns' => [],
|
||||
|
||||
/**
|
||||
* Weather to send the `Access-Control-Allow-Credentials` header.
|
||||
*
|
||||
* The Access-Control-Allow-Credentials response header tells browsers whether
|
||||
* the server allows cross-origin HTTP requests to include credentials.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
|
||||
*/
|
||||
'supportsCredentials' => false,
|
||||
|
||||
/**
|
||||
* Set headers to allow.
|
||||
*
|
||||
* The Access-Control-Allow-Headers response header is used in response to
|
||||
* a preflight request which includes the Access-Control-Request-Headers to
|
||||
* indicate which HTTP headers can be used during the actual request.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
||||
*/
|
||||
'allowedHeaders' => [],
|
||||
|
||||
/**
|
||||
* Set headers to expose.
|
||||
*
|
||||
* The Access-Control-Expose-Headers response header allows a server to
|
||||
* indicate which response headers should be made available to scripts running
|
||||
* in the browser, in response to a cross-origin request.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
|
||||
*/
|
||||
'exposedHeaders' => [],
|
||||
|
||||
/**
|
||||
* Set methods to allow.
|
||||
*
|
||||
* The Access-Control-Allow-Methods response header specifies one or more
|
||||
* methods allowed when accessing a resource in response to a preflight
|
||||
* request.
|
||||
*
|
||||
* E.g.:
|
||||
* - ['GET', 'POST', 'PUT', 'DELETE']
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
||||
*/
|
||||
'allowedMethods' => [],
|
||||
|
||||
/**
|
||||
* Set how many seconds the results of a preflight request can be cached.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
|
||||
*/
|
||||
'maxAge' => 7200,
|
||||
];
|
||||
}
|
||||
204
app/Config/Database.php
Normal file
204
app/Config/Database.php
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Database\Config;
|
||||
|
||||
/**
|
||||
* Database Configuration
|
||||
*/
|
||||
class Database extends Config
|
||||
{
|
||||
/**
|
||||
* The directory that holds the Migrations and Seeds directories.
|
||||
*/
|
||||
public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR;
|
||||
|
||||
/**
|
||||
* Lets you choose which connection group to use if no other is specified.
|
||||
*/
|
||||
public string $defaultGroup = 'default';
|
||||
|
||||
/**
|
||||
* The default database connection.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public array $default = [
|
||||
'DSN' => '',
|
||||
'hostname' => 'localhost',
|
||||
'username' => 'root',
|
||||
'password' => '',
|
||||
'database' => 'hms_ci4_2026',
|
||||
'DBDriver' => 'MySQLi',
|
||||
'DBPrefix' => '',
|
||||
'pConnect' => false,
|
||||
'DBDebug' => true,
|
||||
'charset' => 'utf8mb4',
|
||||
'DBCollat' => 'utf8mb4_general_ci',
|
||||
'swapPre' => '',
|
||||
'encrypt' => false,
|
||||
'compress' => false,
|
||||
'strictOn' => false,
|
||||
'failover' => [],
|
||||
'port' => 3306,
|
||||
'numberNative' => false,
|
||||
'foundRows' => false,
|
||||
'dateFormat' => [
|
||||
'date' => 'Y-m-d',
|
||||
'datetime' => 'Y-m-d H:i:s',
|
||||
'time' => 'H:i:s',
|
||||
],
|
||||
];
|
||||
|
||||
// /**
|
||||
// * Sample database connection for SQLite3.
|
||||
// *
|
||||
// * @var array<string, mixed>
|
||||
// */
|
||||
// public array $default = [
|
||||
// 'database' => 'database.db',
|
||||
// 'DBDriver' => 'SQLite3',
|
||||
// 'DBPrefix' => '',
|
||||
// 'DBDebug' => true,
|
||||
// 'swapPre' => '',
|
||||
// 'failover' => [],
|
||||
// 'foreignKeys' => true,
|
||||
// 'busyTimeout' => 1000,
|
||||
// 'synchronous' => null,
|
||||
// 'dateFormat' => [
|
||||
// 'date' => 'Y-m-d',
|
||||
// 'datetime' => 'Y-m-d H:i:s',
|
||||
// 'time' => 'H:i:s',
|
||||
// ],
|
||||
// ];
|
||||
|
||||
// /**
|
||||
// * Sample database connection for Postgre.
|
||||
// *
|
||||
// * @var array<string, mixed>
|
||||
// */
|
||||
// public array $default = [
|
||||
// 'DSN' => '',
|
||||
// 'hostname' => 'localhost',
|
||||
// 'username' => 'root',
|
||||
// 'password' => 'root',
|
||||
// 'database' => 'ci4',
|
||||
// 'schema' => 'public',
|
||||
// 'DBDriver' => 'Postgre',
|
||||
// 'DBPrefix' => '',
|
||||
// 'pConnect' => false,
|
||||
// 'DBDebug' => true,
|
||||
// 'charset' => 'utf8',
|
||||
// 'swapPre' => '',
|
||||
// 'failover' => [],
|
||||
// 'port' => 5432,
|
||||
// 'dateFormat' => [
|
||||
// 'date' => 'Y-m-d',
|
||||
// 'datetime' => 'Y-m-d H:i:s',
|
||||
// 'time' => 'H:i:s',
|
||||
// ],
|
||||
// ];
|
||||
|
||||
// /**
|
||||
// * Sample database connection for SQLSRV.
|
||||
// *
|
||||
// * @var array<string, mixed>
|
||||
// */
|
||||
// public array $default = [
|
||||
// 'DSN' => '',
|
||||
// 'hostname' => 'localhost',
|
||||
// 'username' => 'root',
|
||||
// 'password' => 'root',
|
||||
// 'database' => 'ci4',
|
||||
// 'schema' => 'dbo',
|
||||
// 'DBDriver' => 'SQLSRV',
|
||||
// 'DBPrefix' => '',
|
||||
// 'pConnect' => false,
|
||||
// 'DBDebug' => true,
|
||||
// 'charset' => 'utf8',
|
||||
// 'swapPre' => '',
|
||||
// 'encrypt' => false,
|
||||
// 'failover' => [],
|
||||
// 'port' => 1433,
|
||||
// 'dateFormat' => [
|
||||
// 'date' => 'Y-m-d',
|
||||
// 'datetime' => 'Y-m-d H:i:s',
|
||||
// 'time' => 'H:i:s',
|
||||
// ],
|
||||
// ];
|
||||
|
||||
// /**
|
||||
// * Sample database connection for OCI8.
|
||||
// *
|
||||
// * You may need the following environment variables:
|
||||
// * NLS_LANG = 'AMERICAN_AMERICA.UTF8'
|
||||
// * NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
|
||||
// * NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
|
||||
// * NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
|
||||
// *
|
||||
// * @var array<string, mixed>
|
||||
// */
|
||||
// public array $default = [
|
||||
// 'DSN' => 'localhost:1521/XEPDB1',
|
||||
// 'username' => 'root',
|
||||
// 'password' => 'root',
|
||||
// 'DBDriver' => 'OCI8',
|
||||
// 'DBPrefix' => '',
|
||||
// 'pConnect' => false,
|
||||
// 'DBDebug' => true,
|
||||
// 'charset' => 'AL32UTF8',
|
||||
// 'swapPre' => '',
|
||||
// 'failover' => [],
|
||||
// 'dateFormat' => [
|
||||
// 'date' => 'Y-m-d',
|
||||
// 'datetime' => 'Y-m-d H:i:s',
|
||||
// 'time' => 'H:i:s',
|
||||
// ],
|
||||
// ];
|
||||
|
||||
/**
|
||||
* This database connection is used when running PHPUnit database tests.
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public array $tests = [
|
||||
'DSN' => '',
|
||||
'hostname' => '127.0.0.1',
|
||||
'username' => '',
|
||||
'password' => '',
|
||||
'database' => ':memory:',
|
||||
'DBDriver' => 'SQLite3',
|
||||
'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS
|
||||
'pConnect' => false,
|
||||
'DBDebug' => true,
|
||||
'charset' => 'utf8',
|
||||
'DBCollat' => '',
|
||||
'swapPre' => '',
|
||||
'encrypt' => false,
|
||||
'compress' => false,
|
||||
'strictOn' => false,
|
||||
'failover' => [],
|
||||
'port' => 3306,
|
||||
'foreignKeys' => true,
|
||||
'busyTimeout' => 1000,
|
||||
'synchronous' => null,
|
||||
'dateFormat' => [
|
||||
'date' => 'Y-m-d',
|
||||
'datetime' => 'Y-m-d H:i:s',
|
||||
'time' => 'H:i:s',
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Ensure that we always set the database group to 'tests' if
|
||||
// we are currently running an automated test suite, so that
|
||||
// we don't overwrite live data on accident.
|
||||
if (ENVIRONMENT === 'testing') {
|
||||
$this->defaultGroup = 'tests';
|
||||
}
|
||||
}
|
||||
}
|
||||
43
app/Config/DocTypes.php
Normal file
43
app/Config/DocTypes.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
class DocTypes
|
||||
{
|
||||
/**
|
||||
* List of valid document types.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $list = [
|
||||
'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
|
||||
'xhtml1-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
|
||||
'xhtml1-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
|
||||
'xhtml1-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
|
||||
'xhtml-basic11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
|
||||
'html5' => '<!DOCTYPE html>',
|
||||
'html4-strict' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
|
||||
'html4-trans' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
|
||||
'html4-frame' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
|
||||
'mathml1' => '<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">',
|
||||
'mathml2' => '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">',
|
||||
'svg10' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">',
|
||||
'svg11' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">',
|
||||
'svg11-basic' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">',
|
||||
'svg11-tiny' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">',
|
||||
'xhtml-math-svg-xh' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
|
||||
'xhtml-math-svg-sh' => '<!DOCTYPE svg:svg PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">',
|
||||
'xhtml-rdfa-1' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">',
|
||||
'xhtml-rdfa-2' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.1//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-2.dtd">',
|
||||
];
|
||||
|
||||
/**
|
||||
* Whether to remove the solidus (`/`) character for void HTML elements (e.g. `<input>`)
|
||||
* for HTML5 compatibility.
|
||||
*
|
||||
* Set to:
|
||||
* `true` - to be HTML5 compatible
|
||||
* `false` - to be XHTML compatible
|
||||
*/
|
||||
public bool $html5 = true;
|
||||
}
|
||||
126
app/Config/Email.php
Normal file
126
app/Config/Email.php
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class Email extends BaseConfig
|
||||
{
|
||||
public string $fromEmail = '';
|
||||
public string $fromName = 'Admin';
|
||||
public string $recipients = '';
|
||||
|
||||
/**
|
||||
* The "user agent"
|
||||
*/
|
||||
public string $userAgent = 'CodeIgniter';
|
||||
|
||||
/**
|
||||
* The mail sending protocol: mail, sendmail, smtp
|
||||
*/
|
||||
public string $protocol = 'mail';
|
||||
|
||||
/**
|
||||
* The server path to Sendmail.
|
||||
*/
|
||||
public string $mailPath = '/usr/sbin/sendmail';
|
||||
|
||||
/**
|
||||
* SMTP Server Hostname
|
||||
*/
|
||||
public string $SMTPHost = '';
|
||||
|
||||
/**
|
||||
* Which SMTP authentication method to use: login, plain
|
||||
*/
|
||||
public string $SMTPAuthMethod = 'login';
|
||||
|
||||
/**
|
||||
* SMTP Username
|
||||
*/
|
||||
public string $SMTPUser = '';
|
||||
|
||||
/**
|
||||
* SMTP Password
|
||||
*/
|
||||
public string $SMTPPass = '';
|
||||
|
||||
/**
|
||||
* SMTP Port
|
||||
*/
|
||||
public int $SMTPPort = 25;
|
||||
|
||||
/**
|
||||
* SMTP Timeout (in seconds)
|
||||
*/
|
||||
public int $SMTPTimeout = 5;
|
||||
|
||||
/**
|
||||
* Enable persistent SMTP connections
|
||||
*/
|
||||
public bool $SMTPKeepAlive = false;
|
||||
|
||||
/**
|
||||
* SMTP Encryption.
|
||||
*
|
||||
* @var string '', 'tls' or 'ssl'. 'tls' will issue a STARTTLS command
|
||||
* to the server. 'ssl' means implicit SSL. Connection on port
|
||||
* 465 should set this to ''.
|
||||
*/
|
||||
public string $SMTPCrypto = 'tls';
|
||||
|
||||
/**
|
||||
* Enable word-wrap
|
||||
*/
|
||||
public bool $wordWrap = true;
|
||||
|
||||
/**
|
||||
* Character count to wrap at
|
||||
*/
|
||||
public int $wrapChars = 76;
|
||||
|
||||
/**
|
||||
* Type of mail, either 'text' or 'html'
|
||||
*/
|
||||
public string $mailType = 'text';
|
||||
|
||||
/**
|
||||
* Character set (utf-8, iso-8859-1, etc.)
|
||||
*/
|
||||
public string $charset = 'UTF-8';
|
||||
|
||||
/**
|
||||
* Whether to validate the email address
|
||||
*/
|
||||
public bool $validate = false;
|
||||
|
||||
/**
|
||||
* Email Priority. 1 = highest. 5 = lowest. 3 = normal
|
||||
*/
|
||||
public int $priority = 3;
|
||||
|
||||
/**
|
||||
* Newline character. (Use “\r\n” to comply with RFC 822)
|
||||
*/
|
||||
public string $CRLF = "\r\n";
|
||||
|
||||
/**
|
||||
* Newline character. (Use “\r\n” to comply with RFC 822)
|
||||
*/
|
||||
public string $newline = "\r\n";
|
||||
|
||||
/**
|
||||
* Enable BCC Batch Mode.
|
||||
*/
|
||||
public bool $BCCBatchMode = false;
|
||||
|
||||
/**
|
||||
* Number of emails in each BCC batch
|
||||
*/
|
||||
public int $BCCBatchSize = 200;
|
||||
|
||||
/**
|
||||
* Enable notify message from server
|
||||
*/
|
||||
public bool $DSN = false;
|
||||
}
|
||||
109
app/Config/Encryption.php
Normal file
109
app/Config/Encryption.php
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* Encryption configuration.
|
||||
*
|
||||
* These are the settings used for encryption, if you don't pass a parameter
|
||||
* array to the encrypter for creation/initialization.
|
||||
*/
|
||||
class Encryption extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Encryption Key Starter
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If you use the Encryption class you must set an encryption key (seed).
|
||||
* You need to ensure it is long enough for the cipher and mode you plan to use.
|
||||
* See the user guide for more info.
|
||||
*/
|
||||
public string $key = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Previous Encryption Keys
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* When rotating encryption keys, add old keys here to maintain ability
|
||||
* to decrypt data encrypted with previous keys. Encryption always uses
|
||||
* the current $key. Decryption tries current key first, then falls back
|
||||
* to previous keys if decryption fails.
|
||||
*
|
||||
* In .env file, use comma-separated string:
|
||||
* encryption.previousKeys = hex2bin:9be8c64fcea509867...,hex2bin:3f5a1d8e9c2b7a4f6...
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $previousKeys = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Encryption Driver to Use
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* One of the supported encryption drivers.
|
||||
*
|
||||
* Available drivers:
|
||||
* - OpenSSL
|
||||
* - Sodium
|
||||
*/
|
||||
public string $driver = 'OpenSSL';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* SodiumHandler's Padding Length in Bytes
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is the number of bytes that will be padded to the plaintext message
|
||||
* before it is encrypted. This value should be greater than zero.
|
||||
*
|
||||
* See the user guide for more information on padding.
|
||||
*/
|
||||
public int $blockSize = 16;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Encryption digest
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'.
|
||||
*/
|
||||
public string $digest = 'SHA512';
|
||||
|
||||
/**
|
||||
* Whether the cipher-text should be raw. If set to false, then it will be base64 encoded.
|
||||
* This setting is only used by OpenSSLHandler.
|
||||
*
|
||||
* Set to false for CI3 Encryption compatibility.
|
||||
*/
|
||||
public bool $rawData = true;
|
||||
|
||||
/**
|
||||
* Encryption key info.
|
||||
* This setting is only used by OpenSSLHandler.
|
||||
*
|
||||
* Set to 'encryption' for CI3 Encryption compatibility.
|
||||
*/
|
||||
public string $encryptKeyInfo = '';
|
||||
|
||||
/**
|
||||
* Authentication key info.
|
||||
* This setting is only used by OpenSSLHandler.
|
||||
*
|
||||
* Set to 'authentication' for CI3 Encryption compatibility.
|
||||
*/
|
||||
public string $authKeyInfo = '';
|
||||
|
||||
/**
|
||||
* Cipher to use.
|
||||
* This setting is only used by OpenSSLHandler.
|
||||
*
|
||||
* Set to 'AES-128-CBC' to decrypt encrypted data that encrypted
|
||||
* by CI3 Encryption default configuration.
|
||||
*/
|
||||
public string $cipher = 'AES-256-CTR';
|
||||
}
|
||||
55
app/Config/Events.php
Normal file
55
app/Config/Events.php
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Events\Events;
|
||||
use CodeIgniter\Exceptions\FrameworkException;
|
||||
use CodeIgniter\HotReloader\HotReloader;
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
* Application Events
|
||||
* --------------------------------------------------------------------
|
||||
* Events allow you to tap into the execution of the program without
|
||||
* modifying or extending core files. This file provides a central
|
||||
* location to define your events, though they can always be added
|
||||
* at run-time, also, if needed.
|
||||
*
|
||||
* You create code that can execute by subscribing to events with
|
||||
* the 'on()' method. This accepts any form of callable, including
|
||||
* Closures, that will be executed when the event is triggered.
|
||||
*
|
||||
* Example:
|
||||
* Events::on('create', [$myInstance, 'myMethod']);
|
||||
*/
|
||||
|
||||
Events::on('pre_system', static function (): void {
|
||||
if (ENVIRONMENT !== 'testing') {
|
||||
if (ini_get('zlib.output_compression')) {
|
||||
throw FrameworkException::forEnabledZlibOutputCompression();
|
||||
}
|
||||
|
||||
while (ob_get_level() > 0) {
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
ob_start(static fn ($buffer) => $buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
* Debug Toolbar Listeners.
|
||||
* --------------------------------------------------------------------
|
||||
* If you delete, they will no longer be collected.
|
||||
*/
|
||||
if (CI_DEBUG && ! is_cli()) {
|
||||
Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect');
|
||||
service('toolbar')->respond();
|
||||
// Hot Reload route - for framework use on the hot reloader.
|
||||
if (ENVIRONMENT === 'development') {
|
||||
service('routes')->get('__hot-reload', static function (): void {
|
||||
(new HotReloader())->run();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
106
app/Config/Exceptions.php
Normal file
106
app/Config/Exceptions.php
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Debug\ExceptionHandler;
|
||||
use CodeIgniter\Debug\ExceptionHandlerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Setup how the exception handler works.
|
||||
*/
|
||||
class Exceptions extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* LOG EXCEPTIONS?
|
||||
* --------------------------------------------------------------------------
|
||||
* If true, then exceptions will be logged
|
||||
* through Services::Log.
|
||||
*
|
||||
* Default: true
|
||||
*/
|
||||
public bool $log = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* DO NOT LOG STATUS CODES
|
||||
* --------------------------------------------------------------------------
|
||||
* Any status codes here will NOT be logged if logging is turned on.
|
||||
* By default, only 404 (Page Not Found) exceptions are ignored.
|
||||
*
|
||||
* @var list<int>
|
||||
*/
|
||||
public array $ignoreCodes = [404];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Error Views Path
|
||||
* --------------------------------------------------------------------------
|
||||
* This is the path to the directory that contains the 'cli' and 'html'
|
||||
* directories that hold the views used to generate errors.
|
||||
*
|
||||
* Default: APPPATH.'Views/errors'
|
||||
*/
|
||||
public string $errorViewPath = APPPATH . 'Views/errors';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* HIDE FROM DEBUG TRACE
|
||||
* --------------------------------------------------------------------------
|
||||
* Any data that you would like to hide from the debug trace.
|
||||
* In order to specify 2 levels, use "/" to separate.
|
||||
* ex. ['server', 'setup/password', 'secret_token']
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $sensitiveDataInTrace = [];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* WHETHER TO THROW AN EXCEPTION ON DEPRECATED ERRORS
|
||||
* --------------------------------------------------------------------------
|
||||
* If set to `true`, DEPRECATED errors are only logged and no exceptions are
|
||||
* thrown. This option also works for user deprecations.
|
||||
*/
|
||||
public bool $logDeprecations = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* LOG LEVEL THRESHOLD FOR DEPRECATIONS
|
||||
* --------------------------------------------------------------------------
|
||||
* If `$logDeprecations` is set to `true`, this sets the log level
|
||||
* to which the deprecation will be logged. This should be one of the log
|
||||
* levels recognized by PSR-3.
|
||||
*
|
||||
* The related `Config\Logger::$threshold` should be adjusted, if needed,
|
||||
* to capture logging the deprecations.
|
||||
*/
|
||||
public string $deprecationLogLevel = LogLevel::WARNING;
|
||||
|
||||
/*
|
||||
* DEFINE THE HANDLERS USED
|
||||
* --------------------------------------------------------------------------
|
||||
* Given the HTTP status code, returns exception handler that
|
||||
* should be used to deal with this error. By default, it will run CodeIgniter's
|
||||
* default handler and display the error information in the expected format
|
||||
* for CLI, HTTP, or AJAX requests, as determined by is_cli() and the expected
|
||||
* response format.
|
||||
*
|
||||
* Custom handlers can be returned if you want to handle one or more specific
|
||||
* error codes yourself like:
|
||||
*
|
||||
* if (in_array($statusCode, [400, 404, 500])) {
|
||||
* return new \App\Libraries\MyExceptionHandler();
|
||||
* }
|
||||
* if ($exception instanceOf PageNotFoundException) {
|
||||
* return new \App\Libraries\MyExceptionHandler();
|
||||
* }
|
||||
*/
|
||||
public function handler(int $statusCode, Throwable $exception): ExceptionHandlerInterface
|
||||
{
|
||||
return new ExceptionHandler($this);
|
||||
}
|
||||
}
|
||||
37
app/Config/Feature.php
Normal file
37
app/Config/Feature.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* Enable/disable backward compatibility breaking features.
|
||||
*/
|
||||
class Feature extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* Use improved new auto routing instead of the legacy version.
|
||||
*/
|
||||
public bool $autoRoutesImproved = true;
|
||||
|
||||
/**
|
||||
* Use filter execution order in 4.4 or before.
|
||||
*/
|
||||
public bool $oldFilterOrder = false;
|
||||
|
||||
/**
|
||||
* The behavior of `limit(0)` in Query Builder.
|
||||
*
|
||||
* If true, `limit(0)` returns all records. (the behavior of 4.4.x or before in version 4.x.)
|
||||
* If false, `limit(0)` returns no records. (the behavior of 3.1.9 or later in version 3.x.)
|
||||
*/
|
||||
public bool $limitZeroAsAll = true;
|
||||
|
||||
/**
|
||||
* Use strict location negotiation.
|
||||
*
|
||||
* By default, the locale is selected based on a loose comparison of the language code (ISO 639-1)
|
||||
* Enabling strict comparison will also consider the region code (ISO 3166-1 alpha-2).
|
||||
*/
|
||||
public bool $strictLocaleNegotiation = false;
|
||||
}
|
||||
110
app/Config/Filters.php
Normal file
110
app/Config/Filters.php
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\Filters as BaseFilters;
|
||||
use CodeIgniter\Filters\Cors;
|
||||
use CodeIgniter\Filters\CSRF;
|
||||
use CodeIgniter\Filters\DebugToolbar;
|
||||
use CodeIgniter\Filters\ForceHTTPS;
|
||||
use CodeIgniter\Filters\Honeypot;
|
||||
use CodeIgniter\Filters\InvalidChars;
|
||||
use CodeIgniter\Filters\PageCache;
|
||||
use CodeIgniter\Filters\PerformanceMetrics;
|
||||
use CodeIgniter\Filters\SecureHeaders;
|
||||
|
||||
class Filters extends BaseFilters
|
||||
{
|
||||
/**
|
||||
* Configures aliases for Filter classes to
|
||||
* make reading things nicer and simpler.
|
||||
*
|
||||
* @var array<string, class-string|list<class-string>>
|
||||
*
|
||||
* [filter_name => classname]
|
||||
* or [filter_name => [classname1, classname2, ...]]
|
||||
*/
|
||||
public array $aliases = [
|
||||
'csrf' => CSRF::class,
|
||||
'toolbar' => DebugToolbar::class,
|
||||
'honeypot' => Honeypot::class,
|
||||
'invalidchars' => InvalidChars::class,
|
||||
'secureheaders' => SecureHeaders::class,
|
||||
'cors' => Cors::class,
|
||||
'forcehttps' => ForceHTTPS::class,
|
||||
'pagecache' => PageCache::class,
|
||||
'performance' => PerformanceMetrics::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* List of special required filters.
|
||||
*
|
||||
* The filters listed here are special. They are applied before and after
|
||||
* other kinds of filters, and always applied even if a route does not exist.
|
||||
*
|
||||
* Filters set by default provide framework functionality. If removed,
|
||||
* those functions will no longer work.
|
||||
*
|
||||
* @see https://codeigniter.com/user_guide/incoming/filters.html#provided-filters
|
||||
*
|
||||
* @var array{before: list<string>, after: list<string>}
|
||||
*/
|
||||
public array $required = [
|
||||
'before' => [
|
||||
'forcehttps', // Force Global Secure Requests
|
||||
'pagecache', // Web Page Caching
|
||||
],
|
||||
'after' => [
|
||||
'pagecache', // Web Page Caching
|
||||
'performance', // Performance Metrics
|
||||
'toolbar', // Debug Toolbar
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* List of filter aliases that are always
|
||||
* applied before and after every request.
|
||||
*
|
||||
* @var array{
|
||||
* before: array<string, array{except: list<string>|string}>|list<string>,
|
||||
* after: array<string, array{except: list<string>|string}>|list<string>
|
||||
* }
|
||||
*/
|
||||
public array $globals = [
|
||||
'before' => [
|
||||
// 'honeypot',
|
||||
// 'csrf',
|
||||
// 'invalidchars',
|
||||
],
|
||||
'after' => [
|
||||
// 'honeypot',
|
||||
// 'secureheaders',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* List of filter aliases that works on a
|
||||
* particular HTTP method (GET, POST, etc.).
|
||||
*
|
||||
* Example:
|
||||
* 'POST' => ['foo', 'bar']
|
||||
*
|
||||
* If you use this, you should disable auto-routing because auto-routing
|
||||
* permits any HTTP method to access a controller. Accessing the controller
|
||||
* with a method you don't expect could bypass the filter.
|
||||
*
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
public array $methods = [];
|
||||
|
||||
/**
|
||||
* List of filter aliases that should run on any
|
||||
* before or after URI patterns.
|
||||
*
|
||||
* Example:
|
||||
* 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
public array $filters = [];
|
||||
}
|
||||
12
app/Config/ForeignCharacters.php
Normal file
12
app/Config/ForeignCharacters.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\ForeignCharacters as BaseForeignCharacters;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*/
|
||||
class ForeignCharacters extends BaseForeignCharacters
|
||||
{
|
||||
}
|
||||
73
app/Config/Format.php
Normal file
73
app/Config/Format.php
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Format\JSONFormatter;
|
||||
use CodeIgniter\Format\XMLFormatter;
|
||||
|
||||
class Format extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Available Response Formats
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* When you perform content negotiation with the request, these are the
|
||||
* available formats that your application supports. This is currently
|
||||
* only used with the API\ResponseTrait. A valid Formatter must exist
|
||||
* for the specified format.
|
||||
*
|
||||
* These formats are only checked when the data passed to the respond()
|
||||
* method is an array.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $supportedResponseFormats = [
|
||||
'application/json',
|
||||
'application/xml', // machine-readable XML
|
||||
'text/xml', // human-readable XML
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Formatters
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Lists the class to use to format responses with of a particular type.
|
||||
* For each mime type, list the class that should be used. Formatters
|
||||
* can be retrieved through the getFormatter() method.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $formatters = [
|
||||
'application/json' => JSONFormatter::class,
|
||||
'application/xml' => XMLFormatter::class,
|
||||
'text/xml' => XMLFormatter::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Formatters Options
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Additional Options to adjust default formatters behaviour.
|
||||
* For each mime type, list the additional options that should be used.
|
||||
*
|
||||
* @var array<string, int>
|
||||
*/
|
||||
public array $formatterOptions = [
|
||||
'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
|
||||
'application/xml' => 0,
|
||||
'text/xml' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Maximum depth for JSON encoding.
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This value determines how deep the JSON encoder will traverse nested structures.
|
||||
*/
|
||||
public int $jsonEncodeDepth = 512;
|
||||
}
|
||||
44
app/Config/Generators.php
Normal file
44
app/Config/Generators.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class Generators extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Generator Commands' Views
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This array defines the mapping of generator commands to the view files
|
||||
* they are using. If you need to customize them for your own, copy these
|
||||
* view files in your own folder and indicate the location here.
|
||||
*
|
||||
* You will notice that the views have special placeholders enclosed in
|
||||
* curly braces `{...}`. These placeholders are used internally by the
|
||||
* generator commands in processing replacements, thus you are warned
|
||||
* not to delete them or modify the names. If you will do so, you may
|
||||
* end up disrupting the scaffolding process and throw errors.
|
||||
*
|
||||
* YOU HAVE BEEN WARNED!
|
||||
*
|
||||
* @var array<string, array<string, string>|string>
|
||||
*/
|
||||
public array $views = [
|
||||
'make:cell' => [
|
||||
'class' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php',
|
||||
'view' => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php',
|
||||
],
|
||||
'make:command' => 'CodeIgniter\Commands\Generators\Views\command.tpl.php',
|
||||
'make:config' => 'CodeIgniter\Commands\Generators\Views\config.tpl.php',
|
||||
'make:controller' => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php',
|
||||
'make:entity' => 'CodeIgniter\Commands\Generators\Views\entity.tpl.php',
|
||||
'make:filter' => 'CodeIgniter\Commands\Generators\Views\filter.tpl.php',
|
||||
'make:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
|
||||
'make:model' => 'CodeIgniter\Commands\Generators\Views\model.tpl.php',
|
||||
'make:seeder' => 'CodeIgniter\Commands\Generators\Views\seeder.tpl.php',
|
||||
'make:validation' => 'CodeIgniter\Commands\Generators\Views\validation.tpl.php',
|
||||
'session:migration' => 'CodeIgniter\Commands\Generators\Views\migration.tpl.php',
|
||||
];
|
||||
}
|
||||
42
app/Config/Honeypot.php
Normal file
42
app/Config/Honeypot.php
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class Honeypot extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* Makes Honeypot visible or not to human
|
||||
*/
|
||||
public bool $hidden = true;
|
||||
|
||||
/**
|
||||
* Honeypot Label Content
|
||||
*/
|
||||
public string $label = 'Fill This Field';
|
||||
|
||||
/**
|
||||
* Honeypot Field Name
|
||||
*/
|
||||
public string $name = 'honeypot';
|
||||
|
||||
/**
|
||||
* Honeypot HTML Template
|
||||
*/
|
||||
public string $template = '<label>{label}</label><input type="text" name="{name}" value="">';
|
||||
|
||||
/**
|
||||
* Honeypot container
|
||||
*
|
||||
* If you enabled CSP, you can remove `style="display:none"`.
|
||||
*/
|
||||
public string $container = '<div style="display:none">{template}</div>';
|
||||
|
||||
/**
|
||||
* The id attribute for Honeypot container tag
|
||||
*
|
||||
* Used when CSP is enabled.
|
||||
*/
|
||||
public string $containerId = 'hpc';
|
||||
}
|
||||
40
app/Config/Hostnames.php
Normal file
40
app/Config/Hostnames.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
class Hostnames
|
||||
{
|
||||
// List of known two-part TLDs for subdomain extraction
|
||||
public const TWO_PART_TLDS = [
|
||||
'co.uk', 'org.uk', 'gov.uk', 'ac.uk', 'sch.uk', 'ltd.uk', 'plc.uk',
|
||||
'com.au', 'net.au', 'org.au', 'edu.au', 'gov.au', 'asn.au', 'id.au',
|
||||
'co.jp', 'ac.jp', 'go.jp', 'or.jp', 'ne.jp', 'gr.jp',
|
||||
'co.nz', 'org.nz', 'govt.nz', 'ac.nz', 'net.nz', 'geek.nz', 'maori.nz', 'school.nz',
|
||||
'co.in', 'net.in', 'org.in', 'ind.in', 'ac.in', 'gov.in', 'res.in',
|
||||
'com.cn', 'net.cn', 'org.cn', 'gov.cn', 'edu.cn',
|
||||
'com.sg', 'net.sg', 'org.sg', 'gov.sg', 'edu.sg', 'per.sg',
|
||||
'co.za', 'org.za', 'gov.za', 'ac.za', 'net.za',
|
||||
'co.kr', 'or.kr', 'go.kr', 'ac.kr', 'ne.kr', 'pe.kr',
|
||||
'co.th', 'or.th', 'go.th', 'ac.th', 'net.th', 'in.th',
|
||||
'com.my', 'net.my', 'org.my', 'edu.my', 'gov.my', 'mil.my', 'name.my',
|
||||
'com.mx', 'org.mx', 'net.mx', 'edu.mx', 'gob.mx',
|
||||
'com.br', 'net.br', 'org.br', 'gov.br', 'edu.br', 'art.br', 'eng.br',
|
||||
'co.il', 'org.il', 'ac.il', 'gov.il', 'net.il', 'muni.il',
|
||||
'co.id', 'or.id', 'ac.id', 'go.id', 'net.id', 'web.id', 'my.id',
|
||||
'com.hk', 'edu.hk', 'gov.hk', 'idv.hk', 'net.hk', 'org.hk',
|
||||
'com.tw', 'net.tw', 'org.tw', 'edu.tw', 'gov.tw', 'idv.tw',
|
||||
'com.sa', 'net.sa', 'org.sa', 'gov.sa', 'edu.sa', 'sch.sa', 'med.sa',
|
||||
'co.ae', 'net.ae', 'org.ae', 'gov.ae', 'ac.ae', 'sch.ae',
|
||||
'com.tr', 'net.tr', 'org.tr', 'gov.tr', 'edu.tr', 'av.tr', 'gen.tr',
|
||||
'co.ke', 'or.ke', 'go.ke', 'ac.ke', 'sc.ke', 'me.ke', 'mobi.ke', 'info.ke',
|
||||
'com.ng', 'org.ng', 'gov.ng', 'edu.ng', 'net.ng', 'sch.ng', 'name.ng',
|
||||
'com.pk', 'net.pk', 'org.pk', 'gov.pk', 'edu.pk', 'fam.pk',
|
||||
'com.eg', 'edu.eg', 'gov.eg', 'org.eg', 'net.eg',
|
||||
'com.cy', 'net.cy', 'org.cy', 'gov.cy', 'ac.cy',
|
||||
'com.lk', 'org.lk', 'edu.lk', 'gov.lk', 'net.lk', 'int.lk',
|
||||
'com.bd', 'net.bd', 'org.bd', 'ac.bd', 'gov.bd', 'mil.bd',
|
||||
'com.ar', 'net.ar', 'org.ar', 'gov.ar', 'edu.ar', 'mil.ar',
|
||||
'gob.cl', 'com.pl', 'net.pl', 'org.pl', 'gov.pl', 'edu.pl',
|
||||
'co.ir', 'ac.ir', 'org.ir', 'id.ir', 'gov.ir', 'sch.ir', 'net.ir',
|
||||
];
|
||||
}
|
||||
33
app/Config/Images.php
Normal file
33
app/Config/Images.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Images\Handlers\GDHandler;
|
||||
use CodeIgniter\Images\Handlers\ImageMagickHandler;
|
||||
|
||||
class Images extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* Default handler used if no other handler is specified.
|
||||
*/
|
||||
public string $defaultHandler = 'gd';
|
||||
|
||||
/**
|
||||
* The path to the image library.
|
||||
* Required for ImageMagick, GraphicsMagick, or NetPBM.
|
||||
*
|
||||
* @deprecated 4.7.0 No longer used.
|
||||
*/
|
||||
public string $libraryPath = '/usr/local/bin/convert';
|
||||
|
||||
/**
|
||||
* The available handler classes.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $handlers = [
|
||||
'gd' => GDHandler::class,
|
||||
'imagick' => ImageMagickHandler::class,
|
||||
];
|
||||
}
|
||||
63
app/Config/Kint.php
Normal file
63
app/Config/Kint.php
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use Kint\Parser\ConstructablePluginInterface;
|
||||
use Kint\Renderer\Rich\TabPluginInterface;
|
||||
use Kint\Renderer\Rich\ValuePluginInterface;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Kint
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* We use Kint's `RichRenderer` and `CLIRenderer`. This area contains options
|
||||
* that you can set to customize how Kint works for you.
|
||||
*
|
||||
* @see https://kint-php.github.io/kint/ for details on these settings.
|
||||
*/
|
||||
class Kint
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var list<class-string<ConstructablePluginInterface>|ConstructablePluginInterface>|null
|
||||
*/
|
||||
public $plugins;
|
||||
|
||||
public int $maxDepth = 6;
|
||||
public bool $displayCalledFrom = true;
|
||||
public bool $expanded = false;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| RichRenderer Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
public string $richTheme = 'aante-light.css';
|
||||
public bool $richFolder = false;
|
||||
|
||||
/**
|
||||
* @var array<string, class-string<ValuePluginInterface>>|null
|
||||
*/
|
||||
public $richObjectPlugins;
|
||||
|
||||
/**
|
||||
* @var array<string, class-string<TabPluginInterface>>|null
|
||||
*/
|
||||
public $richTabPlugins;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| CLI Settings
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
public bool $cliColors = true;
|
||||
public bool $cliForceUTF8 = false;
|
||||
public bool $cliDetectWidth = true;
|
||||
public int $cliMinWidth = 40;
|
||||
}
|
||||
151
app/Config/Logger.php
Normal file
151
app/Config/Logger.php
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Log\Handlers\FileHandler;
|
||||
use CodeIgniter\Log\Handlers\HandlerInterface;
|
||||
|
||||
class Logger extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Error Logging Threshold
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* You can enable error logging by setting a threshold over zero. The
|
||||
* threshold determines what gets logged. Any values below or equal to the
|
||||
* threshold will be logged.
|
||||
*
|
||||
* Threshold options are:
|
||||
*
|
||||
* - 0 = Disables logging, Error logging TURNED OFF
|
||||
* - 1 = Emergency Messages - System is unusable
|
||||
* - 2 = Alert Messages - Action Must Be Taken Immediately
|
||||
* - 3 = Critical Messages - Application component unavailable, unexpected exception.
|
||||
* - 4 = Runtime Errors - Don't need immediate action, but should be monitored.
|
||||
* - 5 = Warnings - Exceptional occurrences that are not errors.
|
||||
* - 6 = Notices - Normal but significant events.
|
||||
* - 7 = Info - Interesting events, like user logging in, etc.
|
||||
* - 8 = Debug - Detailed debug information.
|
||||
* - 9 = All Messages
|
||||
*
|
||||
* You can also pass an array with threshold levels to show individual error types
|
||||
*
|
||||
* array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages
|
||||
*
|
||||
* For a live site you'll usually enable Critical or higher (3) to be logged otherwise
|
||||
* your log files will fill up very fast.
|
||||
*
|
||||
* @var int|list<int>
|
||||
*/
|
||||
public $threshold = (ENVIRONMENT === 'production') ? 4 : 9;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Date Format for Logs
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Each item that is logged has an associated date. You can use PHP date
|
||||
* codes to set your own date formatting
|
||||
*/
|
||||
public string $dateFormat = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Log Handlers
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The logging system supports multiple actions to be taken when something
|
||||
* is logged. This is done by allowing for multiple Handlers, special classes
|
||||
* designed to write the log to their chosen destinations, whether that is
|
||||
* a file on the getServer, a cloud-based service, or even taking actions such
|
||||
* as emailing the dev team.
|
||||
*
|
||||
* Each handler is defined by the class name used for that handler, and it
|
||||
* MUST implement the `CodeIgniter\Log\Handlers\HandlerInterface` interface.
|
||||
*
|
||||
* The value of each key is an array of configuration items that are sent
|
||||
* to the constructor of each handler. The only required configuration item
|
||||
* is the 'handles' element, which must be an array of integer log levels.
|
||||
* This is most easily handled by using the constants defined in the
|
||||
* `Psr\Log\LogLevel` class.
|
||||
*
|
||||
* Handlers are executed in the order defined in this array, starting with
|
||||
* the handler on top and continuing down.
|
||||
*
|
||||
* @var array<class-string<HandlerInterface>, array<string, int|list<string>|string>>
|
||||
*/
|
||||
public array $handlers = [
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
* File Handler
|
||||
* --------------------------------------------------------------------
|
||||
*/
|
||||
FileHandler::class => [
|
||||
// The log levels that this handler will handle.
|
||||
'handles' => [
|
||||
'critical',
|
||||
'alert',
|
||||
'emergency',
|
||||
'debug',
|
||||
'error',
|
||||
'info',
|
||||
'notice',
|
||||
'warning',
|
||||
],
|
||||
|
||||
/*
|
||||
* The default filename extension for log files.
|
||||
* An extension of 'php' allows for protecting the log files via basic
|
||||
* scripting, when they are to be stored under a publicly accessible directory.
|
||||
*
|
||||
* NOTE: Leaving it blank will default to 'log'.
|
||||
*/
|
||||
'fileExtension' => '',
|
||||
|
||||
/*
|
||||
* The file system permissions to be applied on newly created log files.
|
||||
*
|
||||
* IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal
|
||||
* integer notation (i.e. 0700, 0644, etc.)
|
||||
*/
|
||||
'filePermissions' => 0644,
|
||||
|
||||
/*
|
||||
* Logging Directory Path
|
||||
*
|
||||
* By default, logs are written to WRITEPATH . 'logs/'
|
||||
* Specify a different destination here, if desired.
|
||||
*/
|
||||
'path' => '',
|
||||
],
|
||||
|
||||
/*
|
||||
* The ChromeLoggerHandler requires the use of the Chrome web browser
|
||||
* and the ChromeLogger extension. Uncomment this block to use it.
|
||||
*/
|
||||
// 'CodeIgniter\Log\Handlers\ChromeLoggerHandler' => [
|
||||
// /*
|
||||
// * The log levels that this handler will handle.
|
||||
// */
|
||||
// 'handles' => ['critical', 'alert', 'emergency', 'debug',
|
||||
// 'error', 'info', 'notice', 'warning'],
|
||||
// ],
|
||||
|
||||
/*
|
||||
* The ErrorlogHandler writes the logs to PHP's native `error_log()` function.
|
||||
* Uncomment this block to use it.
|
||||
*/
|
||||
// 'CodeIgniter\Log\Handlers\ErrorlogHandler' => [
|
||||
// /* The log levels this handler can handle. */
|
||||
// 'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'],
|
||||
//
|
||||
// /*
|
||||
// * The message type where the error should go. Can be 0 or 4, or use the
|
||||
// * class constants: `ErrorlogHandler::TYPE_OS` (0) or `ErrorlogHandler::TYPE_SAPI` (4)
|
||||
// */
|
||||
// 'messageType' => 0,
|
||||
// ],
|
||||
];
|
||||
}
|
||||
65
app/Config/Migrations.php
Normal file
65
app/Config/Migrations.php
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class Migrations extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Enable/Disable Migrations
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Migrations are enabled by default.
|
||||
*
|
||||
* You should enable migrations whenever you intend to do a schema migration
|
||||
* and disable it back when you're done.
|
||||
*/
|
||||
public bool $enabled = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Migrations Table
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is the name of the table that will store the current migrations state.
|
||||
* When migrations runs it will store in a database table which migration
|
||||
* files have already been run.
|
||||
*/
|
||||
public string $table = 'migrations';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Timestamp Format
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is the format that will be used when creating new migrations
|
||||
* using the CLI command:
|
||||
* > php spark make:migration
|
||||
*
|
||||
* NOTE: if you set an unsupported format, migration runner will not find
|
||||
* your migration files.
|
||||
*
|
||||
* Supported formats:
|
||||
* - YmdHis_
|
||||
* - Y-m-d-His_
|
||||
* - Y_m_d_His_
|
||||
*/
|
||||
public string $timestampFormat = 'Y-m-d-His_';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Enable/Disable Migration Lock
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Locking is disabled by default.
|
||||
*
|
||||
* When enabled, it will prevent multiple migration processes
|
||||
* from running at the same time by using a lock mechanism.
|
||||
*
|
||||
* This is useful in production environments to avoid conflicts
|
||||
* or race conditions during concurrent deployments.
|
||||
*/
|
||||
public bool $lock = false;
|
||||
}
|
||||
534
app/Config/Mimes.php
Normal file
534
app/Config/Mimes.php
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
/**
|
||||
* This file contains an array of mime types. It is used by the
|
||||
* Upload class to help identify allowed file types.
|
||||
*
|
||||
* When more than one variation for an extension exist (like jpg, jpeg, etc)
|
||||
* the most common one should be first in the array to aid the guess*
|
||||
* methods. The same applies when more than one mime-type exists for a
|
||||
* single extension.
|
||||
*
|
||||
* When working with mime types, please make sure you have the ´fileinfo´
|
||||
* extension enabled to reliably detect the media types.
|
||||
*/
|
||||
class Mimes
|
||||
{
|
||||
/**
|
||||
* Map of extensions to mime types.
|
||||
*
|
||||
* @var array<string, list<string>|string>
|
||||
*/
|
||||
public static array $mimes = [
|
||||
'hqx' => [
|
||||
'application/mac-binhex40',
|
||||
'application/mac-binhex',
|
||||
'application/x-binhex40',
|
||||
'application/x-mac-binhex40',
|
||||
],
|
||||
'cpt' => 'application/mac-compactpro',
|
||||
'csv' => [
|
||||
'text/csv',
|
||||
'text/x-comma-separated-values',
|
||||
'text/comma-separated-values',
|
||||
'application/vnd.ms-excel',
|
||||
'application/x-csv',
|
||||
'text/x-csv',
|
||||
'application/csv',
|
||||
'application/excel',
|
||||
'application/vnd.msexcel',
|
||||
'text/plain',
|
||||
],
|
||||
'bin' => [
|
||||
'application/macbinary',
|
||||
'application/mac-binary',
|
||||
'application/octet-stream',
|
||||
'application/x-binary',
|
||||
'application/x-macbinary',
|
||||
],
|
||||
'dms' => 'application/octet-stream',
|
||||
'lha' => 'application/octet-stream',
|
||||
'lzh' => 'application/octet-stream',
|
||||
'exe' => [
|
||||
'application/octet-stream',
|
||||
'application/vnd.microsoft.portable-executable',
|
||||
'application/x-dosexec',
|
||||
'application/x-msdownload',
|
||||
],
|
||||
'class' => 'application/octet-stream',
|
||||
'psd' => [
|
||||
'application/x-photoshop',
|
||||
'image/vnd.adobe.photoshop',
|
||||
],
|
||||
'so' => 'application/octet-stream',
|
||||
'sea' => 'application/octet-stream',
|
||||
'dll' => 'application/octet-stream',
|
||||
'oda' => 'application/oda',
|
||||
'pdf' => [
|
||||
'application/pdf',
|
||||
'application/force-download',
|
||||
'application/x-download',
|
||||
],
|
||||
'ai' => [
|
||||
'application/pdf',
|
||||
'application/postscript',
|
||||
],
|
||||
'eps' => 'application/postscript',
|
||||
'ps' => 'application/postscript',
|
||||
'smi' => 'application/smil',
|
||||
'smil' => 'application/smil',
|
||||
'mif' => 'application/vnd.mif',
|
||||
'xls' => [
|
||||
'application/vnd.ms-excel',
|
||||
'application/msexcel',
|
||||
'application/x-msexcel',
|
||||
'application/x-ms-excel',
|
||||
'application/x-excel',
|
||||
'application/x-dos_ms_excel',
|
||||
'application/xls',
|
||||
'application/x-xls',
|
||||
'application/excel',
|
||||
'application/download',
|
||||
'application/vnd.ms-office',
|
||||
'application/msword',
|
||||
],
|
||||
'ppt' => [
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/powerpoint',
|
||||
'application/vnd.ms-office',
|
||||
'application/msword',
|
||||
],
|
||||
'pptx' => [
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
],
|
||||
'wbxml' => 'application/wbxml',
|
||||
'wmlc' => 'application/wmlc',
|
||||
'dcr' => 'application/x-director',
|
||||
'dir' => 'application/x-director',
|
||||
'dxr' => 'application/x-director',
|
||||
'dvi' => 'application/x-dvi',
|
||||
'gtar' => 'application/x-gtar',
|
||||
'gz' => 'application/x-gzip',
|
||||
'gzip' => 'application/x-gzip',
|
||||
'php' => [
|
||||
'application/x-php',
|
||||
'application/x-httpd-php',
|
||||
'application/php',
|
||||
'text/php',
|
||||
'text/x-php',
|
||||
'application/x-httpd-php-source',
|
||||
],
|
||||
'php4' => 'application/x-httpd-php',
|
||||
'php3' => 'application/x-httpd-php',
|
||||
'phtml' => 'application/x-httpd-php',
|
||||
'phps' => 'application/x-httpd-php-source',
|
||||
'js' => [
|
||||
'application/x-javascript',
|
||||
'text/plain',
|
||||
],
|
||||
'swf' => 'application/x-shockwave-flash',
|
||||
'sit' => 'application/x-stuffit',
|
||||
'tar' => 'application/x-tar',
|
||||
'tgz' => [
|
||||
'application/x-tar',
|
||||
'application/x-gzip-compressed',
|
||||
],
|
||||
'z' => 'application/x-compress',
|
||||
'xhtml' => 'application/xhtml+xml',
|
||||
'xht' => 'application/xhtml+xml',
|
||||
'zip' => [
|
||||
'application/x-zip',
|
||||
'application/zip',
|
||||
'application/x-zip-compressed',
|
||||
'application/s-compressed',
|
||||
'multipart/x-zip',
|
||||
],
|
||||
'rar' => [
|
||||
'application/vnd.rar',
|
||||
'application/x-rar',
|
||||
'application/rar',
|
||||
'application/x-rar-compressed',
|
||||
],
|
||||
'mid' => 'audio/midi',
|
||||
'midi' => 'audio/midi',
|
||||
'mpga' => 'audio/mpeg',
|
||||
'mp2' => 'audio/mpeg',
|
||||
'mp3' => [
|
||||
'audio/mpeg',
|
||||
'audio/mpg',
|
||||
'audio/mpeg3',
|
||||
'audio/mp3',
|
||||
],
|
||||
'aif' => [
|
||||
'audio/x-aiff',
|
||||
'audio/aiff',
|
||||
],
|
||||
'aiff' => [
|
||||
'audio/x-aiff',
|
||||
'audio/aiff',
|
||||
],
|
||||
'aifc' => 'audio/x-aiff',
|
||||
'ram' => 'audio/x-pn-realaudio',
|
||||
'rm' => 'audio/x-pn-realaudio',
|
||||
'rpm' => 'audio/x-pn-realaudio-plugin',
|
||||
'ra' => 'audio/x-realaudio',
|
||||
'rv' => 'video/vnd.rn-realvideo',
|
||||
'wav' => [
|
||||
'audio/x-wav',
|
||||
'audio/wave',
|
||||
'audio/wav',
|
||||
],
|
||||
'bmp' => [
|
||||
'image/bmp',
|
||||
'image/x-bmp',
|
||||
'image/x-bitmap',
|
||||
'image/x-xbitmap',
|
||||
'image/x-win-bitmap',
|
||||
'image/x-windows-bmp',
|
||||
'image/ms-bmp',
|
||||
'image/x-ms-bmp',
|
||||
'application/bmp',
|
||||
'application/x-bmp',
|
||||
'application/x-win-bitmap',
|
||||
],
|
||||
'gif' => 'image/gif',
|
||||
'jpg' => [
|
||||
'image/jpeg',
|
||||
'image/pjpeg',
|
||||
],
|
||||
'jpeg' => [
|
||||
'image/jpeg',
|
||||
'image/pjpeg',
|
||||
],
|
||||
'jpe' => [
|
||||
'image/jpeg',
|
||||
'image/pjpeg',
|
||||
],
|
||||
'jp2' => [
|
||||
'image/jp2',
|
||||
'video/mj2',
|
||||
'image/jpx',
|
||||
'image/jpm',
|
||||
],
|
||||
'j2k' => [
|
||||
'image/jp2',
|
||||
'video/mj2',
|
||||
'image/jpx',
|
||||
'image/jpm',
|
||||
],
|
||||
'jpf' => [
|
||||
'image/jp2',
|
||||
'video/mj2',
|
||||
'image/jpx',
|
||||
'image/jpm',
|
||||
],
|
||||
'jpg2' => [
|
||||
'image/jp2',
|
||||
'video/mj2',
|
||||
'image/jpx',
|
||||
'image/jpm',
|
||||
],
|
||||
'jpx' => [
|
||||
'image/jp2',
|
||||
'video/mj2',
|
||||
'image/jpx',
|
||||
'image/jpm',
|
||||
],
|
||||
'jpm' => [
|
||||
'image/jp2',
|
||||
'video/mj2',
|
||||
'image/jpx',
|
||||
'image/jpm',
|
||||
],
|
||||
'mj2' => [
|
||||
'image/jp2',
|
||||
'video/mj2',
|
||||
'image/jpx',
|
||||
'image/jpm',
|
||||
],
|
||||
'mjp2' => [
|
||||
'image/jp2',
|
||||
'video/mj2',
|
||||
'image/jpx',
|
||||
'image/jpm',
|
||||
],
|
||||
'png' => [
|
||||
'image/png',
|
||||
'image/x-png',
|
||||
],
|
||||
'webp' => 'image/webp',
|
||||
'tif' => 'image/tiff',
|
||||
'tiff' => 'image/tiff',
|
||||
'css' => [
|
||||
'text/css',
|
||||
'text/plain',
|
||||
],
|
||||
'html' => [
|
||||
'text/html',
|
||||
'text/plain',
|
||||
],
|
||||
'htm' => [
|
||||
'text/html',
|
||||
'text/plain',
|
||||
],
|
||||
'shtml' => [
|
||||
'text/html',
|
||||
'text/plain',
|
||||
],
|
||||
'txt' => 'text/plain',
|
||||
'text' => 'text/plain',
|
||||
'log' => [
|
||||
'text/plain',
|
||||
'text/x-log',
|
||||
],
|
||||
'rtx' => 'text/richtext',
|
||||
'rtf' => 'text/rtf',
|
||||
'xml' => [
|
||||
'application/xml',
|
||||
'text/xml',
|
||||
'text/plain',
|
||||
],
|
||||
'xsl' => [
|
||||
'application/xml',
|
||||
'text/xsl',
|
||||
'text/xml',
|
||||
],
|
||||
'mpeg' => 'video/mpeg',
|
||||
'mpg' => 'video/mpeg',
|
||||
'mpe' => 'video/mpeg',
|
||||
'qt' => 'video/quicktime',
|
||||
'mov' => 'video/quicktime',
|
||||
'avi' => [
|
||||
'video/x-msvideo',
|
||||
'video/msvideo',
|
||||
'video/avi',
|
||||
'application/x-troff-msvideo',
|
||||
],
|
||||
'movie' => 'video/x-sgi-movie',
|
||||
'doc' => [
|
||||
'application/msword',
|
||||
'application/vnd.ms-office',
|
||||
],
|
||||
'docx' => [
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/zip',
|
||||
'application/msword',
|
||||
'application/x-zip',
|
||||
],
|
||||
'dot' => [
|
||||
'application/msword',
|
||||
'application/vnd.ms-office',
|
||||
],
|
||||
'dotx' => [
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/zip',
|
||||
'application/msword',
|
||||
],
|
||||
'xlsx' => [
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/zip',
|
||||
'application/vnd.ms-excel',
|
||||
'application/msword',
|
||||
'application/x-zip',
|
||||
],
|
||||
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
|
||||
'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
|
||||
'word' => [
|
||||
'application/msword',
|
||||
'application/octet-stream',
|
||||
],
|
||||
'xl' => 'application/excel',
|
||||
'eml' => 'message/rfc822',
|
||||
'json' => [
|
||||
'application/json',
|
||||
'text/json',
|
||||
],
|
||||
'pem' => [
|
||||
'application/x-x509-user-cert',
|
||||
'application/x-pem-file',
|
||||
'application/octet-stream',
|
||||
],
|
||||
'p10' => [
|
||||
'application/x-pkcs10',
|
||||
'application/pkcs10',
|
||||
],
|
||||
'p12' => 'application/x-pkcs12',
|
||||
'p7a' => 'application/x-pkcs7-signature',
|
||||
'p7c' => [
|
||||
'application/pkcs7-mime',
|
||||
'application/x-pkcs7-mime',
|
||||
],
|
||||
'p7m' => [
|
||||
'application/pkcs7-mime',
|
||||
'application/x-pkcs7-mime',
|
||||
],
|
||||
'p7r' => 'application/x-pkcs7-certreqresp',
|
||||
'p7s' => 'application/pkcs7-signature',
|
||||
'crt' => [
|
||||
'application/x-x509-ca-cert',
|
||||
'application/x-x509-user-cert',
|
||||
'application/pkix-cert',
|
||||
],
|
||||
'crl' => [
|
||||
'application/pkix-crl',
|
||||
'application/pkcs-crl',
|
||||
],
|
||||
'der' => 'application/x-x509-ca-cert',
|
||||
'kdb' => 'application/octet-stream',
|
||||
'pgp' => 'application/pgp',
|
||||
'gpg' => 'application/gpg-keys',
|
||||
'sst' => 'application/octet-stream',
|
||||
'csr' => 'application/octet-stream',
|
||||
'rsa' => 'application/x-pkcs7',
|
||||
'cer' => [
|
||||
'application/pkix-cert',
|
||||
'application/x-x509-ca-cert',
|
||||
],
|
||||
'3g2' => 'video/3gpp2',
|
||||
'3gp' => [
|
||||
'video/3gp',
|
||||
'video/3gpp',
|
||||
],
|
||||
'mp4' => 'video/mp4',
|
||||
'm4a' => 'audio/x-m4a',
|
||||
'f4v' => [
|
||||
'video/mp4',
|
||||
'video/x-f4v',
|
||||
],
|
||||
'flv' => 'video/x-flv',
|
||||
'webm' => 'video/webm',
|
||||
'aac' => 'audio/x-acc',
|
||||
'm4u' => 'application/vnd.mpegurl',
|
||||
'm3u' => 'text/plain',
|
||||
'xspf' => 'application/xspf+xml',
|
||||
'vlc' => 'application/videolan',
|
||||
'wmv' => [
|
||||
'video/x-ms-wmv',
|
||||
'video/x-ms-asf',
|
||||
],
|
||||
'au' => 'audio/x-au',
|
||||
'ac3' => 'audio/ac3',
|
||||
'flac' => 'audio/x-flac',
|
||||
'ogg' => [
|
||||
'audio/ogg',
|
||||
'video/ogg',
|
||||
'application/ogg',
|
||||
],
|
||||
'kmz' => [
|
||||
'application/vnd.google-earth.kmz',
|
||||
'application/zip',
|
||||
'application/x-zip',
|
||||
],
|
||||
'kml' => [
|
||||
'application/vnd.google-earth.kml+xml',
|
||||
'application/xml',
|
||||
'text/xml',
|
||||
],
|
||||
'ics' => 'text/calendar',
|
||||
'ical' => 'text/calendar',
|
||||
'zsh' => 'text/x-scriptzsh',
|
||||
'7zip' => [
|
||||
'application/x-compressed',
|
||||
'application/x-zip-compressed',
|
||||
'application/zip',
|
||||
'multipart/x-zip',
|
||||
],
|
||||
'cdr' => [
|
||||
'application/cdr',
|
||||
'application/coreldraw',
|
||||
'application/x-cdr',
|
||||
'application/x-coreldraw',
|
||||
'image/cdr',
|
||||
'image/x-cdr',
|
||||
'zz-application/zz-winassoc-cdr',
|
||||
],
|
||||
'wma' => [
|
||||
'audio/x-ms-wma',
|
||||
'video/x-ms-asf',
|
||||
],
|
||||
'jar' => [
|
||||
'application/java-archive',
|
||||
'application/x-java-application',
|
||||
'application/x-jar',
|
||||
'application/x-compressed',
|
||||
],
|
||||
'svg' => [
|
||||
'image/svg+xml',
|
||||
'image/svg',
|
||||
'application/xml',
|
||||
'text/xml',
|
||||
],
|
||||
'vcf' => 'text/x-vcard',
|
||||
'srt' => [
|
||||
'text/srt',
|
||||
'text/plain',
|
||||
],
|
||||
'vtt' => [
|
||||
'text/vtt',
|
||||
'text/plain',
|
||||
],
|
||||
'ico' => [
|
||||
'image/x-icon',
|
||||
'image/x-ico',
|
||||
'image/vnd.microsoft.icon',
|
||||
],
|
||||
'stl' => [
|
||||
'application/sla',
|
||||
'application/vnd.ms-pki.stl',
|
||||
'application/x-navistyle',
|
||||
'model/stl',
|
||||
'application/octet-stream',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Attempts to determine the best mime type for the given file extension.
|
||||
*
|
||||
* @return string|null The mime type found, or none if unable to determine.
|
||||
*/
|
||||
public static function guessTypeFromExtension(string $extension)
|
||||
{
|
||||
$extension = trim(strtolower($extension), '. ');
|
||||
|
||||
if (! array_key_exists($extension, static::$mimes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return is_array(static::$mimes[$extension]) ? static::$mimes[$extension][0] : static::$mimes[$extension];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to determine the best file extension for a given mime type.
|
||||
*
|
||||
* @param string|null $proposedExtension - default extension (in case there is more than one with the same mime type)
|
||||
*
|
||||
* @return string|null The extension determined, or null if unable to match.
|
||||
*/
|
||||
public static function guessExtensionFromType(string $type, ?string $proposedExtension = null)
|
||||
{
|
||||
$type = trim(strtolower($type), '. ');
|
||||
|
||||
$proposedExtension = trim(strtolower($proposedExtension ?? ''));
|
||||
|
||||
if (
|
||||
$proposedExtension !== ''
|
||||
&& array_key_exists($proposedExtension, static::$mimes)
|
||||
&& in_array($type, (array) static::$mimes[$proposedExtension], true)
|
||||
) {
|
||||
// The detected mime type matches with the proposed extension.
|
||||
return $proposedExtension;
|
||||
}
|
||||
|
||||
// Reverse check the mime type list if no extension was proposed.
|
||||
// This search is order sensitive!
|
||||
foreach (static::$mimes as $ext => $types) {
|
||||
if (in_array($type, (array) $types, true)) {
|
||||
return $ext;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
82
app/Config/Modules.php
Normal file
82
app/Config/Modules.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Modules\Modules as BaseModules;
|
||||
|
||||
/**
|
||||
* Modules Configuration.
|
||||
*
|
||||
* NOTE: This class is required prior to Autoloader instantiation,
|
||||
* and does not extend BaseConfig.
|
||||
*/
|
||||
class Modules extends BaseModules
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Enable Auto-Discovery?
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If true, then auto-discovery will happen across all elements listed in
|
||||
* $aliases below. If false, no auto-discovery will happen at all,
|
||||
* giving a slight performance boost.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $enabled = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Enable Auto-Discovery Within Composer Packages?
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If true, then auto-discovery will happen across all namespaces loaded
|
||||
* by Composer, as well as the namespaces configured locally.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $discoverInComposer = true;
|
||||
|
||||
/**
|
||||
* The Composer package list for Auto-Discovery
|
||||
* This setting is optional.
|
||||
*
|
||||
* E.g.:
|
||||
* [
|
||||
* 'only' => [
|
||||
* // List up all packages to auto-discover
|
||||
* 'codeigniter4/shield',
|
||||
* ],
|
||||
* ]
|
||||
* or
|
||||
* [
|
||||
* 'exclude' => [
|
||||
* // List up packages to exclude.
|
||||
* 'pestphp/pest',
|
||||
* ],
|
||||
* ]
|
||||
*
|
||||
* @var array{only?: list<string>, exclude?: list<string>}
|
||||
*/
|
||||
public $composerPackages = [];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Auto-Discovery Rules
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Aliases list of all discovery classes that will be active and used during
|
||||
* the current application request.
|
||||
*
|
||||
* If it is not listed, only the base application elements will be used.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public $aliases = [
|
||||
'events',
|
||||
'filters',
|
||||
'registrars',
|
||||
'routes',
|
||||
'services',
|
||||
];
|
||||
}
|
||||
32
app/Config/Optimize.php
Normal file
32
app/Config/Optimize.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
/**
|
||||
* Optimization Configuration.
|
||||
*
|
||||
* NOTE: This class does not extend BaseConfig for performance reasons.
|
||||
* So you cannot replace the property values with Environment Variables.
|
||||
*
|
||||
* WARNING: Do not use these options when running the app in the Worker Mode.
|
||||
*/
|
||||
class Optimize
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Config Caching
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* @see https://codeigniter.com/user_guide/concepts/factories.html#config-caching
|
||||
*/
|
||||
public bool $configCacheEnabled = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Config Caching
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* @see https://codeigniter.com/user_guide/concepts/autoloader.html#file-locator-caching
|
||||
*/
|
||||
public bool $locatorCacheEnabled = false;
|
||||
}
|
||||
37
app/Config/Pager.php
Normal file
37
app/Config/Pager.php
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class Pager extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Templates
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Pagination links are rendered out using views to configure their
|
||||
* appearance. This array contains aliases and the view names to
|
||||
* use when rendering the links.
|
||||
*
|
||||
* Within each view, the Pager object will be available as $pager,
|
||||
* and the desired group as $pagerGroup;
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $templates = [
|
||||
'default_full' => 'CodeIgniter\Pager\Views\default_full',
|
||||
'default_simple' => 'CodeIgniter\Pager\Views\default_simple',
|
||||
'default_head' => 'CodeIgniter\Pager\Views\default_head',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Items Per Page
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The default number of results shown in a single page.
|
||||
*/
|
||||
public int $perPage = 20;
|
||||
}
|
||||
78
app/Config/Paths.php
Normal file
78
app/Config/Paths.php
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
/**
|
||||
* Paths
|
||||
*
|
||||
* Holds the paths that are used by the system to
|
||||
* locate the main directories, app, system, etc.
|
||||
*
|
||||
* Modifying these allows you to restructure your application,
|
||||
* share a system folder between multiple applications, and more.
|
||||
*
|
||||
* All paths are relative to the project's root folder.
|
||||
*
|
||||
* NOTE: This class is required prior to Autoloader instantiation,
|
||||
* and does not extend BaseConfig.
|
||||
*/
|
||||
class Paths
|
||||
{
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* SYSTEM FOLDER NAME
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* This must contain the name of your "system" folder. Include
|
||||
* the path if the folder is not in the same directory as this file.
|
||||
*/
|
||||
public string $systemDirectory = __DIR__ . '/../../vendor/codeigniter4/framework/system';
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* APPLICATION FOLDER NAME
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* If you want this front controller to use a different "app"
|
||||
* folder than the default one you can set its name here. The folder
|
||||
* can also be renamed or relocated anywhere on your server. If
|
||||
* you do, use a full server path.
|
||||
*
|
||||
* @see http://codeigniter.com/user_guide/general/managing_apps.html
|
||||
*/
|
||||
public string $appDirectory = __DIR__ . '/..';
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* WRITABLE DIRECTORY NAME
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* This variable must contain the name of your "writable" directory.
|
||||
* The writable directory allows you to group all directories that
|
||||
* need write permission to a single place that can be tucked away
|
||||
* for maximum security, keeping it out of the app and/or
|
||||
* system directories.
|
||||
*/
|
||||
public string $writableDirectory = __DIR__ . '/../../writable';
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* TESTS DIRECTORY NAME
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* This variable must contain the name of your "tests" directory.
|
||||
*/
|
||||
public string $testsDirectory = __DIR__ . '/../../tests';
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* VIEW DIRECTORY NAME
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* This variable must contain the name of the directory that
|
||||
* contains the view files used by your application. By
|
||||
* default this is in `app/Views`. This value
|
||||
* is used when no value is provided to `Services::renderer()`.
|
||||
*/
|
||||
public string $viewDirectory = __DIR__ . '/../Views';
|
||||
}
|
||||
28
app/Config/Publisher.php
Normal file
28
app/Config/Publisher.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\Publisher as BasePublisher;
|
||||
|
||||
/**
|
||||
* Publisher Configuration
|
||||
*
|
||||
* Defines basic security restrictions for the Publisher class
|
||||
* to prevent abuse by injecting malicious files into a project.
|
||||
*/
|
||||
class Publisher extends BasePublisher
|
||||
{
|
||||
/**
|
||||
* A list of allowed destinations with a (pseudo-)regex
|
||||
* of allowed files for each destination.
|
||||
* Attempts to publish to directories not in this list will
|
||||
* result in a PublisherException. Files that do no fit the
|
||||
* pattern will cause copy/merge to fail.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public $restrictions = [
|
||||
ROOTPATH => '*',
|
||||
FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i',
|
||||
];
|
||||
}
|
||||
811
app/Config/Routes.php
Normal file
811
app/Config/Routes.php
Normal file
|
|
@ -0,0 +1,811 @@
|
|||
<?php
|
||||
|
||||
use CodeIgniter\Router\RouteCollection;
|
||||
|
||||
/**
|
||||
* @var RouteCollection $routes
|
||||
*/
|
||||
$routes->get('/', 'Home::index');
|
||||
$routes->get('dashboard', 'Home::dashboard');
|
||||
$routes->get('my-profile', 'Home::myProfile');
|
||||
$routes->post('my-profile/save', 'Home::myProfileSave');
|
||||
|
||||
// Pharmacy (Medical) - phase 1
|
||||
$routes->get('Medical', 'Medical::index');
|
||||
$routes->get('Medical/search_customer', 'Medical::search_customer');
|
||||
$routes->get('Medical/CounterSaleForm', 'Medical::counter_sale_form');
|
||||
$routes->post('Medical/CounterSaleCreate', 'Medical::counter_sale_create');
|
||||
$routes->match(['get', 'post'], 'Medical/search', 'Medical::search');
|
||||
$routes->get('Medical/get_drug', 'Medical::get_drug');
|
||||
$routes->get('Medical/check_invoice/(:num)/(:num)/(:num)', 'Medical::check_invoice/$1/$2/$3');
|
||||
$routes->get('Medical/Invoice_counter_new/(:num)/(:num)/(:num)', 'Medical::Invoice_counter_new/$1/$2/$3');
|
||||
$routes->get('Medical/invoice_new/(:num)', 'Medical::invoice_new/$1');
|
||||
$routes->get('Medical/invoice_edit/(:num)', 'Medical::invoice_edit/$1');
|
||||
$routes->get('Medical/final_invoice/(:num)', 'Medical::final_invoice/$1');
|
||||
$routes->get('Medical/open_invoice_edit/(:num)', 'Medical::open_invoice_edit/$1');
|
||||
$routes->match(['get', 'post'], 'Medical/edit_invoice_edit/(:num)', 'Medical::edit_invoice_edit/$1');
|
||||
$routes->post('Medical/patient_info', 'Medical::patient_info');
|
||||
$routes->post('Medical/ipd_info', 'Medical::ipd_info');
|
||||
$routes->post('Medical/org_info', 'Medical::org_info');
|
||||
$routes->post('Medical/update_uhid', 'Medical::update_uhid');
|
||||
$routes->post('Medical/update_ipd', 'Medical::update_ipd');
|
||||
$routes->post('Medical/update_org', 'Medical::update_org');
|
||||
$routes->post('Medical/update_invdate', 'Medical::update_invdate');
|
||||
$routes->post('Medical/update_name_phone', 'Medical::update_name_phone');
|
||||
$routes->post('Medical/update_doctor', 'Medical::update_doctor');
|
||||
$routes->post('Medical/update_cr_status_ipd', 'Medical::update_cr_status_ipd');
|
||||
$routes->post('Medical/confirm_payment', 'Medical::confirm_payment');
|
||||
$routes->post('Medical/update_discount', 'Medical::update_discount');
|
||||
$routes->post('Medical/add_item', 'Medical::add_item');
|
||||
$routes->post('Medical/remove_item', 'Medical::remove_item');
|
||||
$routes->post('Medical/update_item_qty', 'Medical::update_item_qty');
|
||||
$routes->post('Medical/add_remove_item', 'Medical::add_remove_item');
|
||||
$routes->post('Medical/go_final', 'Medical::go_final');
|
||||
$routes->match(['get', 'post'], 'Medical/getInvoiceTable', 'Medical::getInvoiceTable');
|
||||
$routes->get('Medical/invoice_print/(:num)', 'Medical::invoice_print/$1');
|
||||
$routes->get('Medical/invoice_print/(:num)/(:num)', 'Medical::invoice_print/$1/$2');
|
||||
$routes->get('Medical/Invoice_Med_Draft', 'Medical::Invoice_Med_Draft');
|
||||
$routes->get('Medical/list_med_inv/(:num)', 'Medical::list_med_inv/$1');
|
||||
$routes->get('Medical/list_med_orginv/(:num)', 'Medical::list_med_orginv/$1');
|
||||
$routes->get('Medical/list_med_orginv/(:num)/(:num)', 'Medical::list_med_orginv/$1/$2');
|
||||
$routes->post('Medical/lock_ipd/(:num)/(:num)', 'Medical::lock_ipd/$1/$2');
|
||||
$routes->get('Medical/med_return/(:num)', 'Medical::med_return/$1');
|
||||
$routes->get('Medical/med_return_new/(:num)', 'Medical::med_return_new/$1');
|
||||
$routes->get('Medical/med_cash_payment/(:num)', 'Medical::med_cash_payment/$1');
|
||||
$routes->post('Medical/group_confirm_payment', 'Medical::group_confirm_payment');
|
||||
$routes->post('Medical/update_group_discount/(:num)', 'Medical::update_group_discount/$1');
|
||||
$routes->get('Medical/ipd_print/(:num)/(:segment)', 'Medical::ipd_print/$1/$2');
|
||||
$routes->get('Medical/list_org_ipd', 'Medical::list_org_ipd');
|
||||
$routes->get('Medical/list_org', 'Medical::list_org');
|
||||
$routes->get('Medical/main_store', 'Medical::main_store');
|
||||
$routes->get('Medical/main_store_link/(:segment)', 'Medical::main_store_placeholder/$1');
|
||||
$routes->get('Medical/SupplierList', 'Medical::supplier_list');
|
||||
$routes->get('Medical/SupplierListSub', 'Medical::supplier_list_sub');
|
||||
$routes->get('Medical/SupplierEdit/(:num)', 'Medical::supplier_edit/$1');
|
||||
$routes->post('Medical/SupplierUpdate', 'Medical::supplier_update');
|
||||
$routes->get('product_master/company_master_list', 'Medical::company_master_list');
|
||||
$routes->get('product_master/CompanyListSub', 'Medical::company_list_sub');
|
||||
$routes->get('product_master/CompanyEdit/(:num)', 'Medical::company_edit/$1');
|
||||
$routes->post('product_master/CompanyUpdate', 'Medical::company_update');
|
||||
$routes->get('Product_master/company_master_list', 'Medical::company_master_list');
|
||||
$routes->get('Product_master/CompanyListSub', 'Medical::company_list_sub');
|
||||
$routes->get('Product_master/CompanyEdit/(:num)', 'Medical::company_edit/$1');
|
||||
$routes->post('Product_master/CompanyUpdate', 'Medical::company_update');
|
||||
$routes->get('product_master/medicine_category', 'Medical::medicine_category');
|
||||
$routes->get('product_master/medicine_category_edit/(:num)', 'Medical::medicine_category_edit/$1');
|
||||
$routes->get('product_master/medicine_category_Sub', 'Medical::medicine_category_sub');
|
||||
$routes->post('product_master/medicine_category_Update', 'Medical::medicine_category_update');
|
||||
$routes->get('Product_master/medicine_category', 'Medical::medicine_category');
|
||||
$routes->get('Product_master/medicine_category_edit/(:num)', 'Medical::medicine_category_edit/$1');
|
||||
$routes->get('Product_master/medicine_category_Sub', 'Medical::medicine_category_sub');
|
||||
$routes->post('Product_master/medicine_category_Update', 'Medical::medicine_category_update');
|
||||
$routes->get('product_master/drug_master_list', 'Medical::drug_master_list');
|
||||
$routes->post('product_master/Product_search', 'Medical::product_search');
|
||||
$routes->get('product_master/Product_edit/(:num)', 'Medical::product_edit/$1');
|
||||
$routes->post('product_master/product_master_update/(:num)', 'Medical::product_master_update/$1');
|
||||
$routes->get('Product_master/drug_master_list', 'Medical::drug_master_list');
|
||||
$routes->post('Product_master/Product_search', 'Medical::product_search');
|
||||
$routes->get('Product_master/Product_edit/(:num)', 'Medical::product_edit/$1');
|
||||
$routes->post('Product_master/product_master_update/(:num)', 'Medical::product_master_update/$1');
|
||||
$routes->get('Medical/Purchase', 'Medical::purchase');
|
||||
$routes->post('Medical/PurchaseInvoice', 'Medical::purchase_invoice');
|
||||
$routes->get('Medical/PurchaseNew', 'Medical::purchase_new');
|
||||
$routes->post('Medical/CreatePurchase', 'Medical::create_purchase');
|
||||
$routes->get('Medical/PurchaseMasterEdit/(:num)', 'Medical::purchase_master_edit/$1');
|
||||
$routes->post('Medical/UpdatePurchase', 'Medical::update_purchase');
|
||||
$routes->get('Medical/UpdatePurchaseInvoiceStatus/(:num)/(:num)', 'Medical::update_purchase_invoice_status/$1/$2');
|
||||
$routes->post('Medical/purchase_invoice_delete/(:num)', 'Medical::purchase_invoice_delete/$1');
|
||||
$routes->get('Medical/PurchaseInvoiceEdit/(:num)', 'Medical::purchase_invoice_edit/$1');
|
||||
$routes->get('Medical/purchase_invoice_item_list/(:num)', 'Medical::purchase_invoice_item_list/$1');
|
||||
$routes->get('Medical/purchase_invoice_item_list_old/(:num)', 'Medical::purchase_invoice_item_list_old/$1');
|
||||
$routes->post('Medical/purchase_invoice_item_edit/(:num)/(:num)', 'Medical::purchase_invoice_item_edit/$1/$2');
|
||||
$routes->post('Medical/purchase_invoice_item_delete/(:num)/(:num)', 'Medical::purchase_invoice_item_delete/$1/$2');
|
||||
$routes->post('Medical/purchase_update_stock/(:num)', 'Medical::purchase_update_stock/$1');
|
||||
$routes->post('Medical/purchase_update_stock/(:num)/(:num)', 'Medical::purchase_update_stock/$1/$2');
|
||||
$routes->get('Medical/challan_invoice/(:num)', 'Medical::challan_invoice/$1');
|
||||
$routes->post('Medical/challan_item_to_purchase/(:num)/(:num)', 'Medical::challan_item_to_purchase/$1/$2');
|
||||
$routes->post('Medical/challan_item_return/(:num)', 'Medical::challan_item_return/$1');
|
||||
$routes->get('Medical/get_drug_master', 'Medical::get_drug_master');
|
||||
$routes->get('Medical/Purchase_return', 'Medical::purchase_return');
|
||||
$routes->get('Medical/store_stock', 'Medical::store_stock');
|
||||
$routes->post('Medical/store_stock_result', 'Medical::store_stock_result');
|
||||
$routes->get('Medical/stock_result_excel/(:segment)/(:segment)/(:segment)', 'Medical::stock_result_excel/$1/$2/$3');
|
||||
$routes->get('Medical/stock_result_excel_3/(:segment)/(:segment)/(:segment)/(:segment)', 'Medical::stock_result_excel_3/$1/$2/$3/$4');
|
||||
$routes->get('Medical/stock_details', 'Medical::stock_details');
|
||||
$routes->post('Medical/store_stock_result_datewise', 'Medical::store_stock_result_datewise');
|
||||
$routes->get('Medical/store_stock_result_datewise_excel/(:segment)/(:segment)/(:segment)', 'Medical::store_stock_result_datewise_excel/$1/$2/$3');
|
||||
$routes->get('Medical_backpanel/store_stock', 'Medical::store_stock');
|
||||
$routes->get('Medical_backpanel/stock', 'Medical::store_stock');
|
||||
$routes->get('Medical_backpanel/Stock', 'Medical::store_stock');
|
||||
$routes->get('Medical_backpanel/Purchase_return', 'Medical::purchase_return');
|
||||
$routes->get('Medical_backpanel/Report_Med_patient', 'Medical::report_med_patient');
|
||||
$routes->get('Medical_backpanel/drug_patient_distribute/(:segment)/(:segment)/(:segment)/(:segment)', 'Medical::drug_patient_distribute/$1/$2/$3/$4');
|
||||
$routes->get('Medical_backpanel/Print_bill_on_uhid', 'Medical::print_bill_on_uhid');
|
||||
$routes->get('Medical_backpanel/uhid_report/(:segment)/(:segment)', 'Medical::uhid_report/$1/$2');
|
||||
$routes->get('Medical_backpanel/SupplierAccount', 'Medical::supplier_account');
|
||||
$routes->get('Medical_backpanel/invoice_item_log', 'Medical::invoice_item_log');
|
||||
$routes->match(['get', 'post'], 'Medical_backpanel/invoice_item_log_data', 'Medical::invoice_item_log_data');
|
||||
$routes->get('Medical_backpanel/stock_details', 'Medical::stock_details');
|
||||
$routes->get('Medical_backpanel/Expire_stock', 'Medical::expire_stock');
|
||||
$routes->get('Medical_backpanel/Expire_stock_pdf', 'Medical::expire_stock_pdf');
|
||||
$routes->get('Medical_backpanel/stocktransfer', 'Medical::stocktransfer');
|
||||
$routes->get('Medical_backpanel/merge_product', 'Medical::merge_product');
|
||||
$routes->get('Medical_backpanel/Med_old_invoice', 'Medical::Invoice_Med_Draft');
|
||||
$routes->get('Medical_backpanel/Report_IPD_CreditBills', 'Medical::report_ipd_credit_bills');
|
||||
$routes->get('Medical_backpanel/Org_Bills', 'Medical::org_bills');
|
||||
$routes->get('Medical_backpanel/Org_Bills_Report/(:segment)/(:segment)', 'Medical::org_bills_report/$1/$2');
|
||||
$routes->get('Medical_backpanel/Org_Bills_Report/(:segment)/(:segment)/(:num)', 'Medical::org_bills_report/$1/$2/$3');
|
||||
$routes->post('Medical_backpanel/store_Stock_result', 'Medical::store_stock_result');
|
||||
$routes->post('Medical_backpanel/Stock_qty_result', 'Medical::store_stock_result');
|
||||
$routes->post('Medical_backpanel/store_Stock_result_datewise', 'Medical::store_stock_result_datewise');
|
||||
$routes->get('Medical_backpanel/store_Stock_result_datewise_excel/(:segment)/(:segment)/(:segment)', 'Medical::store_stock_result_datewise_excel/$1/$2/$3');
|
||||
$routes->get('Medical_backpanel/Stock_result_excel/(:segment)/(:segment)/(:segment)', 'Medical::stock_result_excel/$1/$2/$3');
|
||||
$routes->get('Medical_backpanel/Stock_result_excel_3/(:segment)/(:segment)/(:segment)/(:segment)', 'Medical::stock_result_excel_3/$1/$2/$3/$4');
|
||||
$routes->get('Medical/expire_stock', 'Medical::expire_stock');
|
||||
$routes->get('Medical/expire_stock_pdf', 'Medical::expire_stock_pdf');
|
||||
$routes->get('Medical/stocktransfer', 'Medical::stocktransfer');
|
||||
$routes->get('Medical/merge_product', 'Medical::merge_product');
|
||||
$routes->post('Medical/product_info/(:num)', 'Medical::product_info/$1');
|
||||
$routes->post('Medical/product_merged', 'Medical::product_merged');
|
||||
$routes->post('Medical/ssno_info/(:num)', 'Medical::ssno_info/$1');
|
||||
$routes->post('Medical/ssno_transfer', 'Medical::ssno_transfer');
|
||||
$routes->get('Medical/admin_action_logs/(:segment)', 'Medical::admin_action_logs/$1');
|
||||
$routes->get('Medical_Report/purchase_invoice_report', 'Medical::purchase_invoice_report');
|
||||
$routes->get('Medical_Report/ipd_discharge', 'Medical::ipd_discharge');
|
||||
$routes->get('Medical_Report/Report_6_data/(:segment)', 'Medical::report_6_data/$1');
|
||||
$routes->get('Medical_Report/Report_6_data/(:segment)/(:num)', 'Medical::report_6_data/$1/$2');
|
||||
$routes->get('Medical_Report/Report_daily_med_sale', 'Medical::report_daily_med_sale');
|
||||
$routes->get('Medical_Report/Report_daily_med_sale_data/(:segment)', 'Medical::report_daily_med_sale_data/$1');
|
||||
$routes->get('Medical_Report/Report_daily_med_sale_data/(:segment)/(:num)', 'Medical::report_daily_med_sale_data/$1/$2');
|
||||
$routes->get('Medical_Report/Report_daily_med_sale_doc', 'Medical::report_daily_med_sale_doc');
|
||||
$routes->get('Medical_Report/Report_daily_med_sale_doc_data/(:segment)/(:segment)', 'Medical::report_daily_med_sale_doc_data/$1/$2');
|
||||
$routes->get('Medical_Report/Report_daily_med_sale_doc_data/(:segment)/(:segment)/(:num)', 'Medical::report_daily_med_sale_doc_data/$1/$2/$3');
|
||||
$routes->get('Medical_Report/Report_company_med_sale', 'Medical::report_company_med_sale');
|
||||
$routes->get('Medical_Report/Report_company_med_sale_data/(:segment)/(:num)', 'Medical::report_company_med_sale_data/$1/$2');
|
||||
$routes->get('Medical_Report/Report_company_med_sale_data/(:segment)/(:num)/(:num)', 'Medical::report_company_med_sale_data/$1/$2/$3');
|
||||
$routes->get('Medical_Report/Short_medicine', 'Medical::short_medicine');
|
||||
$routes->get('Medical_Report/Short_medicine_data/(:segment)/(:segment)', 'Medical::short_medicine_data/$1/$2');
|
||||
$routes->get('Medical_Report/Short_medicine_data/(:segment)/(:segment)/(:num)', 'Medical::short_medicine_data/$1/$2/$3');
|
||||
$routes->get('Medical_Report/Report_4', 'Medical::report_4');
|
||||
$routes->get('Medical_Report/Report_4_data/(:segment)', 'Medical::report_4_data/$1');
|
||||
$routes->get('Medical_Report/Report_4_data/(:segment)/(:num)', 'Medical::report_4_data/$1/$2');
|
||||
$routes->get('Medical_Report/Report_IPD_CreditBills', 'Medical::report_ipd_credit_bills');
|
||||
$routes->get('Medical_Report/Report_IPD_Credit_data/(:segment)/(:num)', 'Medical::report_ipd_credit_data/$1/$2');
|
||||
$routes->get('Medical_Report/Report_IPD_Credit_data/(:segment)/(:num)/(:num)', 'Medical::report_ipd_credit_data/$1/$2/$3');
|
||||
$routes->get('Medical_Report/Org_Bills', 'Medical::org_bills');
|
||||
$routes->get('Medical_Report/Org_Bills_Report/(:segment)/(:segment)', 'Medical::org_bills_report/$1/$2');
|
||||
$routes->get('Medical_Report/Org_Bills_Report/(:segment)/(:segment)/(:num)', 'Medical::org_bills_report/$1/$2/$3');
|
||||
$routes->get('Medical_Report/Lost_medicine', 'Medical::master_report/lost-medicine');
|
||||
$routes->get('Medical_Report/Report_2_OPD_Pending', 'Medical::master_report/opd-cash-pending');
|
||||
$routes->get('Medical_Report/Report_2_OPD_Pending_Paid', 'Medical::master_report/opd-old-balance-paid');
|
||||
$routes->get('Medical_Report/Report_5', 'Medical::report_5');
|
||||
$routes->get('Medical_Report/Report_5_data/(:segment)', 'Medical::report_5_data/$1');
|
||||
$routes->get('Medical_Report/Report_5_data/(:segment)/(:num)', 'Medical::report_5_data/$1/$2');
|
||||
$routes->get('Medical_Report/Report_5_HSNdata/(:segment)', 'Medical::report_5_hsndata/$1');
|
||||
$routes->get('Medical_Report/Report_5_HSNdata/(:segment)/(:num)', 'Medical::report_5_hsndata/$1/$2');
|
||||
$routes->get('Medical_Report/Report_3', 'Medical::report_3');
|
||||
$routes->get('Medical_Report/Report_3_data/(:segment)', 'Medical::report_3_data/$1');
|
||||
$routes->get('Medical_Report/Report_3_data/(:segment)/(:num)', 'Medical::report_3_data/$1/$2');
|
||||
$routes->get('Medical_Report/Report_3_GSTR1/(:segment)', 'Medical::report_3_gstr1/$1');
|
||||
$routes->get('Medical_Report/Report_7', 'Medical::master_report/bank-ledger');
|
||||
$routes->get('Medical_Report/Report_gst_1', 'Medical::report_gst_1');
|
||||
$routes->get('Medical_Report/purchase_invoice_data_pdf/(:segment)/(:num)', 'Medical::purchase_invoice_data_pdf/$1/$2');
|
||||
$routes->get('Medical_Report/purchase_invoice_data_pdf/(:segment)/(:num)/(:num)', 'Medical::purchase_invoice_data_pdf/$1/$2/$3');
|
||||
$routes->get('Medical_Report/purchase_invoice_pdf/(:segment)/(:num)', 'Medical::purchase_invoice_pdf/$1/$2');
|
||||
$routes->get('Medical_Report/purchase_invoice_pdf_gst/(:segment)/(:num)', 'Medical::purchase_invoice_pdf_gst/$1/$2');
|
||||
$routes->get('Medical_Report/purchase_invoice_data/(:segment)/(:num)', 'Medical::purchase_invoice_data/$1/$2');
|
||||
$routes->get('Medical_Report/purchase_invoice_data/(:segment)/(:num)/(:num)', 'Medical::purchase_invoice_data/$1/$2/$3');
|
||||
$routes->get('Medical_Report/purchase_gstr2b/(:segment)/(:num)', 'Medical::purchase_gstr2b/$1/$2');
|
||||
$routes->get('Medical_Report/purchase_gstr3b/(:segment)/(:num)', 'Medical::purchase_gstr3b/$1/$2');
|
||||
$routes->get('Medical/supplier_account', 'Medical::supplier_account');
|
||||
$routes->get('Medical/supplier_account_led/(:num)', 'Medical::supplier_account_led/$1');
|
||||
$routes->post('Medical/supplier_account_ledger_data/(:num)', 'Medical::supplier_account_ledger_data/$1');
|
||||
$routes->get('Medical/supplier_account_ledger_pdf/(:num)/(:segment)/(:segment)', 'Medical::supplier_account_ledger_pdf/$1/$2/$3');
|
||||
$routes->get('Medical/supplier_account_add_entry/(:num)', 'Medical::supplier_account_add_entry/$1');
|
||||
$routes->post('Medical/supplier_account_add_entry/(:num)', 'Medical::supplier_account_add_entry/$1');
|
||||
$routes->get('Medical/supplier_account_edit_entry/(:num)', 'Medical::supplier_account_edit_entry/$1');
|
||||
$routes->post('Medical/supplier_account_edit_entry/(:num)', 'Medical::supplier_account_edit_entry/$1');
|
||||
$routes->get('Medical/invoice_item_log', 'Medical::invoice_item_log');
|
||||
$routes->match(['get', 'post'], 'Medical/invoice_item_log_data', 'Medical::invoice_item_log_data');
|
||||
$routes->get('Medical/master', 'Medical::master');
|
||||
$routes->get('Medical/master_report/med-payment-edit', 'Payment_Medical::index');
|
||||
$routes->get('Medical/master_report/(:segment)', 'Medical::master_report/$1');
|
||||
$routes->get('Medical/master_link/(:segment)', 'Medical::master_link/$1');
|
||||
|
||||
$routes->get('Payment_Medical', 'Payment_Medical::index');
|
||||
$routes->get('Payment_Medical/payment_log', 'Payment_Medical::payment_log');
|
||||
$routes->match(['get', 'post'], 'Payment_Medical/payment_log_data', 'Payment_Medical::payment_log_data');
|
||||
$routes->post('Payment_Medical/payment_record', 'Payment_Medical::payment_record');
|
||||
$routes->post('Payment_Medical/change_to_bank', 'Payment_Medical::change_to_bank');
|
||||
$routes->post('Payment_Medical/change_to_cash', 'Payment_Medical::change_to_cash');
|
||||
$routes->post('Payment_Medical/update_amount', 'Payment_Medical::update_amount');
|
||||
$routes->post('Payment_Medical/change_user', 'Payment_Medical::change_user');
|
||||
|
||||
service('auth')->routes($routes);
|
||||
|
||||
|
||||
$routes->group('billing', function($routes) {
|
||||
$routes->get('ipd', 'Billing\\Ipd::index');
|
||||
$routes->get('ipd/current-admission', 'Billing\\Ipd::currentAdmission');
|
||||
$routes->get('ipd/invoices', 'Billing\\Ipd::ipdInvoices');
|
||||
$routes->post('ipd/list', 'Billing\\Ipd::getIpdTable');
|
||||
$routes->get('ipd/panel/(:num)', 'Billing\\Ipd::panel/$1');
|
||||
$routes->get('ipd/panel/(:num)/tab/(:segment)', 'Billing\\Ipd::panelTab/$1/$2');
|
||||
$routes->post('ipd/charge/add/(:num)', 'Billing\\Ipd::addIpdCharge/$1');
|
||||
$routes->post('ipd/charge/update/(:num)', 'Billing\\Ipd::updateIpdCharge/$1');
|
||||
$routes->post('ipd/charge/delete/(:num)', 'Billing\\Ipd::deleteIpdCharge/$1');
|
||||
$routes->post('ipd/charge/package/(:num)', 'Billing\\Ipd::updateIpdChargePackage/$1');
|
||||
$routes->post('ipd/package/add/(:num)', 'Billing\\Ipd::addIpdPackage/$1');
|
||||
$routes->post('ipd/package/update/(:num)', 'Billing\\Ipd::updateIpdPackage/$1');
|
||||
$routes->post('ipd/package/delete/(:num)', 'Billing\\Ipd::deleteIpdPackage/$1');
|
||||
$routes->get('ipd/payment/modal/(:num)', 'Billing\\Ipd::loadPaymentModal/$1');
|
||||
$routes->get('ipd/payment/deduction-modal/(:num)', 'Billing\\Ipd::loadDeductionModal/$1');
|
||||
$routes->get('ipd/payment/tpa-modal/(:num)', 'Billing\\Ipd::loadTpaPaymentModal/$1');
|
||||
$routes->post('ipd/payment/confirm', 'Billing\\Ipd::confirmPayment');
|
||||
$routes->post('ipd/payment/deduct', 'Billing\\Ipd::deductPayment');
|
||||
$routes->post('ipd/payment/tpa', 'Billing\\Ipd::tpaPayment');
|
||||
$routes->get('ipd/payment/receipt/(:num)/(:num)', 'Billing\\Ipd::ipdCashPrintPdf/$1/$2');
|
||||
$routes->get('ipd/cash-balance', 'Billing\\Ipd::cashBalance');
|
||||
$routes->get('ipd/cash-balance/report', 'Billing\\Ipd::cashBalanceReport');
|
||||
$routes->get('ipd/cash-balance/export', 'Billing\\Ipd::cashBalanceExport');
|
||||
$routes->get('patient', 'Patient::index');
|
||||
$routes->get('patient/search_opd', 'Patient::search_opd');
|
||||
$routes->post('patient/create', 'Patient::create');
|
||||
$routes->post('patient/search', 'Patient::search');
|
||||
$routes->post('patient/search_adv', 'Patient::search_adv');
|
||||
$routes->get('patient/person_record/(:num)', 'Patient::person_record/$1');
|
||||
$routes->get('patient/person_record/(:num)/(:num)', 'Patient::person_record/$1/$2');
|
||||
$routes->get('patient/show_cards/(:num)', 'Patient::show_cards/$1');
|
||||
$routes->get('patient/show_cards/(:num)/(:num)', 'Patient::show_cards/$1/$2');
|
||||
$routes->get('patient/show_profile_image/(:num)', 'Patient::show_profile_image/$1');
|
||||
$routes->get('patient/show_profile_image/(:num)/(:num)', 'Patient::show_profile_image/$1/$2');
|
||||
$routes->get('patient/show_profile_opd/(:num)', 'Patient::show_profile_opd/$1');
|
||||
$routes->get('patient/show_profile_opd/(:num)/(:num)', 'Patient::show_profile_opd/$1/$2');
|
||||
$routes->post('patient/save_profile_image/(:num)', 'Patient::save_profile_image/$1');
|
||||
$routes->match(['get', 'post'], 'patient/patient_file_upload/(:num)', 'Patient::patient_file_upload/$1');
|
||||
$routes->get('patient/city', 'Patient::city');
|
||||
$routes->get('patient/get_name', 'Patient::get_name');
|
||||
$routes->post('patient/update', 'Patient::update');
|
||||
$routes->post('patient/update_aadhar', 'Patient::update_aadhar');
|
||||
$routes->post('patient/update_card', 'Patient::update_card');
|
||||
$routes->get('case/newcase/(:num)/(:num)', 'Billing\\CaseMaster::newcase/$1/$2');
|
||||
$routes->get('case/newcase/(:num)/(:num)/(:num)', 'Billing\\CaseMaster::newcase/$1/$2/$3');
|
||||
$routes->get('case/open_case/(:num)', 'Billing\\CaseMaster::open_case/$1');
|
||||
$routes->get('case/open_case/(:num)/(:num)', 'Billing\\CaseMaster::open_case/$1/$2');
|
||||
$routes->post('case/create', 'Billing\\CaseMaster::create');
|
||||
$routes->post('case/update', 'Billing\\CaseMaster::update');
|
||||
$routes->get('case/addPathTest/(:num)', 'Billing\\CaseMaster::addPathTest/$1');
|
||||
$routes->post('case/search', 'Billing\\CaseMaster::search');
|
||||
$routes->get('case/search_all', 'Billing\\CaseMaster::search_all');
|
||||
$routes->get('case/case_invoice/(:segment)', 'Billing\\CaseMaster::case_invoice/$1');
|
||||
$routes->get('case/case_invoice/(:segment)/(:num)/(:num)/(:num)', 'Billing\\CaseMaster::case_invoice/$1/$2/$3/$4');
|
||||
$routes->get('case/case_invoice_ipd/(:num)', 'Billing\\CaseMaster::case_invoice_ipd/$1');
|
||||
$routes->post('case/ORG_info', 'Billing\\CaseMaster::ORG_info');
|
||||
$routes->post('case/update_itemrateqty', 'Billing\\CaseMaster::update_itemrateqty');
|
||||
$routes->post('case/update_status', 'Billing\\CaseMaster::update_status');
|
||||
$routes->post('case/org_contingent_update', 'Billing\\CaseMaster::org_contingent_update');
|
||||
$routes->get('case/case_invoice_print/(:num)', 'Billing\\CaseMaster::case_invoice_print/$1');
|
||||
$routes->post('case/getCaseTable', 'Billing\\CaseMaster::getCaseTable');
|
||||
$routes->get('case/contingent_bill/(:num)', 'Billing\\CaseMaster::contingent_bill/$1');
|
||||
$routes->get('case/contingent_bill/(:num)/(:num)', 'Billing\\CaseMaster::contingent_bill/$1/$2');
|
||||
$routes->get('case/create_contingent_bill/(:num)', 'Billing\\CaseMaster::create_contingent_bill/$1');
|
||||
$routes->post('case/org_confirm_payment', 'Billing\\CaseMaster::org_confirm_payment');
|
||||
$routes->get('case/org_payment_request', 'Billing\\CaseMaster::org_payment_request');
|
||||
$routes->get('case/load_model_box/(:segment)', 'Billing\\CaseMaster::load_model_box/$1');
|
||||
$routes->post('case/payment_request', 'Billing\\CaseMaster::payment_request');
|
||||
$routes->post('case/refund_request', 'Billing\\CaseMaster::refund_request');
|
||||
$routes->get('charges/add/(:num)', 'Billing\\Charges::add/$1');
|
||||
$routes->get('charges/add/(:num)/(:num)', 'Billing\\Charges::add/$1/$2');
|
||||
$routes->get('charges/add/(:num)/(:num)/(:num)', 'Billing\\Charges::add/$1/$2/$3');
|
||||
$routes->get('charges/edit/(:num)', 'Billing\\Charges::edit/$1');
|
||||
$routes->post('charges/list-by-type', 'Billing\\Charges::listByType');
|
||||
$routes->post('charges/item/(:num)', 'Billing\\Charges::item/$1');
|
||||
$routes->post('charges/update-refer', 'Billing\\Charges::updateReferDoc');
|
||||
$routes->post('charges/confirm-payment', 'Billing\\Charges::confirm_payment');
|
||||
$routes->post('charges/cancel-invoice/(:num)', 'Billing\\Charges::cancel_invoice/$1');
|
||||
$routes->post('charges/update-correction', 'Billing\\Charges::update_correction_charges');
|
||||
$routes->get('charges/show/(:num)', 'Billing\\Charges::show/$1');
|
||||
$routes->post('charges/delete', 'Billing\\Charges::delete');
|
||||
$routes->post('charges/update-discount', 'Billing\\Charges::updateDiscount');
|
||||
});
|
||||
|
||||
$routes->get('Opd/addopd/(:num)', 'Opd::addopd/$1');
|
||||
$routes->get('Opd/addopd/(:num)/(:num)', 'Opd::addopd/$1/$2');
|
||||
$routes->get('opd/appointment', 'Opd::appointment');
|
||||
$routes->get('opd/appointment/(:segment)', 'Opd::appointment/$1');
|
||||
$routes->get('Opd/get_appointment_data', 'Opd::get_appointment_data');
|
||||
$routes->get('Opd/get_appointment_data/(:segment)', 'Opd::get_appointment_data/$1');
|
||||
$routes->get('Opd/get_appointment_list/(:num)', 'Opd::get_appointment_list/$1');
|
||||
$routes->get('Opd/get_appointment_list/(:num)/(:segment)', 'Opd::get_appointment_list/$1/$2');
|
||||
$routes->match(['get', 'post'], 'Opd/opd_status/(:num)/(:num)', 'Opd::opd_status/$1/$2');
|
||||
$routes->post('Opd/showfee', 'Opd::showfee');
|
||||
$routes->post('Opd/confirm_opd', 'Opd::confirm_opd');
|
||||
$routes->post('Opd/confirm_payment', 'Opd::confirm_payment');
|
||||
$routes->post('Opd/opd_discount_update/(:num)', 'Opd::opd_discount_update/$1');
|
||||
$routes->match(['get', 'post'], 'Opd/opd_load_doc/(:num)', 'Opd::opd_load_doc/$1');
|
||||
$routes->match(['get', 'post'], 'Opd/opd_file_last_list', 'Opd::opd_file_last_list');
|
||||
$routes->match(['get', 'post'], 'Opd/opd_file_last_list/(:num)', 'Opd::opd_file_last_list/$1');
|
||||
$routes->match(['get', 'post'], 'Opd/save_image/(:num)', 'Opd::save_image/$1');
|
||||
$routes->post('Opd/scan_ai_process_file', 'Opd::scan_ai_process_file');
|
||||
$routes->post('Opd/scan_ai_assist', 'Opd::scan_ai_assist');
|
||||
$routes->match(['get', 'post'], 'Opd/opd_file_hide/(:num)', 'Opd::opd_file_hide/$1');
|
||||
$routes->get('Opd/invoice/(:num)', 'Opd::invoice/$1');
|
||||
$routes->get('Opd/invoice_print/(:num)', 'Opd::invoice_print/$1');
|
||||
$routes->get('Opd/opd_lettre_print/(:num)', 'Opd::opd_lettre_print/$1');
|
||||
$routes->get('Opd/opd_lettre_pdf/(:num)', 'Opd::opd_lettre_pdf/$1');
|
||||
$routes->get('Opd/print_template_builder', 'Opd::print_template_builder');
|
||||
$routes->post('Opd/print_template_save', 'Opd::print_template_save');
|
||||
|
||||
$routes->get('opd_print/invoice_print_pdf/(:num)', 'Opd::invoice_print_pdf/$1');
|
||||
$routes->get('opd_print/opd_PDF_print/(:num)', 'Opd::opd_pdf_print/$1');
|
||||
$routes->get('opd_print/opd_Cont_print/(:num)', 'Opd::opd_cont_print/$1');
|
||||
$routes->get('opd_print/opd_blank_print/(:num)', 'Opd::opd_blank_print/$1');
|
||||
|
||||
$routes->get('Opd_prescription/Prescription/(:num)', 'Opd_prescription::Prescription/$1');
|
||||
$routes->get('Opd_prescription/opd_prescription_print/(:num)/(:num)', 'Opd_prescription::opd_prescription_print/$1/$2');
|
||||
$routes->get('Opd_prescription/opd_prescription_print/(:num)/(:num)/(:num)', 'Opd_prescription::opd_prescription_print/$1/$2/$3');
|
||||
$routes->post('Opd_prescription/opd_prescription_save', 'Opd_prescription::opd_prescription_save');
|
||||
$routes->get('Opd_prescription/fhir_bundle/(:num)', 'Opd_prescription::fhir_bundle/$1');
|
||||
$routes->get('Opd_prescription/fhir_bundle/(:num)/(:num)', 'Opd_prescription::fhir_bundle/$1/$2');
|
||||
$routes->get('Opd_prescription/fhir_bundle_history/(:num)', 'Opd_prescription::fhir_bundle_history/$1');
|
||||
$routes->get('Opd_prescription/fhir_bundle_history/(:num)/(:num)', 'Opd_prescription::fhir_bundle_history/$1/$2');
|
||||
$routes->get('Opd_prescription/complaints_search', 'Opd_prescription::complaints_search');
|
||||
$routes->post('Opd_prescription/complaints_parse', 'Opd_prescription::complaints_parse');
|
||||
$routes->post('Opd_prescription/complaints_ai_draft', 'Opd_prescription::complaints_ai_draft');
|
||||
$routes->post('Opd_prescription/clinical_autotype', 'Opd_prescription::clinical_autotype');
|
||||
$routes->post('Opd_prescription/ai_full_draft', 'Opd_prescription::ai_full_draft');
|
||||
$routes->post('Opd_prescription/local_clinical_assist', 'Opd_prescription::local_clinical_assist');
|
||||
$routes->post('Opd_prescription/section_template_save', 'Opd_prescription::section_template_save');
|
||||
$routes->post('Opd_prescription/section_template_track_usage', 'Opd_prescription::section_template_track_usage');
|
||||
$routes->get('Opd_prescription/section_template_list', 'Opd_prescription::section_template_list');
|
||||
$routes->get('Opd_prescription/section_past_data', 'Opd_prescription::section_past_data');
|
||||
$routes->get('Opd_prescription/template_workspace', 'Opd_prescription::template_workspace');
|
||||
$routes->get('Opd_prescription/clinical_template_monitor', 'Opd_prescription::clinical_template_monitor');
|
||||
$routes->get('Opd_prescription/clinical_template_usage_analytics', 'Opd_prescription::clinical_template_usage_analytics');
|
||||
$routes->get('Opd_prescription/clinical_template_doctors', 'Opd_prescription::clinical_template_doctors');
|
||||
$routes->post('Opd_prescription/clinical_template_update', 'Opd_prescription::clinical_template_update');
|
||||
$routes->get('Opd_prescription/rx_group_panel', 'Opd_prescription::rx_group_panel');
|
||||
$routes->get('Opd_prescription/save_rx_group_list', 'Opd_prescription::save_rx_group_list');
|
||||
$routes->get('Opd_prescription/save_rx_group_list/(:num)', 'Opd_prescription::save_rx_group_list/$1');
|
||||
$routes->get('Opd_prescription/save_rx_group_edit/(:num)', 'Opd_prescription::save_rx_group_edit/$1');
|
||||
$routes->get('Opd_prescription/rx_group_data', 'Opd_prescription::rx_group_data');
|
||||
$routes->get('Opd_prescription/rx_group_get/(:num)', 'Opd_prescription::rx_group_get/$1');
|
||||
$routes->post('Opd_prescription/rx_group_save', 'Opd_prescription::rx_group_save');
|
||||
$routes->post('Opd_prescription/rx_group_apply_to_session', 'Opd_prescription::rx_group_apply_to_session');
|
||||
$routes->get('Opd_prescription/rx_group_medicine/(:num)', 'Opd_prescription::rx_group_medicine/$1');
|
||||
$routes->get('Opd_prescription/rx_group_medicine_list/(:num)', 'Opd_prescription::rx_group_medicine_list/$1');
|
||||
$routes->get('Opd_prescription/rx_group_medicine_get/(:num)', 'Opd_prescription::rx_group_medicine_get/$1');
|
||||
$routes->post('Opd_prescription/rx_group_medicine_save/(:num)', 'Opd_prescription::rx_group_medicine_save/$1');
|
||||
$routes->post('Opd_prescription/rx_group_medicine_remove/(:num)', 'Opd_prescription::rx_group_medicine_remove/$1');
|
||||
$routes->get('Opd_prescription/rx_group_medicine_suggest', 'Opd_prescription::rx_group_medicine_suggest');
|
||||
$routes->get('Opd_prescription/rx_group_generic_suggest', 'Opd_prescription::rx_group_generic_suggest');
|
||||
$routes->get('Opd_prescription/rx_group_dose_masters', 'Opd_prescription::rx_group_dose_masters');
|
||||
|
||||
$routes->get('Opd_prescription/opd_medicince', 'Opd_prescription::opd_medicince');
|
||||
$routes->get('Opd_prescription/opd_medicince_edit/(:num)', 'Opd_prescription::opd_medicince_edit/$1');
|
||||
$routes->get('Opd_prescription/opd_medicince_data', 'Opd_prescription::opd_medicince_data');
|
||||
$routes->get('Opd_prescription/opd_medicince_export', 'Opd_prescription::opd_medicince_export');
|
||||
$routes->get('Opd_prescription/opd_medicince_company_suggest', 'Opd_prescription::opd_medicince_company_suggest');
|
||||
$routes->get('Opd_prescription/opd_medicince_get/(:num)', 'Opd_prescription::opd_medicince_get/$1');
|
||||
$routes->post('Opd_prescription/opd_medicince_save', 'Opd_prescription::opd_medicince_save');
|
||||
$routes->post('Opd_prescription/opd_medicince_ai_details', 'Opd_prescription::opd_medicince_ai_details');
|
||||
$routes->post('Opd_prescription/opd_medicince_remove/(:num)', 'Opd_prescription::opd_medicince_remove/$1');
|
||||
$routes->get('Opd_prescription/opd_medicince_duplicate_report', 'Opd_prescription::opd_medicince_duplicate_report');
|
||||
$routes->post('Opd_prescription/opd_medicince_merge_duplicates', 'Opd_prescription::opd_medicince_merge_duplicates');
|
||||
$routes->post('Opd_prescription/opd_medicince_autofix_duplicates', 'Opd_prescription::opd_medicince_autofix_duplicates');
|
||||
$routes->get('Opd_prescription/opd_advice', 'Opd_prescription::opd_advice');
|
||||
$routes->get('Opd_prescription/opd_advice_edit/(:num)', 'Opd_prescription::opd_advice_edit/$1');
|
||||
$routes->get('Opd_prescription/opd_advice_data', 'Opd_prescription::opd_advice_data');
|
||||
$routes->get('Opd_prescription/opd_advice_get/(:num)', 'Opd_prescription::opd_advice_get/$1');
|
||||
$routes->post('Opd_prescription/opd_advice_save', 'Opd_prescription::opd_advice_save');
|
||||
$routes->post('Opd_prescription/opd_advice_translate_ai', 'Opd_prescription::opd_advice_translate_ai');
|
||||
$routes->post('Opd_prescription/opd_advice_remove/(:num)', 'Opd_prescription::opd_advice_remove/$1');
|
||||
|
||||
$routes->post('Opd_prescription/scan_text_extract', 'Opd_prescription::scan_text_extract');
|
||||
$routes->get('Opd_prescription/patient_scan_history/(:num)', 'Opd_prescription::patient_scan_history/$1');
|
||||
$routes->get('Opd_prescription/advice_search', 'Opd_prescription::advice_search');
|
||||
$routes->get('Opd_prescription/advice_list/(:num)', 'Opd_prescription::advice_list/$1');
|
||||
$routes->get('Opd_prescription/advice_list/(:num)/(:num)', 'Opd_prescription::advice_list/$1/$2');
|
||||
$routes->post('Opd_prescription/advice_add', 'Opd_prescription::advice_add');
|
||||
$routes->post('Opd_prescription/advice_remove/(:num)', 'Opd_prescription::advice_remove/$1');
|
||||
|
||||
$routes->get('Opd_prescription/investigation_search', 'Opd_prescription::investigation_search');
|
||||
$routes->get('Opd_prescription/investigation_shortcuts', 'Opd_prescription::investigation_shortcuts');
|
||||
$routes->get('Opd_prescription/investigation_list/(:num)', 'Opd_prescription::investigation_list/$1');
|
||||
$routes->get('Opd_prescription/investigation_list/(:num)/(:num)', 'Opd_prescription::investigation_list/$1/$2');
|
||||
$routes->post('Opd_prescription/investigation_add', 'Opd_prescription::investigation_add');
|
||||
$routes->post('Opd_prescription/investigation_remove/(:num)', 'Opd_prescription::investigation_remove/$1');
|
||||
|
||||
$routes->get('Opd_prescription/medicine_search', 'Opd_prescription::medicine_search');
|
||||
$routes->get('Opd_prescription/medicine_substitutes', 'Opd_prescription::medicine_substitutes');
|
||||
$routes->get('Opd_prescription/medicine_list/(:num)', 'Opd_prescription::medicine_list/$1');
|
||||
$routes->get('Opd_prescription/vitals_get/(:num)', 'Opd_prescription::vitals_get/$1');
|
||||
$routes->post('Opd_prescription/vitals_save', 'Opd_prescription::vitals_save');
|
||||
$routes->post('Opd_prescription/medicine_add', 'Opd_prescription::medicine_add');
|
||||
$routes->post('Opd_prescription/medicine_favorite_toggle', 'Opd_prescription::medicine_favorite_toggle');
|
||||
$routes->post('Opd_prescription/medicine_update/(:num)', 'Opd_prescription::medicine_update/$1');
|
||||
$routes->post('Opd_prescription/medicine_remove/(:num)', 'Opd_prescription::medicine_remove/$1');
|
||||
|
||||
// Legacy OPD prescription endpoints (old URLs, old data access)
|
||||
$routes->get('Opd_prescription/vital_data/(:num)', 'Opd_prescription::vital_data/$1');
|
||||
$routes->get('Opd_prescription/get_remark/(:num)', 'Opd_prescription::get_remark/$1');
|
||||
$routes->get('Opd_prescription/patient_remark/(:num)', 'Opd_prescription::patient_remark/$1');
|
||||
$routes->get('Opd_prescription/show_profile_opd/(:num)', 'Opd_prescription::show_profile_opd/$1');
|
||||
$routes->get('Opd_prescription/show_profile_opd/(:num)/(:num)', 'Opd_prescription::show_profile_opd/$1/$2');
|
||||
$routes->get('Opd_prescription/show_old_Prescribed/(:num)/(:num)', 'Opd_prescription::show_old_Prescribed/$1/$2');
|
||||
$routes->get('Opd_prescription/show_medical_item/(:num)', 'Opd_prescription::show_medical_item/$1');
|
||||
$routes->get('Opd_prescription/prescribed_dose/(:num)/(:num)', 'Opd_prescription::prescribed_dose/$1/$2');
|
||||
|
||||
$routes->get('Invoice/list_req_payment', 'Invoice::list_req_payment');
|
||||
$routes->post('Invoice/getRequestTable', 'Invoice::getRequestTable');
|
||||
$routes->get('Invoice/payment_form/(:num)', 'Invoice::payment_form/$1');
|
||||
$routes->post('Invoice/req_payment_process', 'Invoice::req_payment_process');
|
||||
$routes->get('Invoice/print_org_payment_invoice/(:num)', 'Invoice::print_org_payment_invoice/$1');
|
||||
$routes->get('Invoice/list_refund', 'Invoice::list_refund');
|
||||
$routes->post('Invoice/getRefundTable', 'Invoice::getRefundTable');
|
||||
$routes->get('Invoice/refund_form/(:num)', 'Invoice::refund_form/$1');
|
||||
$routes->post('Invoice/refund_process', 'Invoice::refund_process');
|
||||
|
||||
$routes->get('Lab_Admin/report_list', 'Setting\Template::report_list');
|
||||
$routes->get('Lab_Admin/report_ultrasound_list/(:num)', 'Setting\Template::report_ultrasound_list/$1');
|
||||
$routes->get('Lab_Admin/report_test_list/(:num)', 'Setting\Template::report_test_list/$1');
|
||||
$routes->get('Lab_Admin/test_search_page/(:num)', 'Setting\Template::test_search_page/$1');
|
||||
$routes->get('Lab_Admin/test_parameter_load/(:num)/(:num)', 'Setting\Template::test_parameter_load/$1/$2');
|
||||
$routes->post('Lab_Admin/test_parameter_edit', 'Setting\Template::test_parameter_edit');
|
||||
$routes->post('Lab_Admin/test_parameter_add', 'Setting\Template::test_parameter_add');
|
||||
$routes->post('Lab_Admin/test_parameter_option_add', 'Setting\Template::test_parameter_option_add');
|
||||
$routes->post('Lab_Admin/remove_test_option/(:num)/(:num)', 'Setting\Template::remove_test_option/$1/$2');
|
||||
$routes->post('Lab_Admin/change_sort/(:num)/(:num)/(:num)/(:num)/(:num)', 'Setting\Template::change_sort/$1/$2/$3/$4/$5');
|
||||
$routes->post('Lab_Admin/change_sort_item/(:num)/(:num)/(:num)/(:num)/(:num)', 'Setting\Template::change_sort_item/$1/$2/$3/$4/$5');
|
||||
$routes->get('Lab_Admin/reportedit_load/(:num)', 'Setting\Template::reportedit_load/$1');
|
||||
$routes->get('Lab_Admin/reportedit_ultrasound_load/(:num)/(:num)', 'Setting\Template::reportedit_ultrasound_load/$1/$2');
|
||||
$routes->get('Lab_Admin/print_pdf_create/(:num)/(:num)/(:num)', 'Diagnosis::printPdfCreate/$1/$2/$3');
|
||||
$routes->get('Lab_Admin/print_pdf_create/(:num)/(:num)/(:num)/(:num)', 'Diagnosis::printPdfCreate/$1/$2/$3/$4');
|
||||
$routes->post('Lab_Admin/report_update', 'Setting\Template::report_update');
|
||||
$routes->post('Lab_Admin/report_insert', 'Setting\Template::report_insert');
|
||||
$routes->post('Lab_Admin/report_ultrasound_insert/(:num)', 'Setting\Template::report_ultrasound_insert/$1');
|
||||
$routes->post('Lab_Admin/report_ultrasound_update/(:num)', 'Setting\Template::report_ultrasound_update/$1');
|
||||
$routes->post('Lab_Admin/add_test_repo/(:num)/(:num)', 'Setting\Template::add_test_repo/$1/$2');
|
||||
$routes->post('Lab_Admin/remove_test_item/(:num)/(:num)', 'Setting\Template::remove_test_item/$1/$2');
|
||||
$routes->post('Lab_Admin/test_item_search', 'Setting\Template::test_item_search');
|
||||
|
||||
$routes->get('Opdcase/addopd/(:num)', 'Opdcase::addopd/$1');
|
||||
$routes->post('Opdcase/showfee', 'Opdcase::showfee');
|
||||
$routes->post('Opdcase/confirm_opd', 'Opdcase::confirm_opd');
|
||||
$routes->get('Opdcase/invoice/(:num)', 'Opd::invoice/$1');
|
||||
|
||||
$routes->get('Report/collection_report', 'Report::collection_report');
|
||||
$routes->get('Report/report_total_payment_app_show/(:segment)/(:segment)/(:segment)', 'Report::report_total_payment_app_show/$1/$2/$3');
|
||||
$routes->get('Report/report_total_payment_app_show/(:segment)/(:segment)/(:segment)/(:num)', 'Report::report_total_payment_app_show/$1/$2/$3/$4');
|
||||
$routes->get('Report/report_total_payment_app_show/(:segment)/(:segment)/(:segment)/(:segment)', 'Report::report_total_payment_app_show/$1/$2/$3/$4');
|
||||
$routes->get('Report/report_total_payment_app_show/(:segment)/(:segment)/(:segment)/(:segment)/(:num)', 'Report::report_total_payment_app_show/$1/$2/$3/$4/$5');
|
||||
|
||||
$routes->get('Report/diagnosis_report', 'Report::diagnosis_report');
|
||||
$routes->get('Report/diagnosis_report_data/(:segment)', 'Report::diagnosis_report_data/$1');
|
||||
$routes->get('Report/diagnosis_report_data/(:segment)/(:segment)', 'Report::diagnosis_report_data/$1/$2');
|
||||
$routes->get('Report/diagnosis_report_data/(:segment)/(:segment)/(:segment)', 'Report::diagnosis_report_data/$1/$2/$3');
|
||||
$routes->get('Report/diagnosis_report_data/(:segment)/(:segment)/(:segment)/(:num)', 'Report::diagnosis_report_data/$1/$2/$3/$4');
|
||||
|
||||
// Insurance Credit Reports
|
||||
$routes->get('Report/insurance_credit_main', 'Report::insurance_credit_main');
|
||||
$routes->get('Report/insurance_opd_report', 'Report::insurance_opd_report');
|
||||
$routes->get('Report/insurance_opd_report_data/(:segment)/(:segment)/(:segment)', 'Report::insurance_opd_report_data/$1/$2/$3');
|
||||
$routes->get('Report/insurance_opd_report_data/(:segment)/(:segment)/(:segment)/(:num)', 'Report::insurance_opd_report_data/$1/$2/$3/$4');
|
||||
$routes->get('Report/insurance_ipd_report', 'Report::insurance_ipd_report');
|
||||
$routes->get('Report/insurance_ipd_report_data/(:segment)/(:segment)/(:segment)', 'Report::insurance_ipd_report_data/$1/$2/$3');
|
||||
$routes->get('Report/insurance_ipd_report_data/(:segment)/(:segment)/(:segment)/(:num)', 'Report::insurance_ipd_report_data/$1/$2/$3/$4');
|
||||
$routes->get('Report/insurance_combined_report', 'Report::insurance_combined_report');
|
||||
$routes->get('Report/insurance_combined_report_data/(:segment)/(:segment)/(:segment)', 'Report::insurance_combined_report_data/$1/$2/$3');
|
||||
$routes->get('Report/insurance_combined_report_data/(:segment)/(:segment)/(:segment)/(:num)', 'Report::insurance_combined_report_data/$1/$2/$3/$4');
|
||||
|
||||
// Organization Packing Routes
|
||||
$routes->get('org-packing', 'OrgPacking::index');
|
||||
$routes->post('org-packing/search', 'OrgPacking::search');
|
||||
$routes->get('org-packing/create', 'OrgPacking::create');
|
||||
$routes->post('org-packing/store', 'OrgPacking::store');
|
||||
$routes->get('org-packing/edit/(:num)', 'OrgPacking::edit/$1');
|
||||
$routes->post('org-packing/update/(:num)', 'OrgPacking::update/$1');
|
||||
$routes->post('org-packing/add-case/(:num)/(:num)', 'OrgPacking::addCase/$1/$2');
|
||||
$routes->post('org-packing/remove-case/(:num)/(:num)', 'OrgPacking::removeCase/$1/$2');
|
||||
$routes->get('org-packing/print/(:num)', 'OrgPacking::printList/$1');
|
||||
|
||||
// API endpoint for Select2 case search
|
||||
$routes->post('api/search-org-cases', 'OrgPacking::searchCases');
|
||||
|
||||
// Diagnosis Routes
|
||||
$routes->get('diagnosis', 'Diagnosis::index');
|
||||
$routes->get('diagnosis/pathology', 'Diagnosis::pathology');
|
||||
$routes->get('diagnosis/biopsy', 'Diagnosis::biopsy');
|
||||
$routes->get('diagnosis/ultrasound', 'Diagnosis::ultrasound');
|
||||
$routes->get('diagnosis/xray', 'Diagnosis::xray');
|
||||
$routes->get('diagnosis/mri', 'Diagnosis::mri');
|
||||
$routes->get('diagnosis/ctscan', 'Diagnosis::ctscan');
|
||||
$routes->post('diagnosis/search-lab', 'Diagnosis::searchLab');
|
||||
$routes->post('diagnosis/search-lab-srno', 'Diagnosis::searchLabBySrno');
|
||||
$routes->post('diagnosis/search-lab-labno', 'Diagnosis::searchLabByLabno');
|
||||
$routes->get('diagnosis/test-data', 'Diagnosis::testData');
|
||||
$routes->get('diagnosis/select-lab-invoice/(:num)/(:num)', 'Diagnosis::selectLabInvoicePath/$1/$2');
|
||||
$routes->get('diagnosis/lab-date-show/(:num)/(:num)', 'Diagnosis::labDateShow/$1/$2');
|
||||
$routes->get('diagnosis/test-list/(:num)/(:num)', 'Diagnosis::testList/$1/$2');
|
||||
$routes->get('diagnosis/edit-test-data/(:num)', 'Diagnosis::editTestData/$1');
|
||||
$routes->post('diagnosis/update-test-value', 'Diagnosis::updateTestValue');
|
||||
$routes->post('diagnosis/create-report/(:num)', 'Diagnosis::createReport/$1');
|
||||
$routes->post('diagnosis/create-report-xray/(:num)', 'Diagnosis::createReportXray/$1');
|
||||
$routes->get('diagnosis/show-report-final/(:num)', 'Diagnosis::showReportFinal/$1');
|
||||
$routes->get('diagnosis/show-report-final-xray/(:num)', 'Diagnosis::showReportFinalXray/$1');
|
||||
$routes->get('diagnosis/print-single-report/(:num)', 'Diagnosis::printSingleReport/$1');
|
||||
$routes->post('diagnosis/final-update/(:num)', 'Diagnosis::finalUpdate/$1');
|
||||
$routes->post('diagnosis/final-update-xray/(:num)', 'Diagnosis::finalUpdateXray/$1');
|
||||
$routes->post('diagnosis/confirm-report/(:num)', 'Diagnosis::confirmReport/$1');
|
||||
$routes->post('diagnosis/confirm-report-xray/(:num)', 'Diagnosis::confirmReportXray/$1');
|
||||
$routes->match(['get', 'post'], 'diagnosis/get-template-xray/(:num)', 'Diagnosis::getTemplateXray/$1');
|
||||
$routes->post('diagnosis/remove-test/(:num)', 'Diagnosis::removeTest/$1');
|
||||
$routes->post('diagnosis/update-combine-report', 'Diagnosis::updateCombineReport');
|
||||
$routes->post('diagnosis/report-compile/(:num)/(:num)', 'Diagnosis::reportCompile/$1/$2');
|
||||
$routes->get('diagnosis/report-file-list/(:num)/(:num)', 'Diagnosis::reportFileList/$1/$2');
|
||||
$routes->get('diagnosis/report-file-list/(:num)/(:num)/(:num)', 'Diagnosis::reportFileList/$1/$2/$3');
|
||||
$routes->get('diagnosis/select-lab-radiology/(:num)/(:num)', 'Diagnosis::selectLabRadiology/$1/$2');
|
||||
$routes->get('diagnosis/print-pdf-create/(:num)/(:num)/(:num)', 'Diagnosis::printPdfCreate/$1/$2/$3');
|
||||
$routes->get('diagnosis/print-pdf-create/(:num)/(:num)/(:num)/(:num)', 'Diagnosis::printPdfCreate/$1/$2/$3/$4');
|
||||
$routes->post('diagnosis/sample-collection/(:num)/(:num)', 'Diagnosis::sampleCollection/$1/$2');
|
||||
$routes->post('diagnosis/update-lab-timing', 'Diagnosis::updateLabTiming');
|
||||
$routes->post('diagnosis/update-lab-no/(:num)', 'Diagnosis::updateLabNo/$1');
|
||||
$routes->post('diagnosis/ai-extract-report-values', 'Diagnosis::aiExtractLabReportValues');
|
||||
$routes->get('diagnosis/ai-extracted-values/(:num)/(:num)', 'Diagnosis::aiExtractedValues/$1/$2');
|
||||
$routes->post('diagnosis/ai-verify-extracted-values/(:num)', 'Diagnosis::aiVerifyExtractedValues/$1');
|
||||
|
||||
// Legacy Lab_Report compatibility
|
||||
$routes->get('Lab_Report/lab_master', 'Diagnosis::labMaster');
|
||||
$routes->get('Lab_Report/lab_path/(:num)', 'Diagnosis::labPathLegacy/$1');
|
||||
$routes->post('Lab_Report/search_lab_4/(:num)', 'Diagnosis::searchLab/$1');
|
||||
$routes->post('Lab_Report/search_lab_4_srno/(:num)', 'Diagnosis::searchLabBySrno/$1');
|
||||
$routes->post('Lab_Report/search_lab_4_labno/(:num)', 'Diagnosis::searchLabByLabno/$1');
|
||||
$routes->get('Lab_Report/select_lab_invoice/(:num)/(:num)', 'Diagnosis::selectLabInvoicePath/$1/$2');
|
||||
$routes->get('Lab_Report/select_lab_invoice_path/(:num)/(:num)', 'Diagnosis::selectLabInvoicePath/$1/$2');
|
||||
$routes->get('Lab_Report/lab_date_show/(:num)/(:num)', 'Diagnosis::labDateShow/$1/$2');
|
||||
$routes->get('Lab_Report/test_list/(:num)/(:num)', 'Diagnosis::testList/$1/$2');
|
||||
$routes->get('Lab_Report/xray_test_list/(:num)/(:num)', 'Diagnosis::testList/$1/$2');
|
||||
$routes->get('Lab_Report/lab_tab_1_process/(:num)/(:num)', 'Diagnosis::labTab1Process/$1/$2');
|
||||
$routes->get('Lab_Report/report_file_list/(:num)/(:num)', 'Diagnosis::reportFileList/$1/$2');
|
||||
$routes->get('Lab_Report/report_file_list/(:num)/(:num)/(:num)', 'Diagnosis::reportFileList/$1/$2/$3');
|
||||
$routes->get('Lab_Report/select_lab_radiology/(:num)/(:num)', 'Diagnosis::selectLabRadiology/$1/$2');
|
||||
$routes->match(['get', 'post'], 'Lab_Report/create_report_xray/(:num)', 'Diagnosis::createReportXray/$1');
|
||||
$routes->get('Lab_Report/show_report_final/(:num)', 'Diagnosis::showReportFinalXray/$1');
|
||||
$routes->match(['get', 'post'], 'Lab_Report/get_template_xray/(:num)', 'Diagnosis::getTemplateXray/$1');
|
||||
$routes->match(['get', 'post'], 'Lab_Report/Final_Update_xray/(:num)', 'Diagnosis::finalUpdateXray/$1');
|
||||
$routes->match(['get', 'post'], 'Lab_Report/confirm_report_xray/(:num)', 'Diagnosis::confirmReportXray/$1');
|
||||
|
||||
// Legacy URL compatibility
|
||||
$routes->get('Ocasemaster/newcase/(:num)/(:num)', 'Billing\\CaseMaster::newcase/$1/$2');
|
||||
$routes->get('Ocasemaster/newcase/(:num)/(:num)/(:num)', 'Billing\\CaseMaster::newcase/$1/$2/$3');
|
||||
$routes->get('Ocasemaster/open_case/(:num)', 'Billing\\CaseMaster::open_case/$1');
|
||||
$routes->get('Ocasemaster/open_case/(:num)/(:num)', 'Billing\\CaseMaster::open_case/$1/$2');
|
||||
$routes->post('Ocasemaster/create', 'Billing\\CaseMaster::create');
|
||||
$routes->post('Ocasemaster/update', 'Billing\\CaseMaster::update');
|
||||
$routes->get('Ocasemaster/addPathTest/(:num)', 'Billing\\CaseMaster::addPathTest/$1');
|
||||
|
||||
$routes->post('Orgcase/search', 'Billing\\CaseMaster::search');
|
||||
$routes->get('Orgcase/search_all', 'Billing\\CaseMaster::search_all');
|
||||
$routes->get('Orgcase/case_invoice/(:segment)', 'Billing\\CaseMaster::case_invoice/$1');
|
||||
$routes->get('Orgcase/case_invoice/(:segment)/(:num)/(:num)/(:num)', 'Billing\\CaseMaster::case_invoice/$1/$2/$3/$4');
|
||||
$routes->get('Orgcase/case_invoice_ipd/(:num)', 'Billing\\CaseMaster::case_invoice_ipd/$1');
|
||||
$routes->post('Orgcase/ORG_info', 'Billing\\CaseMaster::ORG_info');
|
||||
$routes->post('Orgcase/update_itemrateqty', 'Billing\\CaseMaster::update_itemrateqty');
|
||||
$routes->post('Orgcase/update_status', 'Billing\\CaseMaster::update_status');
|
||||
$routes->post('Orgcase/org_contingent_update', 'Billing\\CaseMaster::org_contingent_update');
|
||||
$routes->get('Orgcase/case_invoice_print/(:num)', 'Billing\\CaseMaster::case_invoice_print/$1');
|
||||
$routes->post('Orgcase/getCaseTable', 'Billing\\CaseMaster::getCaseTable');
|
||||
$routes->get('Orgcase/contingent_bill/(:num)', 'Billing\\CaseMaster::contingent_bill/$1');
|
||||
$routes->get('Orgcase/contingent_bill/(:num)/(:num)', 'Billing\\CaseMaster::contingent_bill/$1/$2');
|
||||
$routes->get('Orgcase/create_contingent_bill/(:num)', 'Billing\\CaseMaster::create_contingent_bill/$1');
|
||||
$routes->post('Orgcase/org_confirm_payment', 'Billing\\CaseMaster::org_confirm_payment');
|
||||
$routes->get('Orgcase/org_payment_request', 'Billing\\CaseMaster::org_payment_request');
|
||||
$routes->get('Orgcase/load_model_box/(:segment)', 'Billing\\CaseMaster::load_model_box/$1');
|
||||
$routes->post('Orgcase/payment_request', 'Billing\\CaseMaster::payment_request');
|
||||
$routes->post('Orgcase/refund_request', 'Billing\\CaseMaster::refund_request');
|
||||
|
||||
$routes->get('Patient/person_record/(:num)', 'Patient::person_record/$1');
|
||||
$routes->get('Patient/person_record/(:num)/(:num)', 'Patient::person_record/$1/$2');
|
||||
$routes->get('Patient/show_cards/(:num)', 'Patient::show_cards/$1');
|
||||
$routes->get('Patient/show_cards/(:num)/(:num)', 'Patient::show_cards/$1/$2');
|
||||
$routes->post('Patient/update_card', 'Patient::update_card');
|
||||
$routes->post('Patient/update_aadhar', 'Patient::update_aadhar');
|
||||
$routes->post('Patient/create', 'Patient::create');
|
||||
$routes->post('OcasePathLap/list_pathtest_bytype', 'OcasePathLap::list_pathtest_bytype');
|
||||
$routes->post('OcasePathLap/get_echs_id', 'OcasePathLap::get_echs_id');
|
||||
$routes->post('OcasePathLap/update_refer_doc', 'OcasePathLap::update_refer_doc');
|
||||
$routes->get('OcasePathLap/showinvoice/(:num)', 'OcasePathLap::showinvoice/$1');
|
||||
$routes->post('OcasePathLap/showitem/(:num)', 'OcasePathLap::showitem/$1');
|
||||
$routes->post('OcasePathLap/confirm_payment', 'OcasePathLap::confirm_payment');
|
||||
$routes->get('OcasePathLap/invoice_print/(:num)', 'OcasePathLap::invoice_print/$1');
|
||||
$routes->get('OcasePathLap/addPathTest/(:num)/(:num)', 'Billing\\CaseMaster::addPathTest/$1');
|
||||
|
||||
$routes->group('setting', static function($routes) {
|
||||
$routes->get('admin', 'Setting\\Admin::index');
|
||||
$routes->get('admin/user-management', 'Setting\\UserManagement::index');
|
||||
$routes->get('admin/user-management/new', 'Setting\\UserManagement::create');
|
||||
$routes->post('admin/user-management/new', 'Setting\\UserManagement::store');
|
||||
$routes->get('admin/user-management/edit/(:num)', 'Setting\\UserManagement::edit/$1');
|
||||
$routes->post('admin/user-management/edit/(:num)', 'Setting\\UserManagement::update/$1');
|
||||
$routes->get('admin/user-management/reset-password/(:num)', 'Setting\\UserManagement::resetPasswordForm/$1');
|
||||
$routes->post('admin/user-management/reset-password/(:num)', 'Setting\\UserManagement::resetPassword/$1');
|
||||
$routes->get('admin/user-management/permissions', 'Setting\\UserManagement::permissions');
|
||||
$routes->post('admin/user-management/permissions', 'Setting\\UserManagement::savePermissions');
|
||||
$routes->get('admin/ai-settings', 'Setting\\AiSettings::index');
|
||||
$routes->post('admin/ai-settings/save', 'Setting\\AiSettings::save');
|
||||
$routes->post('admin/ai-settings/test', 'Setting\\AiSettings::test');
|
||||
$routes->get('admin/doctor', 'Setting\\Doctor::index');
|
||||
$routes->get('admin/doctor/new', 'Setting\\Doctor::create');
|
||||
$routes->post('admin/doctor/new', 'Setting\\Doctor::store');
|
||||
$routes->get('admin/doctor/(:num)', 'Setting\\Doctor::doctorRecord/$1');
|
||||
$routes->post('admin/doctor/update', 'Setting\\Doctor::updateRecord');
|
||||
$routes->post('admin/doctor/spec', 'Setting\\Doctor::doctorRecordSpec');
|
||||
$routes->post('admin/doctor/fee/add', 'Setting\\Doctor::addFee');
|
||||
$routes->post('admin/doctor/fee/remove', 'Setting\\Doctor::removeFee');
|
||||
$routes->post('admin/doctor/ipd-fee/add', 'Setting\\Doctor::addIpdFee');
|
||||
$routes->post('admin/doctor/ipd-fee/remove', 'Setting\\Doctor::removeIpdFee');
|
||||
$routes->get('admin/doctor/specs', 'Setting\\Doctor::specs');
|
||||
$routes->post('admin/doctor/specs/create', 'Setting\\Doctor::storeSpec');
|
||||
$routes->post('admin/doctor/specs/update', 'Setting\\Doctor::updateSpec');
|
||||
$routes->post('admin/doctor/specs/delete', 'Setting\\Doctor::deleteSpec');
|
||||
$routes->get('admin/doctor/ipd-fee-types', 'Setting\\Doctor::ipdFeeTypes');
|
||||
$routes->post('admin/doctor/ipd-fee-types/create', 'Setting\\Doctor::storeIpdFeeType');
|
||||
$routes->post('admin/doctor/ipd-fee-types/update', 'Setting\\Doctor::updateIpdFeeType');
|
||||
$routes->post('admin/doctor/ipd-fee-types/delete', 'Setting\\Doctor::deleteIpdFeeType');
|
||||
$routes->get('admin/insurance', 'Setting\\Insurance::index');
|
||||
$routes->get('admin/insurance/new', 'Setting\\Insurance::create');
|
||||
$routes->post('admin/insurance/new', 'Setting\\Insurance::store');
|
||||
$routes->get('admin/insurance/(:num)', 'Setting\\Insurance::record/$1');
|
||||
$routes->post('admin/insurance/update', 'Setting\\Insurance::update');
|
||||
$routes->get('admin/bank', 'Setting\\Bank::index');
|
||||
$routes->post('admin/bank/create', 'Setting\\Bank::createBank');
|
||||
$routes->post('admin/bank/create-with-source', 'Setting\\Bank::createBankWithSource');
|
||||
$routes->post('admin/bank/update', 'Setting\\Bank::updateBank');
|
||||
$routes->post('admin/bank/delete', 'Setting\\Bank::deleteBank');
|
||||
$routes->get('admin/bank/sources/(:num)', 'Setting\\Bank::sources/$1');
|
||||
$routes->post('admin/bank/source/create', 'Setting\\Bank::createSource');
|
||||
$routes->post('admin/bank/source/update', 'Setting\\Bank::updateSource');
|
||||
$routes->post('admin/bank/source/delete', 'Setting\\Bank::deleteSource');
|
||||
$routes->get('admin/medical-bank', 'Setting\\MedicalBank::index');
|
||||
$routes->post('admin/medical-bank/create', 'Setting\\MedicalBank::createBank');
|
||||
$routes->post('admin/medical-bank/create-with-source', 'Setting\\MedicalBank::createBankWithSource');
|
||||
$routes->post('admin/medical-bank/update', 'Setting\\MedicalBank::updateBank');
|
||||
$routes->post('admin/medical-bank/delete', 'Setting\\MedicalBank::deleteBank');
|
||||
$routes->get('admin/medical-bank/sources/(:num)', 'Setting\\MedicalBank::sources/$1');
|
||||
$routes->post('admin/medical-bank/source/create', 'Setting\\MedicalBank::createSource');
|
||||
$routes->post('admin/medical-bank/source/update', 'Setting\\MedicalBank::updateSource');
|
||||
$routes->post('admin/medical-bank/source/delete', 'Setting\\MedicalBank::deleteSource');
|
||||
$routes->get('admin/reffer', 'Setting\\Reffer::index');
|
||||
$routes->get('admin/reffer/new', 'Setting\\Reffer::create');
|
||||
$routes->post('admin/reffer/save', 'Setting\\Reffer::store');
|
||||
$routes->get('admin/reffer/(:num)', 'Setting\\Reffer::edit/$1');
|
||||
$routes->post('admin/reffer/update/(:num)', 'Setting\\Reffer::update/$1');
|
||||
$routes->post('admin/reffer/activate/(:num)/(:num)', 'Setting\\Reffer::activate/$1/$2');
|
||||
$routes->get('admin/reffer/types', 'Setting\\Reffer::typeList');
|
||||
$routes->post('admin/reffer/types/create', 'Setting\\Reffer::storeType');
|
||||
$routes->post('admin/reffer/types/update', 'Setting\\Reffer::updateType');
|
||||
$routes->post('admin/reffer/types/delete', 'Setting\\Reffer::deleteType');
|
||||
$routes->get('admin/bed-management', 'Setting\\BedManagement::index');
|
||||
$routes->get('admin/bed-categories', 'Setting\\BedManagement::categories');
|
||||
$routes->post('admin/bed-categories/save', 'Setting\\BedManagement::saveCategory');
|
||||
$routes->post('admin/bed-categories/delete', 'Setting\\BedManagement::deleteCategory');
|
||||
$routes->get('admin/beds', 'Setting\\BedManagement::beds');
|
||||
$routes->post('admin/beds/save', 'Setting\\BedManagement::saveBed');
|
||||
$routes->post('admin/beds/delete', 'Setting\\BedManagement::deleteBed');
|
||||
$routes->get('admin/bed-maintenance', 'Setting\\BedManagement::maintenance');
|
||||
$routes->post('admin/bed-maintenance/save', 'Setting\\BedManagement::saveMaintenance');
|
||||
$routes->post('admin/bed-maintenance/delete', 'Setting\\BedManagement::deleteMaintenance');
|
||||
$routes->get('admin/bed-assignments', 'Setting\\BedManagement::assignmentHistory');
|
||||
$routes->post('admin/bed-assignments/save', 'Setting\\BedManagement::saveAssignment');
|
||||
$routes->post('admin/bed-assignments/delete', 'Setting\\BedManagement::deleteAssignment');
|
||||
$routes->get('template', 'Setting\\Template::index');
|
||||
$routes->get('charges', 'Setting\\Charges::index');
|
||||
});
|
||||
|
||||
$routes->group('item', static function($routes) {
|
||||
$routes->get('search', 'Item::search');
|
||||
$routes->get('search-itemtype', 'Item::searchItemType');
|
||||
$routes->get('search-adv/(:num)', 'Item::searchAdv/$1');
|
||||
$routes->get('search-print/(:num)', 'Item::searchPrint/$1');
|
||||
$routes->get('export-excel/(:num)', 'Item::exportExcel/$1');
|
||||
$routes->match(['get', 'post'], 'item-record/(:num)', 'Item::itemRecord/$1');
|
||||
$routes->get('itemtype-record/(:num)', 'Item::itemTypeRecord/$1');
|
||||
$routes->get('add', 'Item::addRecord');
|
||||
$routes->get('add-type', 'Item::addItemTypeRecord');
|
||||
$routes->post('create', 'Item::createRecord');
|
||||
$routes->post('update', 'Item::updateRecord');
|
||||
$routes->post('create-type', 'Item::createItemTypeRecord');
|
||||
$routes->post('update-type', 'Item::updateItemTypeRecord');
|
||||
$routes->post('insurance/add', 'Item::addInsuranceItemRecord');
|
||||
$routes->post('insurance/remove', 'Item::removeInsuranceItem');
|
||||
});
|
||||
|
||||
$routes->group('item-ipd', static function($routes) {
|
||||
$routes->get('search', 'ItemIpd::search');
|
||||
$routes->get('search-itemtype', 'ItemIpd::searchItemType');
|
||||
$routes->get('search-adv/(:num)', 'ItemIpd::searchAdv/$1');
|
||||
$routes->get('search-print/(:num)', 'ItemIpd::searchPrint/$1');
|
||||
$routes->get('export-excel/(:num)', 'ItemIpd::exportExcel/$1');
|
||||
$routes->match(['get', 'post'], 'item-record/(:num)', 'ItemIpd::itemRecord/$1');
|
||||
$routes->get('itemtype-record/(:num)', 'ItemIpd::itemTypeRecord/$1');
|
||||
$routes->get('add', 'ItemIpd::addRecord');
|
||||
$routes->get('add-type', 'ItemIpd::addItemTypeRecord');
|
||||
$routes->post('create', 'ItemIpd::createRecord');
|
||||
$routes->post('update', 'ItemIpd::updateRecord');
|
||||
$routes->post('create-type', 'ItemIpd::createItemTypeRecord');
|
||||
$routes->post('update-type', 'ItemIpd::updateItemTypeRecord');
|
||||
$routes->post('insurance/add', 'ItemIpd::addInsuranceItemRecord');
|
||||
$routes->post('insurance/remove', 'ItemIpd::removeInsuranceItem');
|
||||
});
|
||||
|
||||
$routes->group('package', static function($routes) {
|
||||
$routes->get('search', 'Package::search');
|
||||
$routes->get('search-itemtype', 'Package::searchItemType');
|
||||
$routes->get('search-adv/(:num)', 'Package::searchAdv/$1');
|
||||
$routes->get('search-print/(:num)', 'Package::searchPrint/$1');
|
||||
$routes->get('export-excel/(:num)', 'Package::exportExcel/$1');
|
||||
$routes->match(['get', 'post'], 'item-record/(:num)', 'Package::itemRecord/$1');
|
||||
$routes->get('itemtype-record/(:num)', 'Package::itemTypeRecord/$1');
|
||||
$routes->get('add', 'Package::addRecord');
|
||||
$routes->get('add-type', 'Package::addItemTypeRecord');
|
||||
$routes->post('create', 'Package::createRecord');
|
||||
$routes->post('update', 'Package::updateRecord');
|
||||
$routes->post('create-type', 'Package::createItemTypeRecord');
|
||||
$routes->post('update-type', 'Package::updateItemTypeRecord');
|
||||
$routes->post('insurance/add', 'Package::addInsuranceItemRecord');
|
||||
$routes->post('insurance/remove', 'Package::removeInsuranceItem');
|
||||
});
|
||||
|
||||
$routes->group('Package', static function($routes) {
|
||||
$routes->get('search', 'Package::search');
|
||||
$routes->get('search_itemtype', 'Package::searchItemType');
|
||||
$routes->get('search_adv/(:num)', 'Package::searchAdv/$1');
|
||||
$routes->get('search_print/(:num)', 'Package::searchPrint/$1');
|
||||
$routes->get('export-excel/(:num)', 'Package::exportExcel/$1');
|
||||
$routes->match(['get', 'post'], 'item_record/(:num)', 'Package::itemRecord/$1');
|
||||
$routes->get('itemtype_record/(:num)', 'Package::itemTypeRecord/$1');
|
||||
$routes->get('AddRecord', 'Package::addRecord');
|
||||
$routes->get('AddItemTypeRecord', 'Package::addItemTypeRecord');
|
||||
$routes->post('CreateRecord', 'Package::createRecord');
|
||||
$routes->post('UpdateRecord', 'Package::updateRecord');
|
||||
$routes->post('CreateItemTypeRecord', 'Package::createItemTypeRecord');
|
||||
$routes->post('UpdateItemTypeRecord', 'Package::updateItemTypeRecord');
|
||||
$routes->post('AddInsuranceItemRecord', 'Package::addInsuranceItemRecord');
|
||||
$routes->post('remove_record_item', 'Package::removeInsuranceItem');
|
||||
});
|
||||
|
||||
$routes->group('IPD_Package', static function($routes) {
|
||||
$routes->get('search', 'Package::search');
|
||||
$routes->get('search_itemtype', 'Package::searchItemType');
|
||||
$routes->get('search_adv/(:num)', 'Package::searchAdv/$1');
|
||||
$routes->get('search_print/(:num)', 'Package::searchPrint/$1');
|
||||
$routes->get('export-excel/(:num)', 'Package::exportExcel/$1');
|
||||
$routes->match(['get', 'post'], 'item_record/(:num)', 'Package::itemRecord/$1');
|
||||
$routes->get('itemtype_record/(:num)', 'Package::itemTypeRecord/$1');
|
||||
$routes->get('AddRecord', 'Package::addRecord');
|
||||
$routes->get('AddItemTypeRecord', 'Package::addItemTypeRecord');
|
||||
$routes->post('CreateRecord', 'Package::createRecord');
|
||||
$routes->post('UpdateRecord', 'Package::updateRecord');
|
||||
$routes->post('CreateItemTypeRecord', 'Package::createItemTypeRecord');
|
||||
$routes->post('UpdateItemTypeRecord', 'Package::updateItemTypeRecord');
|
||||
$routes->post('AddInsuranceItemRecord', 'Package::addInsuranceItemRecord');
|
||||
$routes->post('remove_record_item', 'Package::removeInsuranceItem');
|
||||
});
|
||||
|
||||
$routes->group('Item_IPD', static function($routes) {
|
||||
$routes->get('search', 'ItemIpd::search');
|
||||
$routes->get('search_itemtype', 'ItemIpd::searchItemType');
|
||||
$routes->get('search_adv/(:num)', 'ItemIpd::searchAdv/$1');
|
||||
$routes->get('search_print/(:num)', 'ItemIpd::searchPrint/$1');
|
||||
$routes->get('export-excel/(:num)', 'ItemIpd::exportExcel/$1');
|
||||
$routes->match(['get', 'post'], 'item_record/(:num)', 'ItemIpd::itemRecord/$1');
|
||||
$routes->get('itemtype_record/(:num)', 'ItemIpd::itemTypeRecord/$1');
|
||||
$routes->get('AddRecord', 'ItemIpd::addRecord');
|
||||
$routes->get('AddItemTypeRecord', 'ItemIpd::addItemTypeRecord');
|
||||
$routes->post('CreateRecord', 'ItemIpd::createRecord');
|
||||
$routes->post('UpdateRecord', 'ItemIpd::updateRecord');
|
||||
$routes->post('CreateItemTypeRecord', 'ItemIpd::createItemTypeRecord');
|
||||
$routes->post('UpdateItemTypeRecord', 'ItemIpd::updateItemTypeRecord');
|
||||
$routes->post('AddInsuranceItemRecord', 'ItemIpd::addInsuranceItemRecord');
|
||||
$routes->post('remove_record_item', 'ItemIpd::removeInsuranceItem');
|
||||
});
|
||||
149
app/Config/Routing.php
Normal file
149
app/Config/Routing.php
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\Routing as BaseRouting;
|
||||
|
||||
/**
|
||||
* Routing configuration
|
||||
*/
|
||||
class Routing extends BaseRouting
|
||||
{
|
||||
/**
|
||||
* For Defined Routes.
|
||||
* An array of files that contain route definitions.
|
||||
* Route files are read in order, with the first match
|
||||
* found taking precedence.
|
||||
*
|
||||
* Default: APPPATH . 'Config/Routes.php'
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $routeFiles = [
|
||||
APPPATH . 'Config/Routes.php',
|
||||
];
|
||||
|
||||
/**
|
||||
* For Defined Routes and Auto Routing.
|
||||
* The default namespace to use for Controllers when no other
|
||||
* namespace has been specified.
|
||||
*
|
||||
* Default: 'App\Controllers'
|
||||
*/
|
||||
public string $defaultNamespace = 'App\Controllers';
|
||||
|
||||
/**
|
||||
* For Auto Routing.
|
||||
* The default controller to use when no other controller has been
|
||||
* specified.
|
||||
*
|
||||
* Default: 'Home'
|
||||
*/
|
||||
public string $defaultController = 'Home';
|
||||
|
||||
/**
|
||||
* For Defined Routes and Auto Routing.
|
||||
* The default method to call on the controller when no other
|
||||
* method has been set in the route.
|
||||
*
|
||||
* Default: 'index'
|
||||
*/
|
||||
public string $defaultMethod = 'index';
|
||||
|
||||
/**
|
||||
* For Auto Routing.
|
||||
* Whether to translate dashes in URIs for controller/method to underscores.
|
||||
* Primarily useful when using the auto-routing.
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
public bool $translateURIDashes = false;
|
||||
|
||||
/**
|
||||
* Sets the class/method that should be called if routing doesn't
|
||||
* find a match. It can be the controller/method name like: Users::index
|
||||
*
|
||||
* This setting is passed to the Router class and handled there.
|
||||
*
|
||||
* If you want to use a closure, you will have to set it in the
|
||||
* routes file by calling:
|
||||
*
|
||||
* $routes->set404Override(function() {
|
||||
* // Do something here
|
||||
* });
|
||||
*
|
||||
* Example:
|
||||
* public $override404 = 'App\Errors::show404';
|
||||
*/
|
||||
public ?string $override404 = null;
|
||||
|
||||
/**
|
||||
* If TRUE, the system will attempt to match the URI against
|
||||
* Controllers by matching each segment against folders/files
|
||||
* in APPPATH/Controllers, when a match wasn't found against
|
||||
* defined routes.
|
||||
*
|
||||
* If FALSE, will stop searching and do NO automatic routing.
|
||||
*/
|
||||
public bool $autoRoute = false;
|
||||
|
||||
/**
|
||||
* If TRUE, the system will look for attributes on controller
|
||||
* class and methods that can run before and after the
|
||||
* controller/method.
|
||||
*
|
||||
* If FALSE, will ignore any attributes.
|
||||
*/
|
||||
public bool $useControllerAttributes = true;
|
||||
|
||||
/**
|
||||
* For Defined Routes.
|
||||
* If TRUE, will enable the use of the 'prioritize' option
|
||||
* when defining routes.
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
public bool $prioritize = false;
|
||||
|
||||
/**
|
||||
* For Defined Routes.
|
||||
* If TRUE, matched multiple URI segments will be passed as one parameter.
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
public bool $multipleSegmentsOneParam = false;
|
||||
|
||||
/**
|
||||
* For Auto Routing (Improved).
|
||||
* Map of URI segments and namespaces.
|
||||
*
|
||||
* The key is the first URI segment. The value is the controller namespace.
|
||||
* E.g.,
|
||||
* [
|
||||
* 'blog' => 'Acme\Blog\Controllers',
|
||||
* ]
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $moduleRoutes = [];
|
||||
|
||||
/**
|
||||
* For Auto Routing (Improved).
|
||||
* Whether to translate dashes in URIs for controller/method to CamelCase.
|
||||
* E.g., blog-controller -> BlogController
|
||||
*
|
||||
* If you enable this, $translateURIDashes is ignored.
|
||||
*
|
||||
* Default: false
|
||||
*/
|
||||
public bool $translateUriToCamelCase = true;
|
||||
}
|
||||
86
app/Config/Security.php
Normal file
86
app/Config/Security.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class Security extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Protection Method
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Protection Method for Cross Site Request Forgery protection.
|
||||
*
|
||||
* @var string 'cookie' or 'session'
|
||||
*/
|
||||
public string $csrfProtection = 'session';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Token Randomization
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Randomize the CSRF Token for added security.
|
||||
*/
|
||||
public bool $tokenRandomize = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Token Name
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Token name for Cross Site Request Forgery protection.
|
||||
*/
|
||||
public string $tokenName = 'csrf_test_name';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Header Name
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Header name for Cross Site Request Forgery protection.
|
||||
*/
|
||||
public string $headerName = 'X-CSRF-TOKEN';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Cookie Name
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Cookie name for Cross Site Request Forgery protection.
|
||||
*/
|
||||
public string $cookieName = 'csrf_cookie_name';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Expires
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Expiration time for Cross Site Request Forgery protection cookie.
|
||||
*
|
||||
* Defaults to two hours (in seconds).
|
||||
*/
|
||||
public int $expires = 7200;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Regenerate
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Regenerate CSRF Token on every submission.
|
||||
*/
|
||||
public bool $regenerate = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CSRF Redirect
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Redirect to previous page with error on failure.
|
||||
*
|
||||
* @see https://codeigniter4.github.io/userguide/libraries/security.html#redirection-on-failure
|
||||
*/
|
||||
public bool $redirect = (ENVIRONMENT === 'production');
|
||||
}
|
||||
32
app/Config/Services.php
Normal file
32
app/Config/Services.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseService;
|
||||
|
||||
/**
|
||||
* Services Configuration file.
|
||||
*
|
||||
* Services are simply other classes/libraries that the system uses
|
||||
* to do its job. This is used by CodeIgniter to allow the core of the
|
||||
* framework to be swapped out easily without affecting the usage within
|
||||
* the rest of your application.
|
||||
*
|
||||
* This file holds any application-specific services, or service overrides
|
||||
* that you might need. An example has been included with the general
|
||||
* method format you should use for your service methods. For more examples,
|
||||
* see the core Services file at system/Config/Services.php.
|
||||
*/
|
||||
class Services extends BaseService
|
||||
{
|
||||
/*
|
||||
* public static function example($getShared = true)
|
||||
* {
|
||||
* if ($getShared) {
|
||||
* return static::getSharedInstance('example');
|
||||
* }
|
||||
*
|
||||
* return new \CodeIgniter\Example();
|
||||
* }
|
||||
*/
|
||||
}
|
||||
128
app/Config/Session.php
Normal file
128
app/Config/Session.php
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Session\Handlers\BaseHandler;
|
||||
use CodeIgniter\Session\Handlers\FileHandler;
|
||||
|
||||
class Session extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Driver
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The session storage driver to use:
|
||||
* - `CodeIgniter\Session\Handlers\ArrayHandler` (for testing)
|
||||
* - `CodeIgniter\Session\Handlers\FileHandler`
|
||||
* - `CodeIgniter\Session\Handlers\DatabaseHandler`
|
||||
* - `CodeIgniter\Session\Handlers\MemcachedHandler`
|
||||
* - `CodeIgniter\Session\Handlers\RedisHandler`
|
||||
*
|
||||
* @var class-string<BaseHandler>
|
||||
*/
|
||||
public string $driver = FileHandler::class;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Cookie Name
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The session cookie name, must contain only [0-9a-z_-] characters
|
||||
*/
|
||||
public string $cookieName = 'ci_session';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Expiration
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The number of SECONDS you want the session to last.
|
||||
* Setting to 0 (zero) means expire when the browser is closed.
|
||||
*/
|
||||
public int $expiration = 7200;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Save Path
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The location to save sessions to and is driver dependent.
|
||||
*
|
||||
* For the 'files' driver, it's a path to a writable directory.
|
||||
* WARNING: Only absolute paths are supported!
|
||||
*
|
||||
* For the 'database' driver, it's a table name.
|
||||
* Please read up the manual for the format with other session drivers.
|
||||
*
|
||||
* IMPORTANT: You are REQUIRED to set a valid save path!
|
||||
*/
|
||||
public string $savePath = WRITEPATH . 'session';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Match IP
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Whether to match the user's IP address when reading the session data.
|
||||
*
|
||||
* WARNING: If you're using the database driver, don't forget to update
|
||||
* your session table's PRIMARY KEY when changing this setting.
|
||||
*/
|
||||
public bool $matchIP = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Time to Update
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* How many seconds between CI regenerating the session ID.
|
||||
*/
|
||||
public int $timeToUpdate = 300;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Regenerate Destroy
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Whether to destroy session data associated with the old session ID
|
||||
* when auto-regenerating the session ID. When set to FALSE, the data
|
||||
* will be later deleted by the garbage collector.
|
||||
*/
|
||||
public bool $regenerateDestroy = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Session Database Group
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* DB Group for the database session.
|
||||
*/
|
||||
public ?string $DBGroup = null;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Lock Retry Interval (microseconds)
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is used for RedisHandler.
|
||||
*
|
||||
* Time (microseconds) to wait if lock cannot be acquired.
|
||||
* The default is 100,000 microseconds (= 0.1 seconds).
|
||||
*/
|
||||
public int $lockRetryInterval = 100_000;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Lock Max Retries
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is used for RedisHandler.
|
||||
*
|
||||
* Maximum number of lock acquisition attempts.
|
||||
* The default is 300 times. That is lock timeout is about 30 (0.1 * 300)
|
||||
* seconds.
|
||||
*/
|
||||
public int $lockMaxRetries = 300;
|
||||
}
|
||||
147
app/Config/Toolbar.php
Normal file
147
app/Config/Toolbar.php
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Debug\Toolbar\Collectors\Database;
|
||||
use CodeIgniter\Debug\Toolbar\Collectors\Events;
|
||||
use CodeIgniter\Debug\Toolbar\Collectors\Files;
|
||||
use CodeIgniter\Debug\Toolbar\Collectors\Logs;
|
||||
use CodeIgniter\Debug\Toolbar\Collectors\Routes;
|
||||
use CodeIgniter\Debug\Toolbar\Collectors\Timers;
|
||||
use CodeIgniter\Debug\Toolbar\Collectors\Views;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Debug Toolbar
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The Debug Toolbar provides a way to see information about the performance
|
||||
* and state of your application during that page display. By default it will
|
||||
* NOT be displayed under production environments, and will only display if
|
||||
* `CI_DEBUG` is true, since if it's not, there's not much to display anyway.
|
||||
*/
|
||||
class Toolbar extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Toolbar Collectors
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* List of toolbar collectors that will be called when Debug Toolbar
|
||||
* fires up and collects data from.
|
||||
*
|
||||
* @var list<class-string>
|
||||
*/
|
||||
public array $collectors = [
|
||||
Timers::class,
|
||||
Database::class,
|
||||
Logs::class,
|
||||
Views::class,
|
||||
// \CodeIgniter\Debug\Toolbar\Collectors\Cache::class,
|
||||
Files::class,
|
||||
Routes::class,
|
||||
Events::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Collect Var Data
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If set to false var data from the views will not be collected. Useful to
|
||||
* avoid high memory usage when there are lots of data passed to the view.
|
||||
*/
|
||||
public bool $collectVarData = true;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Max History
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* `$maxHistory` sets a limit on the number of past requests that are stored,
|
||||
* helping to conserve file space used to store them. You can set it to
|
||||
* 0 (zero) to not have any history stored, or -1 for unlimited history.
|
||||
*/
|
||||
public int $maxHistory = 20;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Toolbar Views Path
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* The full path to the the views that are used by the toolbar.
|
||||
* This MUST have a trailing slash.
|
||||
*/
|
||||
public string $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Max Queries
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* If the Database Collector is enabled, it will log every query that the
|
||||
* the system generates so they can be displayed on the toolbar's timeline
|
||||
* and in the query log. This can lead to memory issues in some instances
|
||||
* with hundreds of queries.
|
||||
*
|
||||
* `$maxQueries` defines the maximum amount of queries that will be stored.
|
||||
*/
|
||||
public int $maxQueries = 100;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Watched Directories
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Contains an array of directories that will be watched for changes and
|
||||
* used to determine if the hot-reload feature should reload the page or not.
|
||||
* We restrict the values to keep performance as high as possible.
|
||||
*
|
||||
* NOTE: The ROOTPATH will be prepended to all values.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $watchedDirectories = [
|
||||
'app',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Watched File Extensions
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Contains an array of file extensions that will be watched for changes and
|
||||
* used to determine if the hot-reload feature should reload the page or not.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $watchedExtensions = [
|
||||
'php', 'css', 'js', 'html', 'svg', 'json', 'env',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Ignored HTTP Headers
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* CodeIgniter Debug Toolbar normally injects HTML and JavaScript into every
|
||||
* HTML response. This is correct for full page loads, but it breaks requests
|
||||
* that expect only a clean HTML fragment.
|
||||
*
|
||||
* Libraries like HTMX, Unpoly, and Hotwire (Turbo) update parts of the page or
|
||||
* manage navigation on the client side. Injecting the Debug Toolbar into their
|
||||
* responses can cause invalid HTML, duplicated scripts, or JavaScript errors
|
||||
* (such as infinite loops or "Maximum call stack size exceeded").
|
||||
*
|
||||
* Any request containing one of the following headers is treated as a
|
||||
* client-managed or partial request, and the Debug Toolbar injection is skipped.
|
||||
*
|
||||
* @var array<string, string|null>
|
||||
*/
|
||||
public array $disableOnHeaders = [
|
||||
'X-Requested-With' => 'xmlhttprequest', // AJAX requests
|
||||
'HX-Request' => 'true', // HTMX requests
|
||||
'X-Up-Version' => null, // Unpoly partial requests
|
||||
];
|
||||
}
|
||||
262
app/Config/UserAgents.php
Normal file
262
app/Config/UserAgents.php
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* User Agents
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* This file contains four arrays of user agent data. It is used by the
|
||||
* User Agent Class to help identify browser, platform, robot, and
|
||||
* mobile device data. The array keys are used to identify the device
|
||||
* and the array values are used to set the actual name of the item.
|
||||
*/
|
||||
class UserAgents extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* OS Platforms
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $platforms = [
|
||||
'windows nt 10.0' => 'Windows 10',
|
||||
'windows nt 6.3' => 'Windows 8.1',
|
||||
'windows nt 6.2' => 'Windows 8',
|
||||
'windows nt 6.1' => 'Windows 7',
|
||||
'windows nt 6.0' => 'Windows Vista',
|
||||
'windows nt 5.2' => 'Windows 2003',
|
||||
'windows nt 5.1' => 'Windows XP',
|
||||
'windows nt 5.0' => 'Windows 2000',
|
||||
'windows nt 4.0' => 'Windows NT 4.0',
|
||||
'winnt4.0' => 'Windows NT 4.0',
|
||||
'winnt 4.0' => 'Windows NT',
|
||||
'winnt' => 'Windows NT',
|
||||
'windows 98' => 'Windows 98',
|
||||
'win98' => 'Windows 98',
|
||||
'windows 95' => 'Windows 95',
|
||||
'win95' => 'Windows 95',
|
||||
'windows phone' => 'Windows Phone',
|
||||
'windows' => 'Unknown Windows OS',
|
||||
'android' => 'Android',
|
||||
'blackberry' => 'BlackBerry',
|
||||
'iphone' => 'iOS',
|
||||
'ipad' => 'iOS',
|
||||
'ipod' => 'iOS',
|
||||
'os x' => 'Mac OS X',
|
||||
'ppc mac' => 'Power PC Mac',
|
||||
'freebsd' => 'FreeBSD',
|
||||
'ppc' => 'Macintosh',
|
||||
'linux' => 'Linux',
|
||||
'debian' => 'Debian',
|
||||
'sunos' => 'Sun Solaris',
|
||||
'beos' => 'BeOS',
|
||||
'apachebench' => 'ApacheBench',
|
||||
'aix' => 'AIX',
|
||||
'irix' => 'Irix',
|
||||
'osf' => 'DEC OSF',
|
||||
'hp-ux' => 'HP-UX',
|
||||
'netbsd' => 'NetBSD',
|
||||
'bsdi' => 'BSDi',
|
||||
'openbsd' => 'OpenBSD',
|
||||
'gnu' => 'GNU/Linux',
|
||||
'unix' => 'Unknown Unix OS',
|
||||
'symbian' => 'Symbian OS',
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Browsers
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* The order of this array should NOT be changed. Many browsers return
|
||||
* multiple browser types so we want to identify the subtype first.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $browsers = [
|
||||
'OPR' => 'Opera',
|
||||
'Flock' => 'Flock',
|
||||
'Edge' => 'Spartan',
|
||||
'Edg' => 'Edge',
|
||||
'Chrome' => 'Chrome',
|
||||
// Opera 10+ always reports Opera/9.80 and appends Version/<real version> to the user agent string
|
||||
'Opera.*?Version' => 'Opera',
|
||||
'Opera' => 'Opera',
|
||||
'MSIE' => 'Internet Explorer',
|
||||
'Internet Explorer' => 'Internet Explorer',
|
||||
'Trident.* rv' => 'Internet Explorer',
|
||||
'Shiira' => 'Shiira',
|
||||
'Firefox' => 'Firefox',
|
||||
'Chimera' => 'Chimera',
|
||||
'Phoenix' => 'Phoenix',
|
||||
'Firebird' => 'Firebird',
|
||||
'Camino' => 'Camino',
|
||||
'Netscape' => 'Netscape',
|
||||
'OmniWeb' => 'OmniWeb',
|
||||
'Safari' => 'Safari',
|
||||
'Mozilla' => 'Mozilla',
|
||||
'Konqueror' => 'Konqueror',
|
||||
'icab' => 'iCab',
|
||||
'Lynx' => 'Lynx',
|
||||
'Links' => 'Links',
|
||||
'hotjava' => 'HotJava',
|
||||
'amaya' => 'Amaya',
|
||||
'IBrowse' => 'IBrowse',
|
||||
'Maxthon' => 'Maxthon',
|
||||
'Ubuntu' => 'Ubuntu Web Browser',
|
||||
'Vivaldi' => 'Vivaldi',
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Mobiles
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $mobiles = [
|
||||
// legacy array, old values commented out
|
||||
'mobileexplorer' => 'Mobile Explorer',
|
||||
// 'openwave' => 'Open Wave',
|
||||
// 'opera mini' => 'Opera Mini',
|
||||
// 'operamini' => 'Opera Mini',
|
||||
// 'elaine' => 'Palm',
|
||||
'palmsource' => 'Palm',
|
||||
// 'digital paths' => 'Palm',
|
||||
// 'avantgo' => 'Avantgo',
|
||||
// 'xiino' => 'Xiino',
|
||||
'palmscape' => 'Palmscape',
|
||||
// 'nokia' => 'Nokia',
|
||||
// 'ericsson' => 'Ericsson',
|
||||
// 'blackberry' => 'BlackBerry',
|
||||
// 'motorola' => 'Motorola'
|
||||
|
||||
// Phones and Manufacturers
|
||||
'motorola' => 'Motorola',
|
||||
'nokia' => 'Nokia',
|
||||
'palm' => 'Palm',
|
||||
'iphone' => 'Apple iPhone',
|
||||
'ipad' => 'iPad',
|
||||
'ipod' => 'Apple iPod Touch',
|
||||
'sony' => 'Sony Ericsson',
|
||||
'ericsson' => 'Sony Ericsson',
|
||||
'blackberry' => 'BlackBerry',
|
||||
'cocoon' => 'O2 Cocoon',
|
||||
'blazer' => 'Treo',
|
||||
'lg' => 'LG',
|
||||
'amoi' => 'Amoi',
|
||||
'xda' => 'XDA',
|
||||
'mda' => 'MDA',
|
||||
'vario' => 'Vario',
|
||||
'htc' => 'HTC',
|
||||
'samsung' => 'Samsung',
|
||||
'sharp' => 'Sharp',
|
||||
'sie-' => 'Siemens',
|
||||
'alcatel' => 'Alcatel',
|
||||
'benq' => 'BenQ',
|
||||
'ipaq' => 'HP iPaq',
|
||||
'mot-' => 'Motorola',
|
||||
'playstation portable' => 'PlayStation Portable',
|
||||
'playstation 3' => 'PlayStation 3',
|
||||
'playstation vita' => 'PlayStation Vita',
|
||||
'hiptop' => 'Danger Hiptop',
|
||||
'nec-' => 'NEC',
|
||||
'panasonic' => 'Panasonic',
|
||||
'philips' => 'Philips',
|
||||
'sagem' => 'Sagem',
|
||||
'sanyo' => 'Sanyo',
|
||||
'spv' => 'SPV',
|
||||
'zte' => 'ZTE',
|
||||
'sendo' => 'Sendo',
|
||||
'nintendo dsi' => 'Nintendo DSi',
|
||||
'nintendo ds' => 'Nintendo DS',
|
||||
'nintendo 3ds' => 'Nintendo 3DS',
|
||||
'wii' => 'Nintendo Wii',
|
||||
'open web' => 'Open Web',
|
||||
'openweb' => 'OpenWeb',
|
||||
|
||||
// Operating Systems
|
||||
'android' => 'Android',
|
||||
'symbian' => 'Symbian',
|
||||
'SymbianOS' => 'SymbianOS',
|
||||
'elaine' => 'Palm',
|
||||
'series60' => 'Symbian S60',
|
||||
'windows ce' => 'Windows CE',
|
||||
|
||||
// Browsers
|
||||
'obigo' => 'Obigo',
|
||||
'netfront' => 'Netfront Browser',
|
||||
'openwave' => 'Openwave Browser',
|
||||
'mobilexplorer' => 'Mobile Explorer',
|
||||
'operamini' => 'Opera Mini',
|
||||
'opera mini' => 'Opera Mini',
|
||||
'opera mobi' => 'Opera Mobile',
|
||||
'fennec' => 'Firefox Mobile',
|
||||
|
||||
// Other
|
||||
'digital paths' => 'Digital Paths',
|
||||
'avantgo' => 'AvantGo',
|
||||
'xiino' => 'Xiino',
|
||||
'novarra' => 'Novarra Transcoder',
|
||||
'vodafone' => 'Vodafone',
|
||||
'docomo' => 'NTT DoCoMo',
|
||||
'o2' => 'O2',
|
||||
|
||||
// Fallback
|
||||
'mobile' => 'Generic Mobile',
|
||||
'wireless' => 'Generic Mobile',
|
||||
'j2me' => 'Generic Mobile',
|
||||
'midp' => 'Generic Mobile',
|
||||
'cldc' => 'Generic Mobile',
|
||||
'up.link' => 'Generic Mobile',
|
||||
'up.browser' => 'Generic Mobile',
|
||||
'smartphone' => 'Generic Mobile',
|
||||
'cellphone' => 'Generic Mobile',
|
||||
];
|
||||
|
||||
/**
|
||||
* -------------------------------------------------------------------
|
||||
* Robots
|
||||
* -------------------------------------------------------------------
|
||||
*
|
||||
* There are hundred of bots but these are the most common.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $robots = [
|
||||
'googlebot' => 'Googlebot',
|
||||
'google-pagerenderer' => 'Google Page Renderer',
|
||||
'google-read-aloud' => 'Google Read Aloud',
|
||||
'google-safety' => 'Google Safety Bot',
|
||||
'msnbot' => 'MSNBot',
|
||||
'baiduspider' => 'Baiduspider',
|
||||
'bingbot' => 'Bing',
|
||||
'bingpreview' => 'BingPreview',
|
||||
'slurp' => 'Inktomi Slurp',
|
||||
'yahoo' => 'Yahoo',
|
||||
'ask jeeves' => 'Ask Jeeves',
|
||||
'fastcrawler' => 'FastCrawler',
|
||||
'infoseek' => 'InfoSeek Robot 1.0',
|
||||
'lycos' => 'Lycos',
|
||||
'yandex' => 'YandexBot',
|
||||
'mediapartners-google' => 'MediaPartners Google',
|
||||
'CRAZYWEBCRAWLER' => 'Crazy Webcrawler',
|
||||
'adsbot-google' => 'AdsBot Google',
|
||||
'feedfetcher-google' => 'Feedfetcher Google',
|
||||
'curious george' => 'Curious George',
|
||||
'ia_archiver' => 'Alexa Crawler',
|
||||
'MJ12bot' => 'Majestic-12',
|
||||
'Uptimebot' => 'Uptimebot',
|
||||
'duckduckbot' => 'DuckDuckBot',
|
||||
'sogou' => 'Sogou Spider',
|
||||
'exabot' => 'Exabot',
|
||||
'bot' => 'Generic Bot',
|
||||
'crawler' => 'Generic Crawler',
|
||||
'spider' => 'Generic Spider',
|
||||
];
|
||||
}
|
||||
83
app/Config/Validation.php
Normal file
83
app/Config/Validation.php
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Validation\StrictRules\CreditCardRules;
|
||||
use CodeIgniter\Validation\StrictRules\FileRules;
|
||||
use CodeIgniter\Validation\StrictRules\FormatRules;
|
||||
use CodeIgniter\Validation\StrictRules\Rules;
|
||||
use App\Validation\AbdmRules;
|
||||
|
||||
class Validation extends BaseConfig
|
||||
{
|
||||
// --------------------------------------------------------------------
|
||||
// Setup
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Stores the classes that contain the
|
||||
* rules that are available.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $ruleSets = [
|
||||
Rules::class,
|
||||
FormatRules::class,
|
||||
FileRules::class,
|
||||
CreditCardRules::class,
|
||||
AbdmRules::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Specifies the views that are used to display the
|
||||
* errors.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
public array $templates = [
|
||||
'list' => 'CodeIgniter\Validation\Views\list',
|
||||
'single' => 'CodeIgniter\Validation\Views\single',
|
||||
];
|
||||
|
||||
/**
|
||||
* Login validation rules for Shield.
|
||||
* Overrides the default email-based login rules.
|
||||
*
|
||||
* @var array<string, array<string, array<int, string>|string>>
|
||||
*/
|
||||
public array $login = [
|
||||
'username' => [
|
||||
'label' => 'Auth.username',
|
||||
'rules' => [
|
||||
'required',
|
||||
'max_length[30]',
|
||||
'min_length[3]',
|
||||
'regex_match[/\A[a-zA-Z0-9\.]+\z/]',
|
||||
],
|
||||
],
|
||||
'password' => [
|
||||
'label' => 'Auth.password',
|
||||
'rules' => ['required', 'max_byte[255]'],
|
||||
'errors' => [
|
||||
'max_byte' => 'Auth.errorPasswordTooLongBytes',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Rules
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* ABDM ABHA-related validation profiles.
|
||||
*
|
||||
* @var array<string, array<string, string>>
|
||||
*/
|
||||
public array $abhaAddress = [
|
||||
'abha_address' => [
|
||||
'label' => 'ABHA Address',
|
||||
'rules' => 'required|valid_abha_address',
|
||||
],
|
||||
];
|
||||
}
|
||||
79
app/Config/View.php
Normal file
79
app/Config/View.php
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\View as BaseView;
|
||||
use CodeIgniter\View\ViewDecoratorInterface;
|
||||
|
||||
/**
|
||||
* @phpstan-type parser_callable (callable(mixed): mixed)
|
||||
* @phpstan-type parser_callable_string (callable(mixed): mixed)&string
|
||||
*/
|
||||
class View extends BaseView
|
||||
{
|
||||
/**
|
||||
* When false, the view method will clear the data between each
|
||||
* call. This keeps your data safe and ensures there is no accidental
|
||||
* leaking between calls, so you would need to explicitly pass the data
|
||||
* to each view. You might prefer to have the data stick around between
|
||||
* calls so that it is available to all views. If that is the case,
|
||||
* set $saveData to true.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $saveData = true;
|
||||
|
||||
/**
|
||||
* Parser Filters map a filter name with any PHP callable. When the
|
||||
* Parser prepares a variable for display, it will chain it
|
||||
* through the filters in the order defined, inserting any parameters.
|
||||
* To prevent potential abuse, all filters MUST be defined here
|
||||
* in order for them to be available for use within the Parser.
|
||||
*
|
||||
* Examples:
|
||||
* { title|esc(js) }
|
||||
* { created_on|date(Y-m-d)|esc(attr) }
|
||||
*
|
||||
* @var array<string, string>
|
||||
* @phpstan-var array<string, parser_callable_string>
|
||||
*/
|
||||
public $filters = [];
|
||||
|
||||
/**
|
||||
* Parser Plugins provide a way to extend the functionality provided
|
||||
* by the core Parser by creating aliases that will be replaced with
|
||||
* any callable. Can be single or tag pair.
|
||||
*
|
||||
* @var array<string, callable|list<string>|string>
|
||||
* @phpstan-var array<string, list<parser_callable_string>|parser_callable_string|parser_callable>
|
||||
*/
|
||||
public $plugins = [];
|
||||
|
||||
/**
|
||||
* View Decorators are class methods that will be run in sequence to
|
||||
* have a chance to alter the generated output just prior to caching
|
||||
* the results.
|
||||
*
|
||||
* All classes must implement CodeIgniter\View\ViewDecoratorInterface
|
||||
*
|
||||
* @var list<class-string<ViewDecoratorInterface>>
|
||||
*/
|
||||
public array $decorators = [];
|
||||
|
||||
/**
|
||||
* Subdirectory within app/Views for namespaced view overrides.
|
||||
*
|
||||
* Namespaced views will be searched in:
|
||||
*
|
||||
* app/Views/{$appOverridesFolder}/{Namespace}/{view_path}.{php|html...}
|
||||
*
|
||||
* This allows application-level overrides for package or module views
|
||||
* without modifying vendor source files.
|
||||
*
|
||||
* Examples:
|
||||
* 'overrides' -> app/Views/overrides/Example/Blog/post/card.php
|
||||
* 'vendor' -> app/Views/vendor/Example/Blog/post/card.php
|
||||
* '' -> app/Views/Example/Blog/post/card.php (direct mapping)
|
||||
*/
|
||||
public string $appOverridesFolder = 'overrides';
|
||||
}
|
||||
50
app/Config/WorkerMode.php
Normal file
50
app/Config/WorkerMode.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
/**
|
||||
* This configuration controls how CodeIgniter behaves when running
|
||||
* in worker mode (with FrankenPHP).
|
||||
*/
|
||||
class WorkerMode
|
||||
{
|
||||
/**
|
||||
* Persistent Services
|
||||
*
|
||||
* List of service names that should persist across requests.
|
||||
* These services will NOT be reset between requests.
|
||||
*
|
||||
* Services not in this list will be reset for each request to prevent
|
||||
* state leakage.
|
||||
*
|
||||
* Recommended persistent services:
|
||||
* - `autoloader`: PSR-4 autoloading configuration
|
||||
* - `locator`: File locator
|
||||
* - `exceptions`: Exception handler
|
||||
* - `commands`: CLI commands registry
|
||||
* - `codeigniter`: Main application instance
|
||||
* - `superglobals`: Superglobals wrapper
|
||||
* - `routes`: Router configuration
|
||||
* - `cache`: Cache instance
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $persistentServices = [
|
||||
'autoloader',
|
||||
'locator',
|
||||
'exceptions',
|
||||
'commands',
|
||||
'codeigniter',
|
||||
'superglobals',
|
||||
'routes',
|
||||
'cache',
|
||||
];
|
||||
|
||||
/**
|
||||
* Force Garbage Collection
|
||||
*
|
||||
* Whether to force garbage collection after each request.
|
||||
* Helps prevent memory leaks at a small performance cost.
|
||||
*/
|
||||
public bool $forceGarbageCollection = true;
|
||||
}
|
||||
103
app/Controllers/BaseController.php
Normal file
103
app/Controllers/BaseController.php
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Libraries\ClinicalAuditTrail;
|
||||
use App\Libraries\FhirR4Builder;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* BaseController provides a convenient place for loading components
|
||||
* and performing functions that are needed by all your controllers.
|
||||
*
|
||||
* Extend this class in any new controllers:
|
||||
* ```
|
||||
* class Home extends BaseController
|
||||
* ```
|
||||
*
|
||||
* For security, be sure to declare any new methods as protected or private.
|
||||
*/
|
||||
abstract class BaseController extends Controller
|
||||
{
|
||||
protected $helpers = ['age', 'common'];
|
||||
|
||||
/**
|
||||
* Be sure to declare properties for any property fetch you initialized.
|
||||
* The creation of dynamic property is deprecated in PHP 8.2.
|
||||
*/
|
||||
|
||||
// protected $session;
|
||||
protected $db;
|
||||
protected ClinicalAuditTrail $clinicalAuditTrail;
|
||||
protected FhirR4Builder $fhirR4Builder;
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
|
||||
{
|
||||
// Load here all helpers you want to be available in your controllers that extend BaseController.
|
||||
// Caution: Do not put the this below the parent::initController() call below.
|
||||
// $this->helpers = ['form', 'url'];
|
||||
|
||||
// Caution: Do not edit this line.
|
||||
parent::initController($request, $response, $logger);
|
||||
|
||||
$this->db = db_connect();
|
||||
$this->clinicalAuditTrail = new ClinicalAuditTrail();
|
||||
$this->fhirR4Builder = new FhirR4Builder();
|
||||
$this->loadLegacyHospitalConstants();
|
||||
// Preload any models, libraries, etc, here.
|
||||
// $this->session = service('session');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int|null $recordId
|
||||
* @param string|int|null $userId
|
||||
* @param mixed $oldValue
|
||||
* @param mixed $newValue
|
||||
*/
|
||||
protected function auditClinicalUpdate(
|
||||
string $module,
|
||||
string $fieldName,
|
||||
$recordId,
|
||||
$oldValue,
|
||||
$newValue,
|
||||
$userId = null
|
||||
): void {
|
||||
if ($userId === null && function_exists('auth')) {
|
||||
$user = auth()->user();
|
||||
$userId = $user->id ?? null;
|
||||
}
|
||||
|
||||
$this->clinicalAuditTrail->logFieldUpdate($module, $recordId, $fieldName, $oldValue, $newValue, $userId);
|
||||
}
|
||||
|
||||
protected function loadLegacyHospitalConstants(): void
|
||||
{
|
||||
if (! $this->db || ! method_exists($this->db, 'tableExists') || ! $this->db->tableExists('hospital_setting')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$rows = $this->db->table('hospital_setting')
|
||||
->select('s_name, s_value')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$key = trim((string) ($row['s_name'] ?? ''));
|
||||
if ($key === '' || ! preg_match('/^[A-Za-z_][A-Za-z0-9_]*$/', $key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! defined($key)) {
|
||||
define($key, (string) ($row['s_value'] ?? ''));
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
1363
app/Controllers/Billing/CaseMaster.php
Normal file
1363
app/Controllers/Billing/CaseMaster.php
Normal file
File diff suppressed because it is too large
Load Diff
1020
app/Controllers/Billing/Charges.php
Normal file
1020
app/Controllers/Billing/Charges.php
Normal file
File diff suppressed because it is too large
Load Diff
942
app/Controllers/Billing/Ipd.php
Normal file
942
app/Controllers/Billing/Ipd.php
Normal file
|
|
@ -0,0 +1,942 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Billing;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\BedAssignmentHistoryModel;
|
||||
use App\Models\ItemIpdModel;
|
||||
use App\Models\IpdBillingModel;
|
||||
use App\Models\IpdModel;
|
||||
use App\Models\PaymentModel;
|
||||
|
||||
class Ipd extends BaseController
|
||||
{
|
||||
protected IpdBillingModel $ipdModel;
|
||||
protected BedAssignmentHistoryModel $bedAssignmentModel;
|
||||
protected ItemIpdModel $itemIpdModel;
|
||||
protected IpdModel $ipdEditModel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->ipdModel = new IpdBillingModel();
|
||||
$this->bedAssignmentModel = new BedAssignmentHistoryModel();
|
||||
$this->itemIpdModel = new ItemIpdModel();
|
||||
$this->ipdEditModel = new IpdModel();
|
||||
helper(['common', 'form', 'age']);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.access',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
return view('billing/ipd/dashboard');
|
||||
}
|
||||
|
||||
public function currentAdmission()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.current-admission',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$data['records'] = $this->ipdModel->getCurrentAdmissions();
|
||||
|
||||
return view('billing/ipd/current_admission', $data);
|
||||
}
|
||||
|
||||
public function ipdInvoices()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$data['ipdCode'] = (string) ($this->request->getGet('ipd_code') ?? '');
|
||||
|
||||
return view('billing/ipd/invoice_list', $data);
|
||||
}
|
||||
|
||||
public function getIpdTable()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$request = $this->request->getPost();
|
||||
$payload = $this->ipdModel->getIpdTableData($request);
|
||||
|
||||
return $this->response->setJSON($payload);
|
||||
}
|
||||
|
||||
public function cashBalance()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.cash-balance',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
return view('billing/ipd/cash_balance');
|
||||
}
|
||||
|
||||
public function cashBalanceReport()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.cash-balance',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$range = (string) ($this->request->getGet('range') ?? '');
|
||||
[$start, $end] = $this->parseDateRange($range);
|
||||
|
||||
$rows = $this->ipdModel->getCashBalanceReport($start, $end);
|
||||
$totals = $this->calculateCashBalanceTotals($rows);
|
||||
|
||||
return view('billing/ipd/cash_balance_table', [
|
||||
'rows' => $rows,
|
||||
'totals' => $totals,
|
||||
]);
|
||||
}
|
||||
|
||||
public function cashBalanceExport()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.export',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$range = (string) ($this->request->getGet('range') ?? '');
|
||||
[$start, $end] = $this->parseDateRange($range);
|
||||
|
||||
$rows = $this->ipdModel->getCashBalanceReport($start, $end);
|
||||
$totals = $this->calculateCashBalanceTotals($rows);
|
||||
|
||||
$content = view('billing/ipd/cash_balance_table', [
|
||||
'rows' => $rows,
|
||||
'totals' => $totals,
|
||||
]);
|
||||
|
||||
ExportExcel($content, 'IPD_Balance_List');
|
||||
|
||||
return $this->response->setBody('');
|
||||
}
|
||||
|
||||
public function panel(int $ipdId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$panelData = $this->ipdModel->getIpdPanelInfo($ipdId);
|
||||
if (empty($panelData)) {
|
||||
return $this->response->setStatusCode(404)->setBody('IPD not found');
|
||||
}
|
||||
|
||||
return view('billing/ipd/panel', $panelData);
|
||||
}
|
||||
|
||||
public function panelTab(int $ipdId, string $tab)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$panelData = $this->ipdModel->getIpdPanelInfo($ipdId);
|
||||
if (empty($panelData)) {
|
||||
return $this->response->setStatusCode(404)->setBody('IPD not found');
|
||||
}
|
||||
|
||||
if ($tab === 'admission') {
|
||||
return view('billing/ipd/panel_admission', $panelData);
|
||||
}
|
||||
|
||||
if ($tab === 'bed-assign') {
|
||||
$panelData['bed_assignments'] = $this->bedAssignmentModel->getByIpd($ipdId);
|
||||
|
||||
return view('billing/ipd/panel_bed_assign', $panelData);
|
||||
}
|
||||
|
||||
if ($tab === 'ipd-charges') {
|
||||
$panelData['ipd_charges_grouped'] = $this->ipdModel->getIpdChargesGrouped($ipdId);
|
||||
$panelData['ipd_charges_total'] = $this->ipdModel->getIpdChargesTotal($ipdId);
|
||||
$panelData['ipd_packages'] = $this->ipdModel->getIpdPackages($ipdId);
|
||||
|
||||
$caseMeta = $this->ipdModel->getIpdCaseMeta($ipdId);
|
||||
$insCompId = (int) ($caseMeta['insurance_id'] ?? 0);
|
||||
if ($insCompId <= 0) {
|
||||
$insCompId = 1;
|
||||
}
|
||||
|
||||
$panelData['ipd_insurance_id'] = $insCompId;
|
||||
$panelData['doc_list'] = $this->ipdModel->getIpdDoctorList();
|
||||
$panelData['item_types'] = $this->itemIpdModel->getItemTypes();
|
||||
|
||||
$itemLists = [];
|
||||
foreach ($panelData['item_types'] as $type) {
|
||||
$typeId = (int) ($type->itype_id ?? 0);
|
||||
if ($typeId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$itemLists[$typeId] = $this->itemIpdModel->getItemsByTypeWithInsurance($typeId, $insCompId);
|
||||
}
|
||||
$panelData['item_lists'] = $itemLists;
|
||||
|
||||
return view('billing/ipd/panel_ipd_charges', $panelData);
|
||||
}
|
||||
|
||||
if ($tab === 'package') {
|
||||
$panelData['ipd_packages'] = $this->ipdModel->getIpdPackages($ipdId);
|
||||
$caseMeta = $this->ipdModel->getIpdCaseMeta($ipdId);
|
||||
$insCompId = (int) ($caseMeta['insurance_id'] ?? 0);
|
||||
if ($insCompId <= 0) {
|
||||
$insCompId = 0;
|
||||
}
|
||||
$panelData['ipd_insurance_id'] = $insCompId;
|
||||
$panelData['package_list'] = $this->ipdModel->getPackageListForInsurance($insCompId);
|
||||
|
||||
return view('billing/ipd/panel_package', $panelData);
|
||||
}
|
||||
|
||||
if ($tab === 'diagnosis-charges') {
|
||||
$panelData['diagnosis_charges'] = $this->ipdModel->getDiagnosisCharges($ipdId);
|
||||
|
||||
return view('billing/ipd/panel_diagnosis', $panelData);
|
||||
}
|
||||
|
||||
if ($tab === 'payments') {
|
||||
$panelData['payments'] = $this->ipdModel->getPayments($ipdId);
|
||||
$panelData['medical_bills'] = $this->ipdModel->getMedicalBills($ipdId);
|
||||
|
||||
return view('billing/ipd/panel_payments', $panelData);
|
||||
}
|
||||
|
||||
if ($tab === 'medical-bills') {
|
||||
$panelData['medical_bills'] = $this->ipdModel->getMedicalBills($ipdId);
|
||||
|
||||
return view('billing/ipd/panel_medical_bills', $panelData);
|
||||
}
|
||||
|
||||
if ($tab === 'bill-details') {
|
||||
$panelData['ipd_packages'] = $this->ipdModel->getIpdPackages($ipdId);
|
||||
$panelData['ipd_invoice_items'] = $this->ipdModel->getIpdInvoiceItems(
|
||||
$ipdId,
|
||||
! empty($panelData['ipd_packages'])
|
||||
);
|
||||
$panelData['showinvoice'] = $this->ipdModel->getIpdInvoiceCharges($ipdId);
|
||||
$panelData['inv_med_list'] = $this->ipdModel->getIpdMedicalCredits($ipdId);
|
||||
$panelData['ipd_payment'] = $this->ipdModel->getPayments($ipdId);
|
||||
$panelData['insurance'] = $this->ipdModel->getIpdInsurance($ipdId);
|
||||
|
||||
$grossTotal = 0.0;
|
||||
foreach ($panelData['ipd_packages'] as $row) {
|
||||
$grossTotal += (float) ($row->package_Amount ?? 0);
|
||||
}
|
||||
foreach ($panelData['ipd_invoice_items'] as $row) {
|
||||
$grossTotal += (float) ($row->item_amount ?? 0);
|
||||
}
|
||||
foreach ($panelData['showinvoice'] as $row) {
|
||||
$grossTotal += (float) ($row->amount ?? 0);
|
||||
}
|
||||
foreach ($panelData['inv_med_list'] as $row) {
|
||||
$grossTotal += (float) ($row->net_amount ?? 0);
|
||||
}
|
||||
|
||||
$ipd = $panelData['ipd_info'] ?? null;
|
||||
$discountTotal = (float) ($ipd->Discount ?? 0) + (float) ($ipd->Discount2 ?? 0) + (float) ($ipd->Discount3 ?? 0);
|
||||
$extraCharge = (float) ($ipd->chargeamount1 ?? 0) + (float) ($ipd->chargeamount2 ?? 0);
|
||||
$netTotal = ($grossTotal + $extraCharge) - $discountTotal;
|
||||
|
||||
$panelData['bill_totals'] = [
|
||||
'gross' => $grossTotal,
|
||||
'net' => $netTotal,
|
||||
];
|
||||
|
||||
$totalPaid = 0.0;
|
||||
foreach ($panelData['ipd_payment'] as $row) {
|
||||
$amount = (float) ($row->amount ?? 0);
|
||||
$creditDebit = (int) ($row->credit_debit ?? 0);
|
||||
$totalPaid += $creditDebit === 0 ? $amount : $amount * -1;
|
||||
}
|
||||
$panelData['bill_totals']['paid'] = $totalPaid;
|
||||
$panelData['bill_totals']['balance'] = $netTotal - $totalPaid;
|
||||
|
||||
return view('billing/ipd/panel_bill_details', $panelData);
|
||||
}
|
||||
|
||||
if ($tab === 'discharge-process') {
|
||||
$panelData['discharge_info'] = $this->ipdModel->getDischargeInfo($ipdId);
|
||||
|
||||
return view('billing/ipd/panel_discharge', $panelData);
|
||||
}
|
||||
|
||||
return view('billing/ipd/panel_placeholder', [
|
||||
'title' => ucwords(str_replace('-', ' ', $tab)),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addIpdCharge(int $ipdId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$itemType = (int) ($this->request->getPost('item_type') ?? 0);
|
||||
$itemId = (int) ($this->request->getPost('item_id') ?? 0);
|
||||
$rate = (float) ($this->request->getPost('item_rate') ?? 0);
|
||||
$qty = (float) ($this->request->getPost('item_qty') ?? 1);
|
||||
$itemDate = (string) ($this->request->getPost('item_date') ?? date('Y-m-d'));
|
||||
$comment = (string) ($this->request->getPost('comment') ?? '');
|
||||
$docId = (int) ($this->request->getPost('doc_id') ?? 0);
|
||||
$referName = (string) ($this->request->getPost('refer_name') ?? '');
|
||||
|
||||
if ($itemType <= 0 || $itemId <= 0) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid item selection']);
|
||||
}
|
||||
|
||||
$itemRow = $this->itemIpdModel->getItemById($itemId);
|
||||
if (empty($itemRow)) {
|
||||
return $this->response->setStatusCode(404)->setJSON(['error' => 'Item not found']);
|
||||
}
|
||||
|
||||
$item = $itemRow[0];
|
||||
if ($rate <= 0) {
|
||||
$rate = (float) ($item->amount ?? 0);
|
||||
}
|
||||
|
||||
if ($qty <= 0) {
|
||||
$qty = 1;
|
||||
}
|
||||
|
||||
$caseMeta = $this->ipdModel->getIpdCaseMeta($ipdId);
|
||||
$insId = (int) ($caseMeta['insurance_id'] ?? 0);
|
||||
$orgCode = (string) ($caseMeta['org_code'] ?? '');
|
||||
|
||||
$docName = '';
|
||||
if ($docId > 0) {
|
||||
$docName = $this->ipdModel->getDoctorNameById($docId);
|
||||
} else {
|
||||
$docName = $referName;
|
||||
}
|
||||
|
||||
$amount = $rate * $qty;
|
||||
|
||||
$insertData = [
|
||||
'ipd_id' => $ipdId,
|
||||
'item_type' => $itemType,
|
||||
'item_id' => $itemId,
|
||||
'item_name' => (string) ($item->idesc ?? ''),
|
||||
'item_rate' => $rate,
|
||||
'item_added_date' => date('Y-m-d H:i:s'),
|
||||
'item_qty' => $qty,
|
||||
'item_amount' => $amount,
|
||||
'doc_id' => $docId,
|
||||
'doc_name' => $docName,
|
||||
'date_item' => $itemDate,
|
||||
'comment' => $comment,
|
||||
'ins_id' => $insId,
|
||||
'org_code' => $orgCode,
|
||||
];
|
||||
|
||||
$insertId = $this->ipdEditModel->insertIpdItem($insertData);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'ok' => $insertId > 0,
|
||||
'id' => $insertId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateIpdCharge(int $itemId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$qty = (float) ($this->request->getPost('item_qty') ?? 1);
|
||||
$rate = (float) ($this->request->getPost('item_rate') ?? 0);
|
||||
if ($qty <= 0) {
|
||||
$qty = 1;
|
||||
}
|
||||
|
||||
$amount = $rate * $qty;
|
||||
|
||||
$this->ipdEditModel->updateIpdItem([
|
||||
'item_qty' => $qty,
|
||||
'item_amount' => $amount,
|
||||
], $itemId);
|
||||
|
||||
return $this->response->setJSON(['ok' => true]);
|
||||
}
|
||||
|
||||
public function deleteIpdCharge(int $itemId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$result = $this->ipdEditModel->deleteIpdInvoiceItem($itemId);
|
||||
|
||||
return $this->response->setJSON(['ok' => $result === 1]);
|
||||
}
|
||||
|
||||
public function updateIpdChargePackage(int $itemId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$packageId = (int) ($this->request->getPost('package_id') ?? 0);
|
||||
|
||||
$this->ipdEditModel->updateIpdItem([
|
||||
'package_id' => $packageId,
|
||||
], $itemId);
|
||||
|
||||
return $this->response->setJSON(['ok' => true]);
|
||||
}
|
||||
|
||||
public function addIpdPackage(int $ipdId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$packageId = (int) ($this->request->getPost('package_id') ?? 0);
|
||||
$packageName = (string) ($this->request->getPost('package_name') ?? '');
|
||||
$comment = (string) ($this->request->getPost('comment') ?? '');
|
||||
$inputAmount = (float) ($this->request->getPost('input_amount') ?? 0);
|
||||
|
||||
$caseMeta = $this->ipdModel->getIpdCaseMeta($ipdId);
|
||||
$insCompId = (int) ($caseMeta['insurance_id'] ?? 0);
|
||||
if ($insCompId <= 0) {
|
||||
$insCompId = 0;
|
||||
}
|
||||
|
||||
$packageDesc = $comment;
|
||||
$amount = $inputAmount;
|
||||
$orgCode = '';
|
||||
|
||||
if ($packageId > 1) {
|
||||
$package = $this->ipdModel->getPackageWithInsurance($packageId, $insCompId);
|
||||
if ($package) {
|
||||
$packageName = (string) ($package->ipd_pakage_name ?? $packageName);
|
||||
$packageDesc = (string) ($package->Pakage_description ?? $packageDesc);
|
||||
$amount = (float) ($package->amount1 ?? $amount);
|
||||
$orgCode = (string) ($package->code ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
if ($inputAmount > 0) {
|
||||
$amount = $inputAmount;
|
||||
}
|
||||
|
||||
$userId = 0;
|
||||
$userName = 'system';
|
||||
if (function_exists('auth')) {
|
||||
$user = auth()->user();
|
||||
if ($user) {
|
||||
$userId = (int) ($user->id ?? 0);
|
||||
$userName = (string) ($user->username ?? $user->email ?? 'user');
|
||||
}
|
||||
}
|
||||
$updateBy = $userName . '[' . $userId . '] D:' . date('d-m-Y h:i:s');
|
||||
|
||||
$insertData = [
|
||||
'ipd_id' => $ipdId,
|
||||
'package_id' => $packageId,
|
||||
'package_name' => $packageName,
|
||||
'package_desc' => $packageDesc,
|
||||
'package_Amount' => $amount,
|
||||
'comment' => $comment,
|
||||
'update_by' => $updateBy,
|
||||
'ins_id' => $insCompId,
|
||||
'org_code' => $orgCode,
|
||||
];
|
||||
|
||||
$insertId = $this->ipdEditModel->insertPackage($insertData);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'ok' => $insertId > 0,
|
||||
'id' => $insertId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateIpdPackage(int $packageItemId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$amount = (float) ($this->request->getPost('input_amount') ?? 0);
|
||||
|
||||
$this->ipdEditModel->updatePackage([
|
||||
'package_Amount' => $amount,
|
||||
], $packageItemId);
|
||||
|
||||
return $this->response->setJSON(['ok' => true]);
|
||||
}
|
||||
|
||||
public function deleteIpdPackage(int $packageItemId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$result = $this->ipdEditModel->deletePackage($packageItemId);
|
||||
|
||||
return $this->response->setJSON(['ok' => $result === 1]);
|
||||
}
|
||||
|
||||
public function loadPaymentModal(int $ipdId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$panelData = $this->ipdModel->getIpdPanelInfo($ipdId);
|
||||
if (empty($panelData)) {
|
||||
return $this->response->setStatusCode(404)->setBody('IPD not found');
|
||||
}
|
||||
|
||||
$panelData['bank_data'] = $this->ipdModel->getBankPaymentSources();
|
||||
|
||||
return view('billing/ipd/ipd_model_payment_box', $panelData);
|
||||
}
|
||||
|
||||
public function loadDeductionModal(int $ipdId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
return view('billing/ipd/ipd_panel_deduction_payment', [
|
||||
'ipd_id' => $ipdId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function loadTpaPaymentModal(int $ipdId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$panelData = $this->ipdModel->getIpdPanelInfo($ipdId);
|
||||
if (empty($panelData)) {
|
||||
return $this->response->setStatusCode(404)->setBody('IPD not found');
|
||||
}
|
||||
|
||||
$panelData['ipd_id'] = $ipdId;
|
||||
|
||||
return view('billing/ipd/ipd_panel_tpa_payment', $panelData);
|
||||
}
|
||||
|
||||
public function confirmPayment()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$ipdId = (int) ($this->request->getPost('ipd_id') ?? 0);
|
||||
$amount = (float) ($this->request->getPost('amount') ?? 0);
|
||||
$mode = (int) ($this->request->getPost('mode') ?? 0);
|
||||
$paymentDate = (string) ($this->request->getPost('date_payment') ?? '');
|
||||
|
||||
if ($ipdId <= 0 || $amount <= 0) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['update' => 0, 'error_text' => 'Amount should be greater than zero.']);
|
||||
}
|
||||
|
||||
$ipdRow = $this->db->table('ipd_master')
|
||||
->select('id, ipd_code')
|
||||
->where('id', $ipdId)
|
||||
->get()
|
||||
->getRow();
|
||||
|
||||
if (! $ipdRow) {
|
||||
return $this->response->setStatusCode(404)->setJSON(['update' => 0, 'error_text' => 'IPD not found']);
|
||||
}
|
||||
|
||||
$userId = 0;
|
||||
$userName = 'system';
|
||||
if (function_exists('auth')) {
|
||||
$user = auth()->user();
|
||||
if ($user) {
|
||||
$userId = (int) ($user->id ?? 0);
|
||||
$userName = (string) ($user->username ?? $user->email ?? 'user');
|
||||
}
|
||||
}
|
||||
|
||||
$payDate = $paymentDate !== '' ? $paymentDate : date('Y-m-d');
|
||||
$payDatetime = $payDate . ' ' . date('H:i:s');
|
||||
$remark = (string) ($this->request->getPost('cash_remark') ?? '');
|
||||
|
||||
$paymentModel = new PaymentModel();
|
||||
|
||||
if ($mode === 1) {
|
||||
$insertId = $paymentModel->insertPayment([
|
||||
'payment_mode' => 1,
|
||||
'payof_type' => 4,
|
||||
'payof_id' => $ipdId,
|
||||
'payof_code' => $ipdRow->ipd_code ?? '',
|
||||
'credit_debit' => 0,
|
||||
'amount' => $amount,
|
||||
'payment_date' => $payDatetime,
|
||||
'remark' => $remark,
|
||||
'update_by' => $userName . '[' . $userId . ']',
|
||||
'update_by_id' => $userId,
|
||||
]);
|
||||
|
||||
$this->ipdEditModel->calculateIPD($ipdId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'ipd_id' => $ipdId,
|
||||
'payid' => $insertId,
|
||||
'pay_date' => $payDatetime,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($mode === 2) {
|
||||
$cardTran = (string) ($this->request->getPost('input_card_tran') ?? '');
|
||||
if ($cardTran === '') {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Card transaction ID is required.']);
|
||||
}
|
||||
|
||||
$insertId = $paymentModel->insertPayment([
|
||||
'payment_mode' => 2,
|
||||
'payof_type' => 4,
|
||||
'payof_id' => $ipdId,
|
||||
'payof_code' => $ipdRow->ipd_code ?? '',
|
||||
'credit_debit' => 0,
|
||||
'amount' => $amount,
|
||||
'payment_date' => $payDatetime,
|
||||
'remark' => $remark,
|
||||
'update_by' => $userName . '[' . $userId . ']',
|
||||
'pay_bank_id' => (int) ($this->request->getPost('cbo_pay_type') ?? 0),
|
||||
'card_tran_id' => $cardTran,
|
||||
'update_by_id' => $userId,
|
||||
]);
|
||||
|
||||
$this->ipdEditModel->calculateIPD($ipdId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'ipd_id' => $ipdId,
|
||||
'payid' => $insertId,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid payment mode.']);
|
||||
}
|
||||
|
||||
public function deductPayment()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$ipdId = (int) ($this->request->getPost('ipd_id') ?? 0);
|
||||
$amount = (float) ($this->request->getPost('amount') ?? 0);
|
||||
$mode = (int) ($this->request->getPost('mode') ?? 0);
|
||||
|
||||
if ($ipdId <= 0 || $amount <= 0) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['update' => 0, 'error_text' => 'Amount should be greater than zero.']);
|
||||
}
|
||||
|
||||
$ipdRow = $this->db->table('ipd_master')
|
||||
->select('id, ipd_code')
|
||||
->where('id', $ipdId)
|
||||
->get()
|
||||
->getRow();
|
||||
|
||||
if (! $ipdRow) {
|
||||
return $this->response->setStatusCode(404)->setJSON(['update' => 0, 'error_text' => 'IPD not found']);
|
||||
}
|
||||
|
||||
$userId = 0;
|
||||
$userName = 'system';
|
||||
if (function_exists('auth')) {
|
||||
$user = auth()->user();
|
||||
if ($user) {
|
||||
$userId = (int) ($user->id ?? 0);
|
||||
$userName = (string) ($user->username ?? $user->email ?? 'user');
|
||||
}
|
||||
}
|
||||
|
||||
$remark = (string) ($this->request->getPost('cash_remark') ?? '');
|
||||
$paymentModel = new PaymentModel();
|
||||
|
||||
if ($mode === 3 || $mode === 4) {
|
||||
$insertId = $paymentModel->insertPayment([
|
||||
'payment_mode' => $mode === 3 ? 1 : 2,
|
||||
'payof_type' => 4,
|
||||
'payof_id' => $ipdId,
|
||||
'payof_code' => $ipdRow->ipd_code ?? '',
|
||||
'credit_debit' => 1,
|
||||
'amount' => $amount,
|
||||
'payment_date' => date('Y-m-d H:i:s'),
|
||||
'remark' => $remark,
|
||||
'update_by' => $userName . '[' . $userId . ']',
|
||||
'update_by_id' => $userId,
|
||||
]);
|
||||
|
||||
$this->ipdEditModel->calculateIPD($ipdId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'ipd_id' => $ipdId,
|
||||
'payid' => $insertId,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid payment mode.']);
|
||||
}
|
||||
|
||||
public function tpaPayment()
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['update' => 0, 'show_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$ipdId = (int) ($this->request->getPost('hid_ipd_id') ?? 0);
|
||||
if ($ipdId <= 0) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['update' => 0, 'show_text' => 'Invalid IPD']);
|
||||
}
|
||||
|
||||
$payData = [
|
||||
'payable_by_tpa' => (float) ($this->request->getPost('input_payable_by_tpa') ?? 0),
|
||||
'discount_for_tpa' => (float) ($this->request->getPost('input_discount_for_tpa') ?? 0),
|
||||
'discount_by_hospital' => (float) ($this->request->getPost('input_discount_by_hospital') ?? 0),
|
||||
'discount_by_hospital_2' => (float) ($this->request->getPost('input_discount_by_hospital_2') ?? 0),
|
||||
'discount_by_hospital_remark' => (string) ($this->request->getPost('input_discount_by_hospital_remark') ?? ''),
|
||||
'discount_by_hospital_2_remark' => (string) ($this->request->getPost('input_discount_by_hospital_2_remark') ?? ''),
|
||||
];
|
||||
|
||||
$this->ipdEditModel->updateIpd($payData, $ipdId);
|
||||
$this->ipdEditModel->calculateIPD($ipdId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'ipd_id' => $ipdId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function ipdCashPrintPdf(int $ipdId, int $payId)
|
||||
{
|
||||
$permission = $this->requireAnyPermission([
|
||||
'billing.access',
|
||||
'billing.ipd.invoice',
|
||||
]);
|
||||
if ($permission) {
|
||||
return $permission;
|
||||
}
|
||||
|
||||
$payment = $this->db->table('payment_history')
|
||||
->select("*,date_format(payment_date,'%d-%m-%Y %h:%i %p') as payment_date_str,if(credit_debit=0,'','Return') as Amount_str", false)
|
||||
->where('payof_type', 4)
|
||||
->where('payof_id', $ipdId)
|
||||
->where('id', $payId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$ipdMaster = $this->db->table('ipd_master')
|
||||
->where('id', $ipdId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
if (empty($ipdMaster)) {
|
||||
return $this->response->setStatusCode(404)->setBody('IPD not found');
|
||||
}
|
||||
|
||||
$patient = $this->db->table('patient_master')
|
||||
->select("*,if(gender=1,'Male','Female') as xgender", false)
|
||||
->where('id', $ipdMaster[0]->p_id)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
return view('billing/ipd/ipd_payment_receipt_print', [
|
||||
'ipd_payment' => $payment,
|
||||
'ipd_master' => $ipdMaster,
|
||||
'patient_master' => $patient,
|
||||
'ipd_id' => $ipdId,
|
||||
'payid' => $payId,
|
||||
]);
|
||||
}
|
||||
|
||||
private function parseDateRange(string $range): array
|
||||
{
|
||||
$start = date('Y-m-d');
|
||||
$end = $start;
|
||||
|
||||
if ($range !== '') {
|
||||
$parts = explode('S', $range);
|
||||
if (count($parts) === 2) {
|
||||
$start = $parts[0];
|
||||
$end = $parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
return [$start, $end];
|
||||
}
|
||||
|
||||
private function calculateCashBalanceTotals(array $rows): array
|
||||
{
|
||||
$totalPaid = 0.0;
|
||||
$totalBalance = 0.0;
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$totalPaid += (float) ($row->sum_of_paid ?? 0);
|
||||
$totalBalance += (float) ($row->balance_amount ?? 0);
|
||||
}
|
||||
|
||||
return [
|
||||
'total_paid' => $totalPaid,
|
||||
'total_balance' => $totalBalance,
|
||||
];
|
||||
}
|
||||
|
||||
private function requireAnyPermission(array $permissions)
|
||||
{
|
||||
if (! function_exists('auth')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
if (! $user || ! method_exists($user, 'can')) {
|
||||
return $this->response->setStatusCode(403)->setBody('Access denied');
|
||||
}
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
if ($user->can($permission)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setStatusCode(403)->setBody('Access denied');
|
||||
}
|
||||
}
|
||||
1963
app/Controllers/Diagnosis.php
Normal file
1963
app/Controllers/Diagnosis.php
Normal file
File diff suppressed because it is too large
Load Diff
477
app/Controllers/Home.php
Normal file
477
app/Controllers/Home.php
Normal file
|
|
@ -0,0 +1,477 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Shield\Models\UserModel;
|
||||
|
||||
class Home extends BaseController
|
||||
{
|
||||
private function ensureAuthenticated()
|
||||
{
|
||||
if (function_exists('auth') && auth()->loggedIn()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(401)->setBody('Unauthorized');
|
||||
}
|
||||
|
||||
return redirect()->to(base_url('login'));
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$authRedirect = $this->ensureAuthenticated();
|
||||
if ($authRedirect !== null) {
|
||||
return $authRedirect;
|
||||
}
|
||||
|
||||
return view('welcome_message', [
|
||||
'initial_route' => base_url('dashboard'),
|
||||
'initial_title' => 'Dashboard',
|
||||
]);
|
||||
}
|
||||
|
||||
public function billing()
|
||||
{
|
||||
$authRedirect = $this->ensureAuthenticated();
|
||||
if ($authRedirect !== null) {
|
||||
return $authRedirect;
|
||||
}
|
||||
|
||||
$user = service('auth')->user();
|
||||
|
||||
return view('billing/main', ['user' => $user]);
|
||||
}
|
||||
|
||||
public function dashboard()
|
||||
{
|
||||
$authRedirect = $this->ensureAuthenticated();
|
||||
if ($authRedirect !== null) {
|
||||
return $authRedirect;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return view('welcome_message', [
|
||||
'initial_route' => base_url('dashboard'),
|
||||
'initial_title' => 'Dashboard',
|
||||
]);
|
||||
}
|
||||
|
||||
$user = service('auth')->user();
|
||||
$today = date('Y-m-d');
|
||||
$monthStart = date('Y-m-01');
|
||||
|
||||
$opdToday = $this->db->table('opd_master')
|
||||
->where('apointment_date', $today)
|
||||
->countAllResults();
|
||||
|
||||
$opdLast7Days = $this->db->table('opd_master')
|
||||
->where('apointment_date >=', date('Y-m-d', strtotime('-7 days')))
|
||||
->where('apointment_date <=', $today)
|
||||
->countAllResults();
|
||||
|
||||
$admitToday = $this->db->table('ipd_master')
|
||||
->where('register_date', $today)
|
||||
->countAllResults();
|
||||
|
||||
$dischargeToday = $this->db->table('ipd_master')
|
||||
->where('discharge_date', $today)
|
||||
->where('ipd_status', 1)
|
||||
->countAllResults();
|
||||
|
||||
$currentIpd = $this->db->table('ipd_master')
|
||||
->where('ipd_status', 0)
|
||||
->countAllResults();
|
||||
|
||||
$currentOrgIpd = $this->db->table('ipd_master i')
|
||||
->join('organization_case_master o', 'o.id = i.case_id', 'inner')
|
||||
->where('o.case_type', 1)
|
||||
->where('i.ipd_status', 0)
|
||||
->countAllResults();
|
||||
|
||||
$opdOrgList = $this->db->table('opd_master o')
|
||||
->select('ins.short_name as org_name')
|
||||
->select('COUNT(o.opd_id) as total_cases', false)
|
||||
->join('hc_insurance ins', 'ins.id = o.insurance_id', 'left')
|
||||
->where('o.apointment_date >=', $monthStart)
|
||||
->where('o.apointment_date <=', $today)
|
||||
->groupBy('ins.short_name')
|
||||
->orderBy('total_cases', 'DESC')
|
||||
->limit(10)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$opdDoctorList = $this->db->table('opd_master o')
|
||||
->select('o.doc_name')
|
||||
->select('COUNT(o.opd_id) as total_cases', false)
|
||||
->select("SUM(CASE WHEN (o.insurance_id IS NULL OR o.insurance_id <= 1) THEN 1 ELSE 0 END) as direct_cases", false)
|
||||
->select("SUM(CASE WHEN (o.insurance_id IS NULL OR o.insurance_id <= 1) THEN 0 ELSE 1 END) as org_cases", false)
|
||||
->where('o.apointment_date', $today)
|
||||
->where('o.doc_name IS NOT NULL', null, false)
|
||||
->where("o.doc_name != ''", null, false)
|
||||
->groupBy('o.doc_name')
|
||||
->orderBy('total_cases', 'DESC')
|
||||
->limit(12)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$ipdDoctorList = $this->db->table('ipd_master_doc_list l')
|
||||
->select('d.p_fname as doc_name')
|
||||
->select('COUNT(DISTINCT l.ipd_id) as total_cases', false)
|
||||
->join('doctor_master d', 'd.id = l.doc_id', 'inner')
|
||||
->join('ipd_master i', 'i.id = l.ipd_id', 'inner')
|
||||
->where('i.ipd_status', 0)
|
||||
->groupBy('d.p_fname')
|
||||
->orderBy('total_cases', 'DESC')
|
||||
->limit(12)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$ipdOrgList = $this->db->table('organization_case_master o')
|
||||
->select('ins.short_name as org_name')
|
||||
->select('COUNT(o.id) as total_cases', false)
|
||||
->join('ipd_master i', 'o.id = i.case_id', 'inner')
|
||||
->join('hc_insurance ins', 'ins.id = o.insurance_id', 'left')
|
||||
->where('o.case_type', 1)
|
||||
->where('i.ipd_status', 0)
|
||||
->groupBy('ins.short_name')
|
||||
->orderBy('total_cases', 'DESC')
|
||||
->limit(10)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$trendStart = $monthStart; // First day of current month
|
||||
$trendEnd = $today;
|
||||
$trendDays = [];
|
||||
|
||||
// Generate all days from start of month to today
|
||||
$startTime = strtotime($monthStart);
|
||||
$endTime = strtotime($today);
|
||||
$currentTime = $startTime;
|
||||
|
||||
while ($currentTime <= $endTime) {
|
||||
$trendDays[] = date('Y-m-d', $currentTime);
|
||||
$currentTime = strtotime('+1 day', $currentTime);
|
||||
}
|
||||
|
||||
$opdTrendRaw = $this->db->table('opd_master')
|
||||
->select("DATE_FORMAT(apointment_date, '%Y-%m-%d') as yd", false)
|
||||
->select('COUNT(opd_id) as total', false)
|
||||
->where('apointment_date >=', $trendStart)
|
||||
->where('apointment_date <=', $trendEnd)
|
||||
->groupBy('yd')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$ipdTrendRaw = $this->db->table('ipd_master')
|
||||
->select("DATE_FORMAT(register_date, '%Y-%m-%d') as yd", false)
|
||||
->select('COUNT(id) as total', false)
|
||||
->where('register_date >=', $trendStart)
|
||||
->where('register_date <=', $trendEnd)
|
||||
->groupBy('yd')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$opdTrendMap = [];
|
||||
foreach ($opdTrendRaw as $row) {
|
||||
$opdTrendMap[$row->yd] = (int) $row->total;
|
||||
}
|
||||
$ipdTrendMap = [];
|
||||
foreach ($ipdTrendRaw as $row) {
|
||||
$ipdTrendMap[$row->yd] = (int) $row->total;
|
||||
}
|
||||
|
||||
$opdTrend = [];
|
||||
$ipdTrend = [];
|
||||
$trendLabels = [];
|
||||
foreach ($trendDays as $dayKey) {
|
||||
$trendLabels[] = date('d M', strtotime($dayKey));
|
||||
$opdTrend[] = $opdTrendMap[$dayKey] ?? 0;
|
||||
$ipdTrend[] = $ipdTrendMap[$dayKey] ?? 0;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'user' => $user,
|
||||
'opd_today' => $opdToday,
|
||||
'opd_last_7_days' => $opdLast7Days,
|
||||
'admit_today' => $admitToday,
|
||||
'discharge_today' => $dischargeToday,
|
||||
'current_ipd' => $currentIpd,
|
||||
'current_org_ipd' => $currentOrgIpd,
|
||||
'opd_org_list' => $opdOrgList,
|
||||
'opd_doctor_list' => $opdDoctorList,
|
||||
'ipd_doctor_list' => $ipdDoctorList,
|
||||
'ipd_org_list' => $ipdOrgList,
|
||||
'trend_labels' => $trendLabels,
|
||||
'trend_opd' => $opdTrend,
|
||||
'trend_ipd' => $ipdTrend,
|
||||
'month_start' => $monthStart,
|
||||
];
|
||||
|
||||
return view('dashboard/index', $data);
|
||||
}
|
||||
|
||||
public function myProfile()
|
||||
{
|
||||
$authRedirect = $this->ensureAuthenticated();
|
||||
if ($authRedirect !== null) {
|
||||
return $authRedirect;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return view('welcome_message', [
|
||||
'initial_route' => base_url('my-profile'),
|
||||
'initial_title' => 'My Profile',
|
||||
]);
|
||||
}
|
||||
|
||||
$user = service('auth')->user();
|
||||
$meta = $this->getCurrentUserProfileMeta((int) ($user->id ?? 0));
|
||||
|
||||
return view('account/my_profile', [
|
||||
'user' => $user,
|
||||
'phone_no' => $meta['phone_no'] ?? '',
|
||||
'person_name' => $meta['full_name'] ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
public function myProfileSave()
|
||||
{
|
||||
$authRedirect = $this->ensureAuthenticated();
|
||||
if ($authRedirect !== null) {
|
||||
return $authRedirect;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Invalid request',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$authUser = service('auth')->user();
|
||||
$userId = (int) ($authUser->id ?? 0);
|
||||
if ($userId <= 0) {
|
||||
return $this->response->setStatusCode(401)->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Unauthorized',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$email = trim((string) $this->request->getPost('email'));
|
||||
$personName = trim((string) $this->request->getPost('person_name'));
|
||||
$phoneNo = trim((string) $this->request->getPost('phone_no'));
|
||||
$password = (string) $this->request->getPost('password');
|
||||
$passwordConfirm = (string) $this->request->getPost('password_confirm');
|
||||
|
||||
if ($personName !== '' && mb_strlen($personName) > 120) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Person name must be maximum 120 characters.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Valid email is required.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($phoneNo !== '' && preg_match('/^[0-9+\-()\s]{7,20}$/', $phoneNo) !== 1) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Phone format is invalid.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($password !== '' || $passwordConfirm !== '') {
|
||||
if (strlen($password) < 8) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Password must be at least 8 characters.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
if (! hash_equals($password, $passwordConfirm)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Password and confirm password do not match.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$tables = config('Auth')->tables;
|
||||
$identitiesTable = (string) ($tables['identities'] ?? 'auth_identities');
|
||||
|
||||
$duplicateEmail = $this->db->table($identitiesTable)
|
||||
->select('id')
|
||||
->where('type', 'email_password')
|
||||
->where('secret', $email)
|
||||
->where('user_id !=', $userId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
|
||||
if (! empty($duplicateEmail)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Email already used by another user.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$userModel = model(UserModel::class);
|
||||
$user = $userModel->find($userId);
|
||||
if ($user === null) {
|
||||
return $this->response->setStatusCode(404)->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'User not found',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$user->email = $email;
|
||||
if ($password !== '') {
|
||||
$user->password = $password;
|
||||
}
|
||||
|
||||
if (! $userModel->save($user)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Unable to update profile.',
|
||||
'errors' => $userModel->errors(),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->setCurrentUserProfileMeta($userId, $phoneNo, $personName);
|
||||
|
||||
$displayName = trim((string) ($user->username ?? ''));
|
||||
if ($personName !== '') {
|
||||
$displayName = $personName;
|
||||
} elseif ($displayName === '') {
|
||||
$displayName = trim((string) ($email !== '' ? $email : 'User'));
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'error_text' => 'Profile updated successfully.',
|
||||
'display_name' => $displayName,
|
||||
'person_name' => $personName,
|
||||
'login_id' => trim((string) ($user->username ?? '')),
|
||||
'user_id' => $userId,
|
||||
'email' => $email,
|
||||
'phone_no' => $phoneNo,
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{phone_no:string, full_name:string}
|
||||
*/
|
||||
private function getCurrentUserProfileMeta(int $userId): array
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return ['phone_no' => '', 'full_name' => ''];
|
||||
}
|
||||
|
||||
$tables = config('Auth')->tables;
|
||||
$identitiesTable = (string) ($tables['identities'] ?? 'auth_identities');
|
||||
if (! $this->db->tableExists($identitiesTable)) {
|
||||
return ['phone_no' => '', 'full_name' => ''];
|
||||
}
|
||||
|
||||
$row = $this->db->table($identitiesTable)
|
||||
->select('extra')
|
||||
->where('user_id', $userId)
|
||||
->where('type', 'email_password')
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
$extraRaw = trim((string) ($row['extra'] ?? ''));
|
||||
if ($extraRaw === '') {
|
||||
return ['phone_no' => '', 'full_name' => ''];
|
||||
}
|
||||
|
||||
$decoded = json_decode($extraRaw, true);
|
||||
if (! is_array($decoded)) {
|
||||
return ['phone_no' => '', 'full_name' => ''];
|
||||
}
|
||||
|
||||
return [
|
||||
'phone_no' => trim((string) ($decoded['phone_no'] ?? '')),
|
||||
'full_name' => trim((string) ($decoded['full_name'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
private function setCurrentUserProfileMeta(int $userId, string $phoneNo, string $fullName): void
|
||||
{
|
||||
if ($userId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$tables = config('Auth')->tables;
|
||||
$identitiesTable = (string) ($tables['identities'] ?? 'auth_identities');
|
||||
if (! $this->db->tableExists($identitiesTable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$row = $this->db->table($identitiesTable)
|
||||
->select('id,extra')
|
||||
->where('user_id', $userId)
|
||||
->where('type', 'email_password')
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
if (empty($row) || empty($row['id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payload = [];
|
||||
$raw = trim((string) ($row['extra'] ?? ''));
|
||||
if ($raw !== '') {
|
||||
$decoded = json_decode($raw, true);
|
||||
if (is_array($decoded)) {
|
||||
$payload = $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
if ($phoneNo === '') {
|
||||
unset($payload['phone_no']);
|
||||
} else {
|
||||
$payload['phone_no'] = $phoneNo;
|
||||
}
|
||||
|
||||
if ($fullName === '') {
|
||||
unset($payload['full_name']);
|
||||
} else {
|
||||
$payload['full_name'] = $fullName;
|
||||
}
|
||||
|
||||
$this->db->table($identitiesTable)
|
||||
->where('id', (int) $row['id'])
|
||||
->update([
|
||||
'extra' => empty($payload) ? null : json_encode($payload, JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
}
|
||||
}
|
||||
524
app/Controllers/Invoice.php
Normal file
524
app/Controllers/Invoice.php
Normal file
|
|
@ -0,0 +1,524 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\InvoiceModel;
|
||||
use App\Models\PaymentModel;
|
||||
|
||||
class Invoice extends BaseController
|
||||
{
|
||||
protected $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = db_connect();
|
||||
helper(['common', 'form']);
|
||||
}
|
||||
|
||||
public function list_req_payment()
|
||||
{
|
||||
return view('Invoice/payment_request_list');
|
||||
}
|
||||
|
||||
public function getRequestTable()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setBody('Invalid request');
|
||||
}
|
||||
|
||||
$requestData = $_REQUEST;
|
||||
|
||||
$columns = [
|
||||
0 => 'id',
|
||||
1 => 'org_code',
|
||||
2 => 'patient_name',
|
||||
3 => 'org_date_str',
|
||||
4 => 'payment_amount',
|
||||
5 => 'payment_process_str',
|
||||
];
|
||||
|
||||
$sqlAll = "select *,
|
||||
date_format(payment_request_datetime,'%d-%m-%Y %h:%i:%s') as org_date_str,
|
||||
(case payment_process when 0 then 'Pending' when 2 then 'Cancel' else 'Complete' end) as payment_process_str";
|
||||
|
||||
$sqlCount = 'Select count(*) as no_rec ';
|
||||
$sqlFrom = ' from org_payment_request ';
|
||||
|
||||
$totalSql = $sqlCount . $sqlFrom;
|
||||
$totalData = (int) ($this->db->query($totalSql)->getResult()[0]->no_rec ?? 0);
|
||||
$totalFiltered = $totalData;
|
||||
|
||||
$sqlWhere = ' WHERE 1 = 1';
|
||||
|
||||
if (! empty($requestData['columns'][0]['search']['value'])) {
|
||||
$idValueRaw = (string) $requestData['columns'][0]['search']['value'];
|
||||
$idValue = preg_replace('/\D+/', '', $idValueRaw);
|
||||
if ($idValue !== '') {
|
||||
$sqlWhere .= ' AND id like "%' . (int) $idValue . '%" ';
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][1]['search']['value'])) {
|
||||
$sqlWhere .= " AND org_code LIKE '%" . $requestData['columns'][1]['search']['value'] . "' ";
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][2]['search']['value'])) {
|
||||
$sqlWhere .= " AND ( patient_name LIKE '" . $requestData['columns'][2]['search']['value'] . "%' ) ";
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][4]['search']['value'])) {
|
||||
$sqlWhere .= " AND payment_amount LIKE '%" . $requestData['columns'][4]['search']['value'] . "%' ";
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][5]['search']['value'])) {
|
||||
$statusValue = strtolower(trim((string) $requestData['columns'][5]['search']['value']));
|
||||
if ($statusValue === 'pending') {
|
||||
$sqlWhere .= ' AND payment_process = 0 ';
|
||||
} elseif ($statusValue === 'cancel') {
|
||||
$sqlWhere .= ' AND payment_process = 2 ';
|
||||
} elseif ($statusValue === 'complete') {
|
||||
$sqlWhere .= ' AND payment_process > 0 AND payment_process <> 2 ';
|
||||
} else {
|
||||
$sqlWhere .= " AND (case payment_process when 0 then 'Pending' when 2 then 'Cancel' else 'Complete' end) LIKE '%" . $requestData['columns'][5]['search']['value'] . "%' ";
|
||||
}
|
||||
}
|
||||
|
||||
$totalFilterSql = $sqlCount . $sqlFrom . $sqlWhere;
|
||||
$totalFiltered = (int) ($this->db->query($totalFilterSql)->getResult()[0]->no_rec ?? 0);
|
||||
|
||||
$orderSql = ' ORDER BY ' . $columns[$requestData['order'][0]['column']] . ' ' . $requestData['order'][0]['dir']
|
||||
. ' LIMIT ' . $requestData['start'] . ' ,' . $requestData['length'];
|
||||
|
||||
$resultSql = $sqlAll . $sqlFrom . $sqlWhere . $orderSql;
|
||||
$rdata = $this->db->query($resultSql)->getResultArray();
|
||||
|
||||
$output = [
|
||||
'draw' => (int) $requestData['draw'],
|
||||
'recordsTotal' => $totalData,
|
||||
'recordsFiltered' => $totalFiltered,
|
||||
'data' => [],
|
||||
];
|
||||
|
||||
foreach ($rdata as $aRow) {
|
||||
$row = [];
|
||||
foreach ($columns as $col) {
|
||||
$row[] = $aRow[$col];
|
||||
}
|
||||
$output['data'][] = $row;
|
||||
}
|
||||
|
||||
return $this->response->setJSON($output);
|
||||
}
|
||||
|
||||
public function list_refund()
|
||||
{
|
||||
return view('Invoice/refund_invoice');
|
||||
}
|
||||
|
||||
public function getRefundTable()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setBody('Invalid request');
|
||||
}
|
||||
|
||||
$requestData = $_REQUEST;
|
||||
|
||||
$columns = [
|
||||
0 => 'id',
|
||||
1 => 'refund_type_code',
|
||||
2 => 'refund_type_str',
|
||||
3 => 'patient_name',
|
||||
4 => 'approved_datetime',
|
||||
5 => 'refund_amount',
|
||||
6 => 'refund_process_str',
|
||||
];
|
||||
|
||||
$sqlAll = "select *,
|
||||
(case refund_type when 1 then 'OPD' when 2 then 'Charge' when 3 then 'Org.Inv.' else 'Other' end) as refund_type_str,
|
||||
(case refund_process when 0 then 'Pending' when 2 then 'Cancel' else 'Complete' end) as refund_process_str";
|
||||
|
||||
$sqlCount = 'Select count(*) as no_rec ';
|
||||
$sqlFrom = ' from refund_order ';
|
||||
|
||||
$totalSql = $sqlCount . $sqlFrom;
|
||||
$totalData = (int) ($this->db->query($totalSql)->getResult()[0]->no_rec ?? 0);
|
||||
$totalFiltered = $totalData;
|
||||
|
||||
$sqlWhere = ' WHERE 1 = 1';
|
||||
|
||||
if (! empty($requestData['columns'][0]['search']['value'])) {
|
||||
$idValueRaw = (string) $requestData['columns'][0]['search']['value'];
|
||||
$idValue = preg_replace('/\D+/', '', $idValueRaw);
|
||||
if ($idValue !== '') {
|
||||
$sqlWhere .= ' AND id like "%' . (int) $idValue . '%" ';
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][1]['search']['value'])) {
|
||||
$sqlWhere .= " AND refund_type_code LIKE '%" . $requestData['columns'][1]['search']['value'] . "%' ";
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][2]['search']['value'])) {
|
||||
$typeValue = strtolower(trim((string) $requestData['columns'][2]['search']['value']));
|
||||
if ($typeValue === 'opd') {
|
||||
$sqlWhere .= ' AND refund_type = 1 ';
|
||||
} elseif ($typeValue === 'charge') {
|
||||
$sqlWhere .= ' AND refund_type = 2 ';
|
||||
} elseif ($typeValue === 'org.inv.' || $typeValue === 'org' || $typeValue === 'org.inv') {
|
||||
$sqlWhere .= ' AND refund_type = 3 ';
|
||||
} else {
|
||||
$sqlWhere .= " AND (case refund_type when 1 then 'OPD' when 2 then 'Charge' when 3 then 'Org.Inv.' else 'Other' end) LIKE '%" . $requestData['columns'][2]['search']['value'] . "%' ";
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][3]['search']['value'])) {
|
||||
$sqlWhere .= " AND ( patient_name LIKE '%" . $requestData['columns'][3]['search']['value'] . "%') ";
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][5]['search']['value'])) {
|
||||
$sqlWhere .= " AND refund_amount LIKE '%" . $requestData['columns'][5]['search']['value'] . "%' ";
|
||||
}
|
||||
|
||||
if (! empty($requestData['columns'][6]['search']['value'])) {
|
||||
$statusValue = strtolower(trim((string) $requestData['columns'][6]['search']['value']));
|
||||
if ($statusValue === 'pending') {
|
||||
$sqlWhere .= ' AND refund_process = 0 ';
|
||||
} elseif ($statusValue === 'cancel') {
|
||||
$sqlWhere .= ' AND refund_process = 2 ';
|
||||
} elseif ($statusValue === 'complete') {
|
||||
$sqlWhere .= ' AND refund_process > 0 AND refund_process <> 2 ';
|
||||
} else {
|
||||
$sqlWhere .= " AND (case refund_process when 0 then 'Pending' when 2 then 'Cancel' else 'Complete' end) LIKE '%" . $requestData['columns'][6]['search']['value'] . "%' ";
|
||||
}
|
||||
}
|
||||
|
||||
$totalFilterSql = $sqlCount . $sqlFrom . $sqlWhere;
|
||||
$totalFiltered = (int) ($this->db->query($totalFilterSql)->getResult()[0]->no_rec ?? 0);
|
||||
|
||||
$orderSql = ' ORDER BY ' . $columns[$requestData['order'][0]['column']] . ' ' . $requestData['order'][0]['dir']
|
||||
. ' LIMIT ' . $requestData['start'] . ' ,' . $requestData['length'];
|
||||
|
||||
$resultSql = $sqlAll . $sqlFrom . $sqlWhere . $orderSql;
|
||||
$rdata = $this->db->query($resultSql)->getResultArray();
|
||||
|
||||
$output = [
|
||||
'draw' => (int) $requestData['draw'],
|
||||
'recordsTotal' => $totalData,
|
||||
'recordsFiltered' => $totalFiltered,
|
||||
'data' => [],
|
||||
];
|
||||
|
||||
foreach ($rdata as $aRow) {
|
||||
$row = [];
|
||||
foreach ($columns as $col) {
|
||||
$row[] = $aRow[$col];
|
||||
}
|
||||
$output['data'][] = $row;
|
||||
}
|
||||
|
||||
return $this->response->setJSON($output);
|
||||
}
|
||||
|
||||
public function refund_form(int $refundId)
|
||||
{
|
||||
$refundOrder = $this->db->table('refund_order')
|
||||
->where('id', $refundId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
if (empty($refundOrder)) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
return view('Invoice/refund_amount_panel', [
|
||||
'refund_order' => $refundOrder,
|
||||
]);
|
||||
}
|
||||
|
||||
public function refund_process()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$refundId = (int) $this->request->getPost('r_id');
|
||||
|
||||
if ($refundId <= 0) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Invalid refund request',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$refundOrder = $this->db->table('refund_order')
|
||||
->where('id', $refundId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
if (empty($refundOrder)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'No Record Found',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
if ((int) $refundOrder[0]->refund_process > 0) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Already Done',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$refundType = (int) ($refundOrder[0]->refund_type ?? 0);
|
||||
$payofType = match ($refundType) {
|
||||
1 => '1',
|
||||
2 => '2',
|
||||
3 => '3',
|
||||
default => '0',
|
||||
};
|
||||
|
||||
$user = auth()->user();
|
||||
$userId = $user->id ?? '';
|
||||
$userName = $user->username ?? $user->email ?? 'User';
|
||||
$userLabel = $userName . '[' . $userId . ']';
|
||||
|
||||
$payData = [
|
||||
'payment_mode' => '1',
|
||||
'payof_type' => $payofType,
|
||||
'payof_id' => $refundOrder[0]->refund_type_id,
|
||||
'payof_code' => $refundOrder[0]->refund_type_code,
|
||||
'credit_debit' => '1',
|
||||
'amount' => $refundOrder[0]->refund_amount,
|
||||
'payment_date' => date('Y-m-d H:i:s'),
|
||||
'remark' => $refundOrder[0]->refund_type_reason,
|
||||
'update_by' => $userLabel,
|
||||
'update_by_id' => $userId,
|
||||
];
|
||||
|
||||
$paymentModel = new PaymentModel();
|
||||
$insertId = $paymentModel->insertPayment($payData);
|
||||
|
||||
if ($insertId <= 0) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Unable to process refund',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->table('refund_order')
|
||||
->where('id', $refundId)
|
||||
->update([
|
||||
'refund_process' => '1',
|
||||
'refund_by' => $userLabel,
|
||||
'refund_by_id' => $userId,
|
||||
'refund_datetime' => date('Y-m-d H:i:s'),
|
||||
'pay_id' => $insertId,
|
||||
]);
|
||||
|
||||
if ($refundType === 2) {
|
||||
$invoiceModel = new InvoiceModel();
|
||||
$invoiceModel->updateInvoiceFinal((int) $refundOrder[0]->refund_type_id);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'showcontent' => 'Refund Update',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function payment_form(int $reqId)
|
||||
{
|
||||
$reqPayment = $this->db->table('org_payment_request')
|
||||
->where('id', $reqId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
if (empty($reqPayment)) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$data['req_payment_order'] = $reqPayment;
|
||||
|
||||
$orgInfo = $this->db->table('organization_case_master')
|
||||
->where('id', (int) $reqPayment[0]->org_id)
|
||||
->get()
|
||||
->getResult();
|
||||
$data['org_info'] = $orgInfo;
|
||||
|
||||
$patientId = (int) $reqPayment[0]->patient_id;
|
||||
$personInfo = $this->db->table('patient_master')
|
||||
->where('id', $patientId)
|
||||
->get()
|
||||
->getResult();
|
||||
$this->applyAge($personInfo, 'age');
|
||||
$data['person_info'] = $personInfo;
|
||||
|
||||
$sql = "select s.id, s.pay_type, m.bank_name
|
||||
from hospital_bank m join hospital_bank_payment_source s on m.id=s.bank_id";
|
||||
$query = $this->db->query($sql);
|
||||
$data['bank_data'] = $query->getResult();
|
||||
|
||||
if ((int) $reqPayment[0]->payment_process > 0) {
|
||||
$printUrl = base_url('Invoice/print_org_payment_invoice') . '/' . $reqPayment[0]->id;
|
||||
$showcontent = 'Amount Receipt : <a href="' . $printUrl . '" target="_blank" class="btn btn-default"><i class="fa fa-print"></i> Print Payment Reciept</a> ';
|
||||
return $this->response->setBody($showcontent);
|
||||
}
|
||||
|
||||
return view('Invoice/payment_req_panel', $data);
|
||||
}
|
||||
|
||||
public function req_payment_process()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$mode = (string) $this->request->getPost('mode');
|
||||
$amount = (float) $this->request->getPost('amount');
|
||||
$reqPaymentId = (int) $this->request->getPost('req_payment_id');
|
||||
$cashRemark = (string) $this->request->getPost('cash_remark');
|
||||
|
||||
$payBankId = (int) $this->request->getPost('cbo_pay_type');
|
||||
$inputCardMac = (string) $this->request->getPost('input_card_mac');
|
||||
$inputCardBank = (string) $this->request->getPost('input_card_bank');
|
||||
$inputCardDigit = (string) $this->request->getPost('input_card_digit');
|
||||
$inputCardTran = (string) $this->request->getPost('input_card_tran');
|
||||
|
||||
$reqPayment = $this->db->table('org_payment_request')
|
||||
->where('id', $reqPaymentId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
if (empty($reqPayment)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'No Record Found',
|
||||
'payid' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
if ((int) $reqPayment[0]->payment_process > 0) {
|
||||
$printUrl = base_url('Invoice/print_org_payment_invoice') . '/' . $reqPaymentId;
|
||||
$showcontent = 'Already Done : <a href="' . $printUrl . '" target="_blank" class="btn btn-default"><i class="fa fa-print"></i> Print Invoice</a> ';
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => $showcontent,
|
||||
'payid' => (int) ($reqPayment[0]->pay_id ?? 0),
|
||||
]);
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$userId = $user->id ?? '';
|
||||
$userName = $user->username ?? $user->email ?? 'User';
|
||||
$userLabel = $userName . '[' . $userId . ']';
|
||||
|
||||
$payData = [
|
||||
'payment_mode' => $mode,
|
||||
'payof_type' => '3',
|
||||
'payof_id' => $reqPayment[0]->org_id,
|
||||
'payof_code' => $reqPayment[0]->org_code,
|
||||
'credit_debit' => '0',
|
||||
'amount' => $reqPayment[0]->payment_amount,
|
||||
'payment_date' => date('Y-m-d H:i:s'),
|
||||
'remark' => $cashRemark,
|
||||
'update_by' => $userLabel,
|
||||
'update_by_id' => $userId,
|
||||
'pay_bank_id' => $payBankId,
|
||||
'card_bank' => $inputCardMac,
|
||||
'card_remark' => $inputCardBank,
|
||||
'cust_card' => $inputCardDigit,
|
||||
'card_tran_id' => $inputCardTran,
|
||||
];
|
||||
|
||||
$paymentModel = new PaymentModel();
|
||||
$insertId = $paymentModel->insertPayment($payData);
|
||||
|
||||
if ($insertId > 0) {
|
||||
$this->db->table('org_payment_request')
|
||||
->where('id', $reqPaymentId)
|
||||
->update([
|
||||
'payment_process' => '1',
|
||||
'payment_accept_by' => $userLabel,
|
||||
'payment_accept_by_id' => $userId,
|
||||
'payment_datetime' => date('Y-m-d H:i:s'),
|
||||
'pay_id' => $insertId,
|
||||
]);
|
||||
|
||||
$printUrl = base_url('Invoice/print_org_payment_invoice') . '/' . $reqPaymentId;
|
||||
$showcontent = 'Amount Receipt : <a href="' . $printUrl . '" target="_blank" class="btn btn-default"><i class="fa fa-print"></i> Print Invoice</a> ';
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'showcontent' => $showcontent,
|
||||
'payid' => $insertId,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Unable to process payment.',
|
||||
'payid' => 0,
|
||||
]);
|
||||
}
|
||||
|
||||
public function print_org_payment_invoice(int $reqId)
|
||||
{
|
||||
$reqPayment = $this->db->table('org_payment_request')
|
||||
->where('id', $reqId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
if (empty($reqPayment)) {
|
||||
return $this->response->setStatusCode(404)->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$data['req_payment_order'] = $reqPayment;
|
||||
|
||||
$orgInfo = $this->db->table('organization_case_master')
|
||||
->where('id', (int) $reqPayment[0]->org_id)
|
||||
->get()
|
||||
->getResult();
|
||||
$data['org_info'] = $orgInfo;
|
||||
|
||||
$patientId = (int) $reqPayment[0]->patient_id;
|
||||
$patientMaster = $this->db->table('patient_master')
|
||||
->where('id', $patientId)
|
||||
->get()
|
||||
->getResult();
|
||||
$this->applyAge($patientMaster, 'age');
|
||||
$data['patient_master'] = $patientMaster;
|
||||
|
||||
$data['req_payment_order'][0]->payment_date_str = date('d-m-Y H:i:s', strtotime($reqPayment[0]->payment_datetime ?? 'now'));
|
||||
|
||||
return view('Invoice/Invoice_org_payment', $data);
|
||||
}
|
||||
|
||||
private function applyAge(array $rows, string $field = 'age'): void
|
||||
{
|
||||
foreach ($rows as $row) {
|
||||
$row->{$field} = get_age_1(
|
||||
$row->dob ?? null,
|
||||
$row->age ?? '',
|
||||
$row->age_in_month ?? '',
|
||||
$row->estimate_dob ?? ''
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
271
app/Controllers/Item.php
Normal file
271
app/Controllers/Item.php
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\ItemModel;
|
||||
|
||||
class Item extends BaseController
|
||||
{
|
||||
public function searchItemType(): string
|
||||
{
|
||||
$model = new ItemModel();
|
||||
|
||||
return view('Setting/Charges/OPD_Charges/item_type_search_v', [
|
||||
'data' => $model->getItemTypes(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchAdv(int $itypeId = 1): string
|
||||
{
|
||||
$model = new ItemModel();
|
||||
|
||||
return view('Setting/Charges/OPD_Charges/item_search_adv', [
|
||||
'data' => $model->getItemsByType($itypeId),
|
||||
'typeId' => $itypeId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(): string
|
||||
{
|
||||
$model = new ItemModel();
|
||||
$typeId = 1;
|
||||
|
||||
return view('Setting/Charges/OPD_Charges/item_search_V', [
|
||||
'labitemtype' => $model->getItemTypesList(),
|
||||
'data' => $model->getItemsByType($typeId),
|
||||
'typeId' => $typeId,
|
||||
'insurance_list' => $model->getInsuranceList(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchPrint(int $itypeId = 1): string
|
||||
{
|
||||
$model = new ItemModel();
|
||||
$insuranceId = (int) $this->request->getGet('insurance');
|
||||
$insurance = $insuranceId > 0 ? $model->getInsuranceById($insuranceId) : null;
|
||||
$data = $insuranceId > 0
|
||||
? $model->getItemsByTypeWithInsurance($itypeId, $insuranceId)
|
||||
: $model->getItemsByType($itypeId);
|
||||
|
||||
return view('Setting/Charges/OPD_Charges/item_item_list', [
|
||||
'data' => $data,
|
||||
'insuranceId' => $insuranceId,
|
||||
'insuranceName' => $insurance->ins_company_name ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
public function exportExcel(int $itypeId = 1)
|
||||
{
|
||||
$model = new ItemModel();
|
||||
$insuranceId = (int) $this->request->getGet('insurance');
|
||||
$insurance = $insuranceId > 0 ? $model->getInsuranceById($insuranceId) : null;
|
||||
$data = $insuranceId > 0
|
||||
? $model->getItemsByTypeWithInsurance($itypeId, $insuranceId)
|
||||
: $model->getItemsByType($itypeId);
|
||||
|
||||
$table = view('Setting/Charges/OPD_Charges/item_item_excel', [
|
||||
'data' => $data,
|
||||
'insuranceId' => $insuranceId,
|
||||
'insuranceName' => $insurance->ins_company_name ?? '',
|
||||
]);
|
||||
|
||||
$filename = 'OPD_Charges_' . date('dMy') . '.xls';
|
||||
|
||||
return $this->response
|
||||
->setHeader('Content-Type', 'application/vnd.ms-excel')
|
||||
->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
|
||||
->setHeader('Cache-Control', 'max-age=0, no-cache, no-store, must-revalidate')
|
||||
->setHeader('Pragma', 'no-cache')
|
||||
->setHeader('Expires', '0')
|
||||
->setBody($table);
|
||||
}
|
||||
|
||||
public function itemTypeRecord(int $id): string
|
||||
{
|
||||
$model = new ItemModel();
|
||||
|
||||
return view('Setting/Charges/OPD_Charges/item_type_profile', [
|
||||
'data_item' => $model->getItemTypeById($id),
|
||||
]);
|
||||
}
|
||||
|
||||
public function itemRecord(int $id): string
|
||||
{
|
||||
$model = new ItemModel();
|
||||
|
||||
return view('Setting/Charges/OPD_Charges/item_profile_V', [
|
||||
'data_item' => $model->getItemById($id),
|
||||
'data_item_type' => $model->getItemTypesList(),
|
||||
'data_insurance_item' => $model->getInsuranceItemList($id),
|
||||
'data_insurance' => $model->getInsuranceList(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
|
||||
$data = [
|
||||
'itype' => $this->request->getPost('Item_Type'),
|
||||
'idesc' => $this->request->getPost('input_Item_name'),
|
||||
'amount' => $this->request->getPost('input_amount'),
|
||||
'idesc_detail' => $this->request->getPost('input_Item_desc'),
|
||||
'update_date' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
$updated = $model->updateItem($data, $itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : '',
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addRecord(): string
|
||||
{
|
||||
$model = new ItemModel();
|
||||
|
||||
return view('Setting/Charges/OPD_Charges/item_create_V', [
|
||||
'data_item_type' => $model->getItemTypesList(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addItemTypeRecord(): string
|
||||
{
|
||||
return view('Setting/Charges/OPD_Charges/item_type_create');
|
||||
}
|
||||
|
||||
public function createRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemModel();
|
||||
$data = [
|
||||
'itype' => $this->request->getPost('Item_Type'),
|
||||
'idesc' => $this->request->getPost('input_Item_name'),
|
||||
'amount' => $this->request->getPost('input_amount'),
|
||||
'update_date' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertItem($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addInsuranceItemRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
|
||||
$data = [
|
||||
'hc_items_id' => $itemId,
|
||||
'hc_insurance_id' => $this->request->getPost('ins_company_name'),
|
||||
'amount1' => $this->request->getPost('input_amount'),
|
||||
'code' => $this->request->getPost('input_item_code'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertItemInsurance($data);
|
||||
$list = $model->getInsuranceItemList($itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'html' => view('Setting/Charges/OPD_Charges/item_insurance_list', [
|
||||
'data_insurance_item' => $list,
|
||||
]),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function removeInsuranceItem()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
$removeId = (int) $this->request->getPost('in_remove_id');
|
||||
|
||||
$deleted = $model->deleteItemInsurance($removeId);
|
||||
$list = $model->getInsuranceItemList($itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please Check',
|
||||
'html' => view('Setting/Charges/OPD_Charges/item_insurance_list', [
|
||||
'data_insurance_item' => $list,
|
||||
]),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createItemTypeRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemModel();
|
||||
$data = [
|
||||
'is_ipd_opd' => $this->request->getPost('Item_Type_ipd'),
|
||||
'group_desc' => $this->request->getPost('input_Item_type'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertItemType($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateItemTypeRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemModel();
|
||||
$itemTypeId = (int) $this->request->getPost('itemtype_id');
|
||||
|
||||
$data = [
|
||||
'is_ipd_opd' => $this->request->getPost('Item_Type_ipd'),
|
||||
'group_desc' => $this->request->getPost('input_Item_type'),
|
||||
];
|
||||
|
||||
$updated = $model->updateItemType($data, $itemTypeId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : '',
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
269
app/Controllers/ItemIpd.php
Normal file
269
app/Controllers/ItemIpd.php
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\ItemIpdModel;
|
||||
|
||||
class ItemIpd extends BaseController
|
||||
{
|
||||
public function searchItemType(): string
|
||||
{
|
||||
$model = new ItemIpdModel();
|
||||
|
||||
return view('Setting/Charges/IPD_Charges/item_type_search_v', [
|
||||
'data' => $model->getItemTypes(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchAdv(int $itypeId = 1): string
|
||||
{
|
||||
$model = new ItemIpdModel();
|
||||
|
||||
return view('Setting/Charges/IPD_Charges/item_search_adv', [
|
||||
'data' => $model->getItemsByType($itypeId),
|
||||
'typeId' => $itypeId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(): string
|
||||
{
|
||||
$model = new ItemIpdModel();
|
||||
$typeId = 1;
|
||||
|
||||
return view('Setting/Charges/IPD_Charges/item_search_V', [
|
||||
'labitemtype' => $model->getItemTypesList(),
|
||||
'data' => $model->getItemsByType($typeId),
|
||||
'typeId' => $typeId,
|
||||
'insurance_list' => $model->getInsuranceList(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchPrint(int $itypeId = 1): string
|
||||
{
|
||||
$model = new ItemIpdModel();
|
||||
$insuranceId = (int) $this->request->getGet('insurance');
|
||||
$insurance = $insuranceId > 0 ? $model->getInsuranceById($insuranceId) : null;
|
||||
$data = $insuranceId > 0
|
||||
? $model->getItemsByTypeWithInsurance($itypeId, $insuranceId)
|
||||
: $model->getItemsByType($itypeId);
|
||||
|
||||
return view('Setting/Charges/IPD_Charges/item_item_list', [
|
||||
'data' => $data,
|
||||
'insuranceId' => $insuranceId,
|
||||
'insuranceName' => $insurance->ins_company_name ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
public function exportExcel(int $itypeId = 1)
|
||||
{
|
||||
$model = new ItemIpdModel();
|
||||
$insuranceId = (int) $this->request->getGet('insurance');
|
||||
$insurance = $insuranceId > 0 ? $model->getInsuranceById($insuranceId) : null;
|
||||
$data = $insuranceId > 0
|
||||
? $model->getItemsByTypeWithInsurance($itypeId, $insuranceId)
|
||||
: $model->getItemsByType($itypeId);
|
||||
|
||||
$table = view('Setting/Charges/IPD_Charges/item_item_excel', [
|
||||
'data' => $data,
|
||||
'insuranceId' => $insuranceId,
|
||||
'insuranceName' => $insurance->ins_company_name ?? '',
|
||||
]);
|
||||
|
||||
$filename = 'IPD_Charges_' . date('dMy') . '.xls';
|
||||
|
||||
return $this->response
|
||||
->setHeader('Content-Type', 'application/vnd.ms-excel')
|
||||
->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
|
||||
->setHeader('Cache-Control', 'max-age=0, no-cache, no-store, must-revalidate')
|
||||
->setHeader('Pragma', 'no-cache')
|
||||
->setHeader('Expires', '0')
|
||||
->setBody($table);
|
||||
}
|
||||
|
||||
public function itemTypeRecord(int $id): string
|
||||
{
|
||||
$model = new ItemIpdModel();
|
||||
|
||||
return view('Setting/Charges/IPD_Charges/item_type_profile', [
|
||||
'data_item' => $model->getItemTypeById($id),
|
||||
]);
|
||||
}
|
||||
|
||||
public function itemRecord(int $id): string
|
||||
{
|
||||
$model = new ItemIpdModel();
|
||||
|
||||
return view('Setting/Charges/IPD_Charges/item_profile_V', [
|
||||
'data_item' => $model->getItemById($id),
|
||||
'data_item_type' => $model->getItemTypesList(),
|
||||
'data_insurance_item' => $model->getInsuranceItemList($id),
|
||||
'data_insurance' => $model->getInsuranceList(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemIpdModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
|
||||
$data = [
|
||||
'itype' => $this->request->getPost('Item_Type'),
|
||||
'idesc' => $this->request->getPost('input_Item_name'),
|
||||
'amount' => $this->request->getPost('input_amount'),
|
||||
'idesc_detail' => $this->request->getPost('input_Item_desc'),
|
||||
'update_date' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
$updated = $model->updateItem($data, $itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : '',
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addRecord(): string
|
||||
{
|
||||
$model = new ItemIpdModel();
|
||||
|
||||
return view('Setting/Charges/IPD_Charges/item_create_V', [
|
||||
'data_item_type' => $model->getItemTypesList(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addItemTypeRecord(): string
|
||||
{
|
||||
return view('Setting/Charges/IPD_Charges/item_type_create');
|
||||
}
|
||||
|
||||
public function createRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemIpdModel();
|
||||
$data = [
|
||||
'itype' => $this->request->getPost('Item_Type'),
|
||||
'idesc' => $this->request->getPost('input_Item_name'),
|
||||
'amount' => $this->request->getPost('input_amount'),
|
||||
'update_date' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertItem($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addInsuranceItemRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemIpdModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
|
||||
$data = [
|
||||
'hc_items_id' => $itemId,
|
||||
'hc_insurance_id' => $this->request->getPost('ins_company_name'),
|
||||
'amount1' => $this->request->getPost('input_amount'),
|
||||
'code' => $this->request->getPost('input_item_code'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertItemInsurance($data);
|
||||
$list = $model->getInsuranceItemList($itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'html' => view('Setting/Charges/IPD_Charges/item_insurance_list', [
|
||||
'data_insurance_item' => $list,
|
||||
]),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function removeInsuranceItem()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemIpdModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
$removeId = (int) $this->request->getPost('in_remove_id');
|
||||
|
||||
$deleted = $model->deleteItemInsurance($removeId);
|
||||
$list = $model->getInsuranceItemList($itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please Check',
|
||||
'html' => view('Setting/Charges/IPD_Charges/item_insurance_list', [
|
||||
'data_insurance_item' => $list,
|
||||
]),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createItemTypeRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemIpdModel();
|
||||
$data = [
|
||||
'group_desc' => $this->request->getPost('input_Item_type'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertItemType($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateItemTypeRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new ItemIpdModel();
|
||||
$itemTypeId = (int) $this->request->getPost('itemtype_id');
|
||||
|
||||
$data = [
|
||||
'group_desc' => $this->request->getPost('input_Item_type'),
|
||||
];
|
||||
|
||||
$updated = $model->updateItemType($data, $itemTypeId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : '',
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
10932
app/Controllers/Medical.php
Normal file
10932
app/Controllers/Medical.php
Normal file
File diff suppressed because it is too large
Load Diff
397
app/Controllers/OcasePathLap.php
Normal file
397
app/Controllers/OcasePathLap.php
Normal file
|
|
@ -0,0 +1,397 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\InvoiceModel;
|
||||
use App\Models\PaymentModel;
|
||||
|
||||
class OcasePathLap extends BaseController
|
||||
{
|
||||
protected $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = db_connect();
|
||||
helper(['common', 'form']);
|
||||
}
|
||||
|
||||
public function list_pathtest_bytype()
|
||||
{
|
||||
$typeId = (int) $this->request->getPost('itype_idv');
|
||||
$insId = (int) $this->request->getPost('ins_id');
|
||||
|
||||
if ($insId > 1) {
|
||||
$sql = 'select id,Concat(idesc,\' : [\',amount1,\']\',if(hc_insurance_id=0,\'\',\'-INS\')) as sdesc from v_hc_items_with_insurance '
|
||||
. 'where itype=' . $typeId . ' and hc_insurance_id in (0,' . $insId . ') order by idesc';
|
||||
} else {
|
||||
$sql = 'select id,Concat(idesc,\' : [\',amount,\']\') as sdesc from hc_items where itype=' . $typeId . ' order by idesc';
|
||||
}
|
||||
|
||||
$labitem = $this->db->query($sql)->getResult();
|
||||
|
||||
$html = '<div class="form-group">\n<label>Charge Code</label>';
|
||||
$html .= '<select class="form-control" id="itype_name_id" name="itype_name_id">';
|
||||
foreach ($labitem as $row) {
|
||||
$html .= '<option value=' . $row->id . '>' . $row->sdesc . '</option>';
|
||||
}
|
||||
$html .= '</select></div>';
|
||||
|
||||
return $this->response->setBody($html);
|
||||
}
|
||||
|
||||
public function get_echs_id()
|
||||
{
|
||||
$srNo = (string) $this->request->getPost('input_charge_code');
|
||||
$typeId = (int) $this->request->getPost('itype_idv');
|
||||
|
||||
$row = $this->db->table('hc_items')
|
||||
->where('itype', $typeId)
|
||||
->where('echs_sr_no', $srNo)
|
||||
->get()
|
||||
->getRow();
|
||||
|
||||
return $this->response->setBody($row ? (string) $row->id : '0');
|
||||
}
|
||||
|
||||
public function update_refer_doc()
|
||||
{
|
||||
$invoiceId = (int) $this->request->getPost('inv_id');
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$referName = '';
|
||||
|
||||
if ($docId < 1) {
|
||||
$referName = (string) $this->request->getPost('refername');
|
||||
} else {
|
||||
$doc = $this->db->table('doctor_master')->where('id', $docId)->get()->getRow();
|
||||
$referName = $doc->p_fname ?? '';
|
||||
}
|
||||
|
||||
$this->db->table('invoice_master')
|
||||
->where('id', $invoiceId)
|
||||
->update([
|
||||
'refer_by_id' => $docId,
|
||||
'refer_by_other' => $referName,
|
||||
]);
|
||||
|
||||
return $this->response->setStatusCode(204);
|
||||
}
|
||||
|
||||
public function showinvoice(int $invoiceId)
|
||||
{
|
||||
$sql = 'select i.*,t.desc from invoice_item i join hc_item_type t on i.item_type=t.itype_id where i.inv_master_id=' . $invoiceId;
|
||||
$data['invoiceDetails'] = $this->db->query($sql)->getResult();
|
||||
|
||||
$data['invoiceGtotal'] = $this->db->table('invoice_item')
|
||||
->selectSum('item_amount', 'Gtotal')
|
||||
->where('inv_master_id', $invoiceId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$data['invoice_master'] = $this->db->table('invoice_master')
|
||||
->where('id', $invoiceId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
if (empty($data['invoice_master'])) {
|
||||
return $this->response->setStatusCode(404)->setBody('Invoice not found');
|
||||
}
|
||||
|
||||
$sql = 'select *,if(gender=1,\'Male\',\'Female\') as xgender from patient_master where id=' . (int) $data['invoice_master'][0]->attach_id;
|
||||
$data['patient_master'] = $this->db->query($sql)->getResult();
|
||||
$this->applyAge($data['patient_master']);
|
||||
|
||||
$insCompId = (int) $data['invoice_master'][0]->insurance_id;
|
||||
$insId = (int) $data['invoice_master'][0]->insurance_card_id;
|
||||
|
||||
$data['hc_insurance_card'] = $this->db->table('hc_insurance_card')->where('id', $insId)->get()->getResult();
|
||||
$data['insurance'] = $this->db->table('hc_insurance')->where('id', $insCompId)->get()->getResult();
|
||||
|
||||
$data['ipd_master'] = $this->db->table('ipd_master')
|
||||
->where('ipd_status', 0)
|
||||
->where('p_id', (int) $data['invoice_master'][0]->attach_id)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$data['case_master'] = $this->db->table('organization_case_master')
|
||||
->where('status', 0)
|
||||
->where('p_id', (int) $data['invoice_master'][0]->attach_id)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$data['payment_history'] = $this->db->query('select sum(if(credit_debit>0,amount*-1,amount)) as paid_amount from payment_history where payof_type=2 and payof_id=' . $invoiceId)->getResult();
|
||||
|
||||
$discountAmount = (float) $data['invoice_master'][0]->discount_amount;
|
||||
$totalAmount = (float) ($data['invoiceGtotal'][0]->Gtotal ?? 0);
|
||||
$netAmount = $totalAmount - $discountAmount;
|
||||
$paidAmount = (float) ($data['payment_history'][0]->paid_amount ?? 0);
|
||||
$balanceAmount = $netAmount - $paidAmount;
|
||||
$paymentPart = $balanceAmount > 0 ? 1 : 0;
|
||||
|
||||
$invoiceModel = new InvoiceModel();
|
||||
$invoiceModel->updateInvoice([
|
||||
'total_amount' => $totalAmount,
|
||||
'net_amount' => $netAmount,
|
||||
'payment_part_received' => $paidAmount,
|
||||
'payment_part_balance' => $balanceAmount,
|
||||
'payment_part' => $paymentPart,
|
||||
], $invoiceId);
|
||||
|
||||
$data['invoice_master'] = $this->db->table('invoice_master')->where('id', $invoiceId)->get()->getResult();
|
||||
|
||||
return view('Invoice/Organization_Invoice_PathLab_final_V', $data);
|
||||
}
|
||||
|
||||
public function showitem(int $type)
|
||||
{
|
||||
$invoiceId = (int) $this->request->getPost('lab_invoice_id');
|
||||
|
||||
if ($type > 0) {
|
||||
$insId = (int) $this->request->getPost('ins_id');
|
||||
$itemId = (int) $this->request->getPost('itype_name_id');
|
||||
|
||||
if ($insId > 1) {
|
||||
$sql = 'select id,Concat(idesc,\' : [\',amount1,\']\',if(hc_insurance_id=0,\'\',\'-INS\')) as sdesc,amount1 from v_hc_items_with_insurance '
|
||||
. 'where id=' . $itemId . ' and hc_insurance_id in (0,' . $insId . ')';
|
||||
} else {
|
||||
$sql = 'select id,Concat(idesc,\' : [\',amount,\']\') as sdesc,amount from hc_items where id=' . $itemId;
|
||||
}
|
||||
|
||||
$itemlist = $this->db->query($sql)->getResult();
|
||||
$itemRate = $insId > 1 ? (float) $itemlist[0]->amount1 : (float) $itemlist[0]->amount;
|
||||
$qty = (float) $this->request->getPost('input_qty');
|
||||
$amountValue = $qty * $itemRate;
|
||||
|
||||
$invoiceModel = new InvoiceModel();
|
||||
$invoiceModel->addInvoiceItem([
|
||||
'inv_master_id' => $invoiceId,
|
||||
'item_type' => (int) $this->request->getPost('itype_idv'),
|
||||
'item_id' => $itemId,
|
||||
'item_name' => $itemlist[0]->sdesc,
|
||||
'item_rate' => $itemRate,
|
||||
'item_added_date' => str_to_MysqlDate(date('d/m/Y')),
|
||||
'item_qty' => $qty,
|
||||
'item_amount' => $amountValue,
|
||||
]);
|
||||
} else {
|
||||
$itemId = (int) $this->request->getPost('itemid');
|
||||
$this->db->table('invoice_item')->where('id', $itemId)->delete();
|
||||
}
|
||||
|
||||
$sql = 'select i.*,t.desc from invoice_item i join hc_item_type t on i.item_type=t.itype_id where i.inv_master_id=' . $invoiceId;
|
||||
$invoiceDetails = $this->db->query($sql)->getResult();
|
||||
|
||||
$invoiceGtotal = $this->db->table('invoice_item')
|
||||
->selectSum('item_amount', 'Gtotal')
|
||||
->where('inv_master_id', $invoiceId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$html = '<table class="table table-striped ">';
|
||||
$html .= '<tr><th style="width: 10px">#</th><th>Item Group</th><th>Charge Name</th><th>Rate</th><th>Qty</th><th>Amount</th><th></th></tr>';
|
||||
|
||||
$srno = 0;
|
||||
foreach ($invoiceDetails as $row) {
|
||||
$srno++;
|
||||
$html .= '<tr>';
|
||||
$html .= '<td>' . $srno . '</td>';
|
||||
$html .= '<td>' . $row->desc . '</td>';
|
||||
$html .= '<td>' . $row->item_name . '</td>';
|
||||
$html .= '<td>' . $row->item_rate . '</td>';
|
||||
$html .= '<td>' . $row->item_qty . '</td>';
|
||||
$html .= '<td>' . $row->item_amount . '</td>';
|
||||
$html .= '<td><button type="button" class="btn btn-danger" id="btn_add_fee" onclick="remove_item_invoice(' . $row->id . ')">-Remove</button></td>';
|
||||
$html .= '</tr>';
|
||||
}
|
||||
|
||||
$html .= '<input type="hidden" id="srno" name="srno" value="' . $srno . '" />';
|
||||
$html .= '<tr><th style="width: 10px">#</th><th></th><th></th><th></th><th>Gross Total</th><th>' . ($invoiceGtotal[0]->Gtotal ?? 0) . '</th><th></th></tr>';
|
||||
$html .= '</table>';
|
||||
|
||||
return $this->response->setBody($html);
|
||||
}
|
||||
|
||||
public function confirm_payment()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setBody('Invalid request');
|
||||
}
|
||||
|
||||
$invoiceId = (int) $this->request->getPost('lab_invoice_id');
|
||||
$mode = (int) $this->request->getPost('mode');
|
||||
$amountPaid = (float) $this->request->getPost('input_amount_paid');
|
||||
|
||||
$invMaster = $this->db->table('invoice_master')->where('id', $invoiceId)->get()->getRow();
|
||||
if (! $invMaster) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invoice not found']);
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$userId = $user->id ?? '';
|
||||
$userName = $user->username ?? $user->email ?? 'User';
|
||||
|
||||
$payRemark = '';
|
||||
if ((float) ($invMaster->discount_amount ?? 0) > 0) {
|
||||
$payRemark = 'Dis.Amt.:' . ($invMaster->discount_desc ?? '') . ' /Amount: ' . ($invMaster->discount_amount ?? 0) . '/Update:' . ($invMaster->disc_update_by ?? '');
|
||||
}
|
||||
|
||||
$paymentModel = new PaymentModel();
|
||||
$invoiceModel = new InvoiceModel();
|
||||
|
||||
if ($mode === 1) {
|
||||
$payData = [
|
||||
'payment_mode' => 1,
|
||||
'payof_type' => 2,
|
||||
'payof_id' => $invoiceId,
|
||||
'payof_code' => $invMaster->invoice_code ?? '',
|
||||
'credit_debit' => 0,
|
||||
'amount' => $amountPaid,
|
||||
'payment_date' => date('Y-m-d H:i:s'),
|
||||
'remark' => $payRemark,
|
||||
'update_by' => $userName . '[' . $userId . ']',
|
||||
];
|
||||
$paymentId = $paymentModel->insertPayment($payData);
|
||||
|
||||
$invoiceModel->updateInvoice([
|
||||
'payment_mode' => 1,
|
||||
'payment_status' => 1,
|
||||
'invoice_status' => 1,
|
||||
'payment_mode_desc' => 'Cash',
|
||||
'payment_id' => $paymentId,
|
||||
'confirm_invoice' => date('Y-m-d H:i:s'),
|
||||
'prepared_by' => $userName . '[' . $userId . ']',
|
||||
], $invoiceId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'showcontent' => 'Cash',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($mode === 2) {
|
||||
$payData = [
|
||||
'payment_mode' => 2,
|
||||
'payof_type' => 2,
|
||||
'payof_id' => $invoiceId,
|
||||
'payof_code' => $invMaster->invoice_code ?? '',
|
||||
'credit_debit' => 0,
|
||||
'amount' => $amountPaid,
|
||||
'payment_date' => date('Y-m-d H:i:s'),
|
||||
'remark' => $payRemark,
|
||||
'update_by' => $userName . '[' . $userId . ']',
|
||||
'card_bank' => (string) $this->request->getPost('input_card_mac'),
|
||||
'cust_card' => (string) $this->request->getPost('input_card_bank'),
|
||||
'card_remark' => (string) $this->request->getPost('input_card_digit'),
|
||||
'card_tran_id' => (string) $this->request->getPost('input_card_tran'),
|
||||
];
|
||||
$paymentId = $paymentModel->insertPayment($payData);
|
||||
|
||||
$invoiceModel->updateInvoice([
|
||||
'payment_mode' => 2,
|
||||
'payment_status' => 1,
|
||||
'invoice_status' => 1,
|
||||
'payment_mode_desc' => 'Bank Card',
|
||||
'payment_id' => $paymentId,
|
||||
'confirm_invoice' => date('Y-m-d H:i:s'),
|
||||
'card_bank' => (string) $this->request->getPost('input_card_mac'),
|
||||
'cust_card' => (string) $this->request->getPost('input_card_bank'),
|
||||
'card_remark' => (string) $this->request->getPost('input_card_digit'),
|
||||
'card_tran_id' => (string) $this->request->getPost('input_card_tran'),
|
||||
'prepared_by' => $userName . '[' . $userId . ']',
|
||||
], $invoiceId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'showcontent' => 'Bank Card',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($mode === 3) {
|
||||
$invoiceModel->updateInvoice([
|
||||
'payment_mode' => 3,
|
||||
'payment_status' => 1,
|
||||
'invoice_status' => 1,
|
||||
'payment_mode_desc' => 'IPD Credit',
|
||||
'confirm_invoice' => date('Y-m-d H:i:s'),
|
||||
'ipd_id' => (int) $this->request->getPost('ipd_id'),
|
||||
'prepared_by' => $userName . '[' . $userId . ']',
|
||||
], $invoiceId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'showcontent' => 'IPD Credit',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($mode === 4) {
|
||||
$invoiceModel->updateInvoice([
|
||||
'payment_mode' => 3,
|
||||
'payment_status' => 1,
|
||||
'invoice_status' => 1,
|
||||
'payment_mode_desc' => 'Org.Case Credit',
|
||||
'confirm_invoice' => date('Y-m-d H:i:s'),
|
||||
'insurance_case_id' => (int) $this->request->getPost('case_id'),
|
||||
'prepared_by' => $userName . '[' . $userId . ']',
|
||||
], $invoiceId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'showcontent' => 'Org. Credit',
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid payment mode']);
|
||||
}
|
||||
|
||||
public function invoice_print(int $invoiceId)
|
||||
{
|
||||
$sql = 'select i.*,t.desc from invoice_item i join hc_item_type t on i.item_type=t.itype_id where i.inv_master_id=' . $invoiceId;
|
||||
$data['invoiceDetails'] = $this->db->query($sql)->getResult();
|
||||
|
||||
$data['invoiceGtotal'] = $this->db->table('invoice_item')
|
||||
->selectSum('item_amount', 'Gtotal')
|
||||
->where('inv_master_id', $invoiceId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$data['invoice_master'] = $this->db->table('invoice_master')
|
||||
->where('id', $invoiceId)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
if (empty($data['invoice_master'])) {
|
||||
return $this->response->setStatusCode(404)->setBody('Invoice not found');
|
||||
}
|
||||
|
||||
$sql = 'select *,if(gender=1,\'Male\',\'Female\') as xgender from patient_master where id=' . (int) $data['invoice_master'][0]->attach_id;
|
||||
$data['patient_master'] = $this->db->query($sql)->getResult();
|
||||
$this->applyAge($data['patient_master']);
|
||||
|
||||
$insCompId = (int) $data['invoice_master'][0]->insurance_id;
|
||||
$insId = (int) $data['invoice_master'][0]->insurance_card_id;
|
||||
|
||||
$data['hc_insurance_card'] = $this->db->table('hc_insurance_card')->where('id', $insId)->get()->getResult();
|
||||
$data['insurance'] = $this->db->table('hc_insurance')->where('id', $insCompId)->get()->getResult();
|
||||
|
||||
$data['case_master'] = $this->db->table('organization_case_master')
|
||||
->where('id', (int) $data['invoice_master'][0]->insurance_case_id)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$data['payment_history'] = $this->db->query('select *,(case payment_mode when 1 Then \'cash\' when 2 then \'Bank Card\' when 3 then \'Org Credit\' else \'Pending\' end) as Payment_type_str from payment_history where payof_type=2 and payof_id=' . $invoiceId)->getResult();
|
||||
|
||||
return view('Invoice/Organization_invoice_print_v', $data);
|
||||
}
|
||||
|
||||
private function applyAge(array $rows, string $field = 'age'): void
|
||||
{
|
||||
foreach ($rows as $row) {
|
||||
$row->{$field} = get_age_1(
|
||||
$row->dob ?? null,
|
||||
$row->age ?? '',
|
||||
$row->age_in_month ?? '',
|
||||
$row->estimate_dob ?? ''
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
3944
app/Controllers/Opd.php
Normal file
3944
app/Controllers/Opd.php
Normal file
File diff suppressed because it is too large
Load Diff
6273
app/Controllers/Opd_prescription.php
Normal file
6273
app/Controllers/Opd_prescription.php
Normal file
File diff suppressed because it is too large
Load Diff
197
app/Controllers/Opdcase.php
Normal file
197
app/Controllers/Opdcase.php
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\OpdModel;
|
||||
|
||||
class Opdcase extends BaseController
|
||||
{
|
||||
public function addopd(int $pno)
|
||||
{
|
||||
$sql = "select *, if(gender=1,'Male','Female') as xgender
|
||||
from patient_master where id='" . (int) $pno . "'";
|
||||
$query = $this->db->query($sql);
|
||||
$data['person_info'] = $query->getResult();
|
||||
|
||||
if (empty($data['person_info'])) {
|
||||
return $this->response->setStatusCode(404)->setBody('Patient not found');
|
||||
}
|
||||
|
||||
$row = $data['person_info'][0];
|
||||
$row->age = get_age_1($row->dob ?? null, $row->age ?? '', $row->age_in_month ?? '', $row->estimate_dob ?? '');
|
||||
|
||||
$sql = "select d.id, d.p_fname, group_concat(m.SpecName) as SpecName
|
||||
from doctor_master d
|
||||
join doc_spec s join med_spec m on d.id = s.doc_id and s.med_spec_id = m.id
|
||||
where d.active = 1
|
||||
group by d.id";
|
||||
$query = $this->db->query($sql);
|
||||
$data['doc_spec_l'] = $query->getResult();
|
||||
|
||||
$cards = $this->db->table('hc_insurance_card')
|
||||
->where('p_id', $pno)
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$insuranceId = 0;
|
||||
if (!empty($cards)) {
|
||||
$insuranceId = (int) ($cards[0]->insurance_id ?? 0);
|
||||
} elseif (!empty($row->insurance_id)) {
|
||||
$insuranceId = (int) $row->insurance_id;
|
||||
}
|
||||
|
||||
return view('billing/opd_app_insurance_V', [
|
||||
'person_info' => $data['person_info'],
|
||||
'doc_spec_l' => $data['doc_spec_l'],
|
||||
'insurance_cards' => $cards,
|
||||
'insurance_id' => $insuranceId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function showfee()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'content' => '',
|
||||
'error_text' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$insuranceId = (int) $this->request->getPost('insurance_id');
|
||||
|
||||
$sql = "select d.id, d.p_fname, group_concat(m.SpecName) as SpecName,
|
||||
if(d.gender=1,'Male','Female') as xGender
|
||||
from doctor_master d
|
||||
join doc_spec s join med_spec m on d.id = s.doc_id and s.med_spec_id = m.id
|
||||
where d.active = 1 and d.id=" . $docId . " group by d.id";
|
||||
$query = $this->db->query($sql);
|
||||
$docInfo = $query->getResult();
|
||||
|
||||
$sql = "select * from hc_insurance where id=" . $insuranceId;
|
||||
$query = $this->db->query($sql);
|
||||
$opdFee = $query->getResult();
|
||||
|
||||
$content = '';
|
||||
$content .= '<h5><strong>Name :</strong> ' . esc($docInfo[0]->p_fname ?? '') .
|
||||
' <strong>/ Specialization:</strong> ' . esc($docInfo[0]->SpecName ?? '') .
|
||||
' <strong>/ Gender :</strong> ' . esc($docInfo[0]->xGender ?? '') . ' </h5>';
|
||||
$content .= '<input type="hidden" name="doc_id" id="doc_id" value="' . esc($docInfo[0]->id ?? 0) . '" />';
|
||||
|
||||
if (count($opdFee) > 0) {
|
||||
foreach ($opdFee as $row) {
|
||||
$content .= '<label class="d-block">';
|
||||
$content .= '<input type="radio" name="fee_id" id="fee_id" class="form-check-input me-1" checked value="' . (int) $row->id . '"> ';
|
||||
$content .= 'Rs. ' . esc($row->opd_fee) . ' [Insurance OPD Fee Apply]';
|
||||
$content .= '</label>';
|
||||
}
|
||||
} else {
|
||||
$content .= '<div class="alert alert-warning">No insurance fee found.</div>';
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
'content' => $content,
|
||||
]);
|
||||
}
|
||||
|
||||
public function confirm_opd()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$feeId = (int) $this->request->getPost('fee_id');
|
||||
$pid = (int) $this->request->getPost('pid');
|
||||
$insuranceId = (int) $this->request->getPost('insurance_id');
|
||||
$appointmentDate = (string) $this->request->getPost('datepicker_appointment');
|
||||
|
||||
if ($docId <= 0 || $feeId <= 0 || $pid <= 0 || $insuranceId <= 0 || $appointmentDate === '') {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => 'Missing required fields.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$sql = "select * from patient_master where id=" . $pid;
|
||||
$query = $this->db->query($sql);
|
||||
$personInfo = $query->getResult();
|
||||
|
||||
$sql = "select d.id, d.p_fname, group_concat(m.SpecName) as SpecName,
|
||||
if(d.gender=1,'Male','Female') as xGender
|
||||
from doctor_master d
|
||||
join doc_spec s join med_spec m on d.id = s.doc_id and s.med_spec_id = m.id
|
||||
where d.active=1 and d.id=" . $docId . " group by d.id";
|
||||
$query = $this->db->query($sql);
|
||||
$docInfo = $query->getResult();
|
||||
|
||||
$sql = "select * from hc_insurance where id=" . $insuranceId;
|
||||
$query = $this->db->query($sql);
|
||||
$insurance = $query->getResult();
|
||||
|
||||
if (count($personInfo) === 0 || count($docInfo) === 0 || count($insurance) === 0) {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => 'Invalid patient, doctor, or insurance selection.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$sql = "select * from opd_master where p_id=" . $pid . " order by opd_id desc";
|
||||
$query = $this->db->query($sql);
|
||||
$opdMaster = $query->getResult();
|
||||
|
||||
$user = auth()->user();
|
||||
$userLabel = $user ? ($user->username ?? $user->email ?? 'User') : 'User';
|
||||
$userId = $user->id ?? '';
|
||||
$userNameInfo = $userLabel . ' [' . date('d-m-Y H:i:s') . '] ' . $userId;
|
||||
|
||||
$opdFeeAmount = $insurance[0]->opd_fee ?? 0;
|
||||
$opdFeeDesc = $insurance[0]->opd_desc ?? '';
|
||||
|
||||
$insert = [
|
||||
'p_id' => $pid,
|
||||
'P_name' => strtoupper((string) $personInfo[0]->p_fname),
|
||||
'doc_id' => $docId,
|
||||
'insurance_id' => $insuranceId,
|
||||
'opd_fee_id' => $feeId,
|
||||
'opd_fee_amount' => $opdFeeAmount,
|
||||
'opd_fee_gross_amount' => $opdFeeAmount,
|
||||
'opd_fee_desc' => $opdFeeDesc,
|
||||
'doc_name' => $docInfo[0]->p_fname,
|
||||
'doc_spec' => $docInfo[0]->SpecName,
|
||||
'apointment_date' => str_to_MysqlDate($appointmentDate),
|
||||
'opd_fee_type' => '1',
|
||||
'prepared_by' => $userNameInfo,
|
||||
];
|
||||
|
||||
if (count($opdMaster) > 0) {
|
||||
$insert['last_opdvisit_date'] = $opdMaster[0]->apointment_date;
|
||||
}
|
||||
|
||||
$opdModel = new OpdModel();
|
||||
$insertId = $opdModel->insertOpd($insert);
|
||||
|
||||
if ($insertId > 0) {
|
||||
$this->db->table('patient_master')
|
||||
->where('id', $pid)
|
||||
->update(['last_visit' => str_to_MysqlDate($appointmentDate)]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? 'OPD Register' : 'OPD already exists for today.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
348
app/Controllers/OrgPacking.php
Normal file
348
app/Controllers/OrgPacking.php
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
class OrgPacking extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('org_packing/index');
|
||||
}
|
||||
|
||||
public function search()
|
||||
{
|
||||
$search = $this->request->getPost('search') ?? '';
|
||||
|
||||
$builder = $this->db->table('org_packing p');
|
||||
$builder->select('p.id')
|
||||
->select("DATE_FORMAT(p.date_of_create, '%d-%m-%Y') as date_created", false)
|
||||
->select('p.label_no, p.files_status')
|
||||
->select('COUNT(c.id) as no_records', false)
|
||||
->select("IF(p.org_type = 0, 'OPD', 'IPD') as list_type", false)
|
||||
->join('organization_case_master c', 'p.id = c.packing_id', 'left')
|
||||
->groupBy('p.id')
|
||||
->orderBy('p.date_of_create', 'DESC')
|
||||
->limit(50);
|
||||
|
||||
if (!empty($search)) {
|
||||
if (is_numeric($search)) {
|
||||
$builder->where("(p.label_no LIKE '%" . $this->db->escapeLikeString($search) . "%' OR p.Invoice_no = " . (int)$search . ")", null, false);
|
||||
} else {
|
||||
$builder->like('p.label_no', $search);
|
||||
}
|
||||
}
|
||||
|
||||
$packings = $builder->get()->getResult();
|
||||
|
||||
return view('org_packing/search_result', ['packings' => $packings]);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('org_packing/create');
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
$rules = [
|
||||
'label_no' => 'required|min_length[3]|max_length[30]',
|
||||
'org_type' => 'required|in_list[0,1]',
|
||||
'date_of_create' => 'required|valid_date',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => implode('<br>', $this->validator->getErrors())
|
||||
]);
|
||||
}
|
||||
|
||||
$labelNo = $this->request->getPost('label_no');
|
||||
$orgType = (int) $this->request->getPost('org_type');
|
||||
$dateCreated = $this->request->getPost('date_of_create');
|
||||
|
||||
// Check if label already exists
|
||||
$exists = $this->db->table('org_packing')
|
||||
->where('label_no', $labelNo)
|
||||
->countAllResults();
|
||||
|
||||
if ($exists > 0) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => 'Label No already exists'
|
||||
]);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'date_of_create' => $dateCreated,
|
||||
'label_no' => $labelNo,
|
||||
'org_type' => $orgType,
|
||||
];
|
||||
|
||||
$insertId = $this->db->table('org_packing')->insert($data);
|
||||
|
||||
if ($insertId) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'insert_id' => $this->db->insertID(),
|
||||
'message' => 'Packing created successfully'
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => 'Failed to create packing'
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $id)
|
||||
{
|
||||
$packing = $this->db->table('org_packing')
|
||||
->where('id', $id)
|
||||
->get()
|
||||
->getRow();
|
||||
|
||||
if (!$packing) {
|
||||
return redirect()->back()->with('error', 'Packing not found');
|
||||
}
|
||||
|
||||
// Get cases in this packing
|
||||
$cases = $this->db->table('organization_case_master o')
|
||||
->select('o.*, o.case_id_code, o.insurance_company_name')
|
||||
->select('p.p_code, p.p_fname, p.age')
|
||||
->select('o.insurance_no, o.insurance_no_1')
|
||||
->select("IF(o.case_type = 0, 'OPD', 'IPD') as ipd_opd", false)
|
||||
->join('patient_master p', 'o.p_id = p.id', 'inner')
|
||||
->where('o.packing_id', $id)
|
||||
->orderBy('o.packing_short', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
return view('org_packing/edit', [
|
||||
'packing' => $packing,
|
||||
'cases' => $cases,
|
||||
'packing_id' => $id
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(int $id)
|
||||
{
|
||||
$rules = [
|
||||
'label_no' => 'required|min_length[3]|max_length[30]',
|
||||
'org_type' => 'required|in_list[0,1]',
|
||||
'date_of_create' => 'required|valid_date',
|
||||
];
|
||||
|
||||
if (!$this->validate($rules)) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => implode('<br>', $this->validator->getErrors())
|
||||
]);
|
||||
}
|
||||
|
||||
$labelNo = $this->request->getPost('label_no');
|
||||
$orgType = (int) $this->request->getPost('org_type');
|
||||
$dateCreated = $this->request->getPost('date_of_create');
|
||||
|
||||
// Check if label already exists for other records
|
||||
$exists = $this->db->table('org_packing')
|
||||
->where('label_no', $labelNo)
|
||||
->where('id !=', $id)
|
||||
->countAllResults();
|
||||
|
||||
if ($exists > 0) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => 'Label No already exists'
|
||||
]);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'date_of_create' => $dateCreated,
|
||||
'label_no' => $labelNo,
|
||||
'org_type' => $orgType,
|
||||
];
|
||||
|
||||
$updated = $this->db->table('org_packing')
|
||||
->where('id', $id)
|
||||
->update($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => 'Packing updated successfully'
|
||||
]);
|
||||
}
|
||||
|
||||
public function addCase(int $orgId, int $packingId)
|
||||
{
|
||||
// Check if already added
|
||||
$exists = $this->db->table('organization_case_master')
|
||||
->where('id', $orgId)
|
||||
->where('packing_id', $packingId)
|
||||
->countAllResults();
|
||||
|
||||
if ($exists > 0) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => 'Case already added to this packing'
|
||||
]);
|
||||
}
|
||||
|
||||
// Get max short number
|
||||
$maxShort = $this->db->table('organization_case_master')
|
||||
->selectMax('packing_short', 'max_short')
|
||||
->where('packing_id', $packingId)
|
||||
->get()
|
||||
->getRow();
|
||||
|
||||
$nextShort = ((int) ($maxShort->max_short ?? 0)) + 1;
|
||||
|
||||
$user = auth()->user();
|
||||
$userName = ($user->username ?? 'System') . ' [' . date('d-m-Y H:i:s') . ']';
|
||||
|
||||
$data = [
|
||||
'packing_id' => $packingId,
|
||||
'packing_update_by' => $userName,
|
||||
'packing_short' => $nextShort
|
||||
];
|
||||
|
||||
$this->db->table('organization_case_master')
|
||||
->where('id', $orgId)
|
||||
->update($data);
|
||||
|
||||
return $this->getCasesList($packingId);
|
||||
}
|
||||
|
||||
public function removeCase(int $orgId, int $packingId)
|
||||
{
|
||||
$user = auth()->user();
|
||||
$userName = ($user->username ?? 'System') . ' [' . date('d-m-Y H:i:s') . ']';
|
||||
|
||||
$data = [
|
||||
'packing_id' => 0,
|
||||
'packing_update_by' => $userName,
|
||||
'packing_short' => 0
|
||||
];
|
||||
|
||||
$this->db->table('organization_case_master')
|
||||
->where('id', $orgId)
|
||||
->update($data);
|
||||
|
||||
return $this->getCasesList($packingId);
|
||||
}
|
||||
|
||||
private function getCasesList(int $packingId)
|
||||
{
|
||||
$cases = $this->db->table('organization_case_master o')
|
||||
->select('o.*, o.case_id_code, o.insurance_company_name')
|
||||
->select('p.p_code, p.p_fname, p.age')
|
||||
->select('o.insurance_no, o.insurance_no_1')
|
||||
->select("IF(o.case_type = 0, 'OPD', 'IPD') as ipd_opd", false)
|
||||
->join('patient_master p', 'o.p_id = p.id', 'inner')
|
||||
->where('o.packing_id', $packingId)
|
||||
->orderBy('o.packing_short', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
return view('org_packing/cases_list', [
|
||||
'cases' => $cases,
|
||||
'packing_id' => $packingId
|
||||
]);
|
||||
}
|
||||
|
||||
public function printList(int $packingId)
|
||||
{
|
||||
$packing = $this->db->table('org_packing')
|
||||
->where('id', $packingId)
|
||||
->get()
|
||||
->getRow();
|
||||
|
||||
if (!$packing) {
|
||||
return redirect()->back()->with('error', 'Packing not found');
|
||||
}
|
||||
|
||||
if ($packing->org_type == 0) {
|
||||
return $this->printOpdList($packingId);
|
||||
} else {
|
||||
return $this->printIpdList($packingId);
|
||||
}
|
||||
}
|
||||
|
||||
private function printOpdList(int $packingId)
|
||||
{
|
||||
$cases = $this->db->table('organization_case_master org')
|
||||
->select('org.*, org.case_id_code')
|
||||
->select('p.p_code, p.p_fname, p.age')
|
||||
->select("IF(org.case_type = 0, 'OPD', 'IPD') as ipd_opd", false)
|
||||
->select('(org.inv_opd_amt + org.inv_opd_charge_amt + org.inv_opd_med_amt) as claim_amt', false)
|
||||
->select("DATE_FORMAT(MIN(i.inv_date), '%d-%m-%Y') as opd_date", false)
|
||||
->join('patient_master p', 'org.p_id = p.id', 'inner')
|
||||
->join('invoice_master i', 'org.id = i.insurance_case_id', 'left')
|
||||
->where('org.packing_id', $packingId)
|
||||
->groupBy('org.id')
|
||||
->orderBy('org.packing_short', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$packing = $this->db->table('org_packing')->where('id', $packingId)->get()->getRow();
|
||||
|
||||
return view('org_packing/print_opd', [
|
||||
'cases' => $cases,
|
||||
'packing' => $packing
|
||||
]);
|
||||
}
|
||||
|
||||
private function printIpdList(int $packingId)
|
||||
{
|
||||
$cases = $this->db->table('organization_case_master org')
|
||||
->select('org.*, org.case_id_code')
|
||||
->select('p.p_code, p.p_fname, p.age')
|
||||
->select('i.ipd_code')
|
||||
->select("IF(org.case_type = 0, 'OPD', 'IPD') as ipd_opd", false)
|
||||
->select("DATE_FORMAT(i.register_date, '%d-%m-%Y') as admit_date", false)
|
||||
->select("DATE_FORMAT(i.discharge_date, '%d-%m-%Y') as discharge_date", false)
|
||||
->select('((i.charge_amount + i.chargeamount1 + i.chargeamount2 + i.med_amount) - (i.Discount + i.Discount2 + i.Discount3)) as claim_amt', false)
|
||||
->join('patient_master p', 'org.p_id = p.id', 'inner')
|
||||
->join('ipd_master i', 'org.id = i.case_id', 'left')
|
||||
->where('org.packing_id', $packingId)
|
||||
->orderBy('org.packing_short', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$packing = $this->db->table('org_packing')->where('id', $packingId)->get()->getRow();
|
||||
|
||||
return view('org_packing/print_ipd', [
|
||||
'cases' => $cases,
|
||||
'packing' => $packing
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchCases()
|
||||
{
|
||||
$search = $this->request->getPost('q');
|
||||
$orgType = (int) $this->request->getPost('org_type');
|
||||
$packingId = (int) $this->request->getPost('packing_id');
|
||||
|
||||
if (empty($search) || strlen($search) < 2) {
|
||||
return $this->response->setJSON([]);
|
||||
}
|
||||
|
||||
$builder = $this->db->table('organization_case_master o')
|
||||
->select('o.id')
|
||||
->select("CONCAT(o.case_id_code, ' - ', p.p_fname, ' (', p.p_code, ') - ', o.insurance_company_name) as text", false)
|
||||
->join('patient_master p', 'o.p_id = p.id', 'inner')
|
||||
->where('o.case_type', $orgType)
|
||||
->where('(o.packing_id = 0 OR o.packing_id IS NULL)', null, false)
|
||||
->groupStart()
|
||||
->like('o.case_id_code', $search)
|
||||
->orLike('p.p_fname', $search)
|
||||
->orLike('p.p_code', $search)
|
||||
->orLike('o.insurance_no', $search)
|
||||
->groupEnd()
|
||||
->limit(20);
|
||||
|
||||
$results = $builder->get()->getResult();
|
||||
|
||||
return $this->response->setJSON($results);
|
||||
}
|
||||
}
|
||||
267
app/Controllers/Package.php
Normal file
267
app/Controllers/Package.php
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\PackageModel;
|
||||
|
||||
class Package extends BaseController
|
||||
{
|
||||
public function searchItemType(): string
|
||||
{
|
||||
$model = new PackageModel();
|
||||
|
||||
return view('Setting/Charges/Package/item_type_search_v', [
|
||||
'data' => $model->getPackageGroups(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchAdv(int $groupId = 1): string
|
||||
{
|
||||
$model = new PackageModel();
|
||||
|
||||
return view('Setting/Charges/Package/item_search_adv', [
|
||||
'data' => $model->getPackagesByGroup($groupId),
|
||||
'groupId' => $groupId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function search(): string
|
||||
{
|
||||
$model = new PackageModel();
|
||||
$groupId = 1;
|
||||
|
||||
return view('Setting/Charges/Package/item_search_V', [
|
||||
'package_group' => $model->getPackageGroups(),
|
||||
'data' => $model->getPackagesByGroup($groupId),
|
||||
'groupId' => $groupId,
|
||||
'insurance_list' => $model->getInsuranceList(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function searchPrint(int $groupId = 1): string
|
||||
{
|
||||
$model = new PackageModel();
|
||||
$insuranceId = (int) $this->request->getGet('insurance');
|
||||
$insurance = $insuranceId > 0 ? $model->getInsuranceById($insuranceId) : null;
|
||||
$data = $insuranceId > 0
|
||||
? $model->getPackagesByGroupWithInsurance($groupId, $insuranceId)
|
||||
: $model->getPackagesByGroup($groupId);
|
||||
|
||||
return view('Setting/Charges/Package/item_item_list', [
|
||||
'data' => $data,
|
||||
'insuranceId' => $insuranceId,
|
||||
'insuranceName' => $insurance->ins_company_name ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
public function exportExcel(int $groupId = 1)
|
||||
{
|
||||
$model = new PackageModel();
|
||||
$insuranceId = (int) $this->request->getGet('insurance');
|
||||
$insurance = $insuranceId > 0 ? $model->getInsuranceById($insuranceId) : null;
|
||||
$data = $insuranceId > 0
|
||||
? $model->getPackagesByGroupWithInsurance($groupId, $insuranceId)
|
||||
: $model->getPackagesByGroup($groupId);
|
||||
|
||||
$table = view('Setting/Charges/Package/item_item_excel', [
|
||||
'data' => $data,
|
||||
'insuranceId' => $insuranceId,
|
||||
'insuranceName' => $insurance->ins_company_name ?? '',
|
||||
]);
|
||||
|
||||
$filename = 'IPD_Package_' . date('dMy') . '.xls';
|
||||
|
||||
return $this->response
|
||||
->setHeader('Content-Type', 'application/vnd.ms-excel')
|
||||
->setHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
|
||||
->setHeader('Cache-Control', 'max-age=0, no-cache, no-store, must-revalidate')
|
||||
->setHeader('Pragma', 'no-cache')
|
||||
->setHeader('Expires', '0')
|
||||
->setBody($table);
|
||||
}
|
||||
|
||||
public function itemTypeRecord(int $id): string
|
||||
{
|
||||
$model = new PackageModel();
|
||||
|
||||
return view('Setting/Charges/Package/item_type_profile', [
|
||||
'data_item' => $model->getPackageGroupById($id),
|
||||
]);
|
||||
}
|
||||
|
||||
public function itemRecord(int $id): string
|
||||
{
|
||||
$model = new PackageModel();
|
||||
|
||||
return view('Setting/Charges/Package/item_profile_V', [
|
||||
'data_item' => $model->getPackageById($id),
|
||||
'data_insurance_item' => $model->getPackageInsuranceList($id),
|
||||
'data_insurance' => $model->getInsuranceList(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new PackageModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
|
||||
$data = [
|
||||
'ipd_pakage_name' => $this->request->getPost('input_Package_name'),
|
||||
'Pakage_description' => $this->request->getPost('input_Pakage_description'),
|
||||
'Pakage_Min_Amount' => $this->request->getPost('input_Pakage_Min_Amount'),
|
||||
'update_date' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
$updated = $model->updatePackage($data, $itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : '',
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addRecord(): string
|
||||
{
|
||||
$model = new PackageModel();
|
||||
|
||||
return view('Setting/Charges/Package/item_create_V', [
|
||||
'data_item_type' => $model->getPackageGroups(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addItemTypeRecord(): string
|
||||
{
|
||||
return view('Setting/Charges/Package/item_type_create');
|
||||
}
|
||||
|
||||
public function createRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new PackageModel();
|
||||
$data = [
|
||||
'pakage_group_id' => $this->request->getPost('Item_Type'),
|
||||
'ipd_pakage_name' => $this->request->getPost('input_Item_name'),
|
||||
'Pakage_Min_Amount' => $this->request->getPost('input_amount'),
|
||||
'update_date' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertPackage($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addInsuranceItemRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new PackageModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
|
||||
$data = [
|
||||
'hc_items_id' => $itemId,
|
||||
'hc_insurance_id' => $this->request->getPost('ins_company_name'),
|
||||
'i_amount' => $this->request->getPost('input_amount'),
|
||||
'code' => $this->request->getPost('input_item_code'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertPackageInsurance($data);
|
||||
$list = $model->getPackageInsuranceList($itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'html' => view('Setting/Charges/Package/item_insurance_list', [
|
||||
'data_insurance_item' => $list,
|
||||
]),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function removeInsuranceItem()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new PackageModel();
|
||||
$itemId = (int) $this->request->getPost('p_id');
|
||||
$removeId = (int) $this->request->getPost('in_remove_id');
|
||||
|
||||
$deleted = $model->deletePackageInsurance($removeId);
|
||||
$list = $model->getPackageInsuranceList($itemId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please Check',
|
||||
'html' => view('Setting/Charges/Package/item_insurance_list', [
|
||||
'data_insurance_item' => $list,
|
||||
]),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createItemTypeRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new PackageModel();
|
||||
$data = [
|
||||
'pakage_group_name' => $this->request->getPost('input_Item_type'),
|
||||
];
|
||||
|
||||
$insertId = $model->insertPackageGroup($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateItemTypeRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new PackageModel();
|
||||
$groupId = (int) $this->request->getPost('itemtype_id');
|
||||
|
||||
$data = [
|
||||
'pakage_group_name' => $this->request->getPost('input_Item_type'),
|
||||
];
|
||||
|
||||
$updated = $model->updatePackageGroup($data, $groupId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : '',
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
931
app/Controllers/Patient.php
Normal file
931
app/Controllers/Patient.php
Normal file
|
|
@ -0,0 +1,931 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\BloodGroupModel;
|
||||
use App\Models\PatientModel;
|
||||
|
||||
class Patient extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$user = auth()->user();
|
||||
|
||||
$bloodGroupModel = new BloodGroupModel();
|
||||
$data['blood_group'] = $bloodGroupModel
|
||||
->orderBy('id', 'ASC')
|
||||
->findAll();
|
||||
|
||||
$data['user'] = $user;
|
||||
return view('billing/Patient_V', $data);
|
||||
}
|
||||
|
||||
public function search_opd()
|
||||
{
|
||||
$sql = "SELECT p.*,
|
||||
Date_Format(o.apointment_date,'%d-%m-%Y') AS opd_Visit,o.doc_name,o.doc_spec,o.opd_code,i.short_name
|
||||
FROM (patient_master p join opd_master o on p.id =o.p_id)
|
||||
Left join hc_insurance i on i.id = o.insurance_id
|
||||
order BY o.opd_id DESC LIMIT 100 ";
|
||||
|
||||
$query = $this->db->query($sql);
|
||||
$data['data'] = $query->getResult();
|
||||
|
||||
return view('billing/Patient_Search_opd', $data);
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response
|
||||
->setStatusCode(400)
|
||||
->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$chk_age = $this->request->getPost('chk_age');
|
||||
$age_month = (string) $this->request->getPost('input_age_month');
|
||||
$age_year = (string) $this->request->getPost('input_age_year');
|
||||
|
||||
$rules = [
|
||||
'input_name' => 'required|min_length[1]|max_length[100]',
|
||||
'input_relative_name' => 'required|min_length[1]|max_length[100]',
|
||||
'input_mphone1' => 'required|min_length[10]|max_length[10]',
|
||||
];
|
||||
|
||||
if ($chk_age === 'on') {
|
||||
$estimate_dob = 1;
|
||||
if ($age_year === '' && $age_month === '') {
|
||||
$rules['input_age_year'] = 'required|min_length[1]|max_length[4]';
|
||||
}
|
||||
} else {
|
||||
$estimate_dob = 0;
|
||||
$rules['datepicker_dob'] = 'required|min_length[1]|max_length[10]';
|
||||
}
|
||||
|
||||
$validation = service('validation');
|
||||
$validation->setRules($rules);
|
||||
if (!$validation->withRequest($this->request)->run()) {
|
||||
$errorText = implode("\n", $validation->getErrors());
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => $errorText,
|
||||
]);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'mphone1' => $this->request->getPost('input_mphone1'),
|
||||
'p_fname' => strtoupper((string) $this->request->getPost('input_name')),
|
||||
'gender' => $this->request->getPost('optionsRadios_gender'),
|
||||
'zip' => $this->request->getPost('input_zip'),
|
||||
'add1' => strtoupper((string) $this->request->getPost('input_address')),
|
||||
'city' => strtoupper((string) $this->request->getPost('input_city')),
|
||||
'district' => strtoupper((string) $this->request->getPost('input_district')),
|
||||
'state' => strtoupper((string) $this->request->getPost('input_state')),
|
||||
'title' => $this->request->getPost('cbo_title'),
|
||||
'p_relative' => $this->request->getPost('cbo_relation'),
|
||||
'p_rname' => strtoupper((string) $this->request->getPost('input_relative_name')),
|
||||
'blood_group' => strtoupper((string) $this->request->getPost('input_blood_group')),
|
||||
'udai' => strtoupper((string) $this->request->getPost('input_udai')),
|
||||
'estimate_dob' => $estimate_dob,
|
||||
];
|
||||
|
||||
if ($chk_age === 'on') {
|
||||
$data['age'] = $age_year;
|
||||
$data['age_in_month'] = $age_month;
|
||||
} else {
|
||||
$data['dob'] = $this->parseDate($this->request->getPost('datepicker_dob'));
|
||||
}
|
||||
|
||||
$patientModel = new PatientModel();
|
||||
$insertId = $patientModel->insertPatient($data);
|
||||
if ($insertId <= 0) {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => 'Unable to save patient.',
|
||||
]);
|
||||
}
|
||||
|
||||
// Check Multiple UHID
|
||||
$relativeName = trim(strtoupper((string) $this->request->getPost('input_relative_name')));
|
||||
$patientName = trim(strtoupper((string) $this->request->getPost('input_name')));
|
||||
|
||||
$builder = $this->db->table('patient_master');
|
||||
$builder->select("id, CONCAT(p_code,'/',p_fname,'/',IF(gender=1,'M','F'),'/',p_relative,' ',p_rname) as Sresult");
|
||||
$builder->groupStart()
|
||||
->where('p_rname', $relativeName)
|
||||
->where('p_fname', $patientName)
|
||||
->groupEnd();
|
||||
$builder->where('id <>', $insertId);
|
||||
$builder->orderBy('id', 'DESC');
|
||||
$search_result = $builder->get()->getResult();
|
||||
|
||||
$logText = '';
|
||||
foreach ($search_result as $row) {
|
||||
$logText .= $row->Sresult . PHP_EOL;
|
||||
}
|
||||
|
||||
if (count($search_result) > 0) {
|
||||
$user = auth()->user();
|
||||
$userLabel = $user ? ($user->username ?? $user->email ?? 'User') : 'User';
|
||||
$userId = $user->id ?? '';
|
||||
$userName = $userLabel . '[Date:' . date('d-m-Y H:i:s') . ']-' . $userId;
|
||||
|
||||
$dupData = [
|
||||
'new_uhid' => $insertId,
|
||||
'name_of_person' => $patientName,
|
||||
'new_patient_code' => '',
|
||||
'date_of_registration' => date('Y-m-d H:i:s'),
|
||||
'update_by' => $userName,
|
||||
'remark_duplicate' => $logText,
|
||||
];
|
||||
|
||||
$patientModel->insertDuplicateLog($dupData);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['insertid' => $insertId]);
|
||||
}
|
||||
|
||||
public function search_adv()
|
||||
{
|
||||
$inputMphone1 = trim((string) $this->request->getPost('input_mphone1'));
|
||||
$inputAadhar = trim((string) $this->request->getPost('input_udai'));
|
||||
$inputRelativeName = trim((string) $this->request->getPost('input_relative_name'));
|
||||
$inputName = trim((string) $this->request->getPost('input_name'));
|
||||
|
||||
$builder = $this->db->table('patient_master');
|
||||
$builder->select("id, CONCAT(p_fname,'/',IF(gender=1,'M','F'),'/',p_relative,' ',p_rname) AS Sresult");
|
||||
|
||||
$hasCondition = false;
|
||||
if ($inputMphone1 !== '') {
|
||||
$builder->orWhere('mphone1', $inputMphone1);
|
||||
$hasCondition = true;
|
||||
}
|
||||
|
||||
if ($inputAadhar !== '') {
|
||||
$builder->orWhere('udai', $inputAadhar);
|
||||
$hasCondition = true;
|
||||
}
|
||||
|
||||
if ($inputRelativeName !== '') {
|
||||
$builder->groupStart()
|
||||
->where('p_rname', $inputRelativeName)
|
||||
->where('p_fname', $inputName)
|
||||
->groupEnd();
|
||||
$hasCondition = true;
|
||||
}
|
||||
|
||||
$searchResult = [];
|
||||
if ($hasCondition) {
|
||||
$searchResult = $builder->orderBy('id', 'DESC')->get()->getResult();
|
||||
}
|
||||
|
||||
return view('billing/search_adv_data', ['search_result' => $searchResult]);
|
||||
}
|
||||
|
||||
public function search()
|
||||
{
|
||||
$sdata = (string) $this->request->getPost('txtsearch');
|
||||
$sdata = preg_replace('/[^A-Za-z0-9 _.@\-]/', '', trim($sdata ?? ''));
|
||||
|
||||
if (strlen($sdata) === 0) {
|
||||
$sql = "SELECT p.*,
|
||||
Date_Format(p.last_visit,'%d-%m-%Y') AS Last_Visit
|
||||
FROM patient_master p
|
||||
GROUP BY p.id
|
||||
ORDER BY p.last_visit DESC
|
||||
LIMIT 100 ";
|
||||
} else {
|
||||
$sdateArray = explode(' ', $sdata);
|
||||
$searchString = ' 1=1 ';
|
||||
|
||||
foreach ($sdateArray as $rowData) {
|
||||
if ($rowData === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_numeric($rowData)) {
|
||||
$searchString .= " and (p.p_code like '%$rowData'
|
||||
or p.mphone1 = '$rowData'
|
||||
or p.udai='$rowData' )";
|
||||
} elseif (ctype_alpha($rowData)) {
|
||||
$searchString .= " and (p.p_fname like '%$rowData%'
|
||||
or p.email1 = '$rowData'
|
||||
or SUBSTRING_INDEX(p.p_fname,' ',1) sounds like '$rowData')";
|
||||
} else {
|
||||
$searchString .= " and (p.p_code like '$rowData'
|
||||
or p.email1 = '$rowData' )";
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "SELECT p.*,
|
||||
Date_Format(p.last_visit,'%d-%m-%Y') AS Last_Visit
|
||||
FROM patient_master p
|
||||
WHERE $searchString
|
||||
GROUP BY p.id
|
||||
ORDER BY p.last_visit DESC";
|
||||
}
|
||||
|
||||
$query = $this->db->query($sql);
|
||||
$data['data'] = $query->getResult();
|
||||
|
||||
return view('billing/Patient_Search_V', $data);
|
||||
}
|
||||
|
||||
public function person_record(int $pno, int $edit = 0)
|
||||
{
|
||||
$sql = "select *,
|
||||
Date_Format(insert_date,'%Y-%m-%d') as str_regdate,
|
||||
if(gender=1,'Male','Female') as xgender ,
|
||||
if(date_add(insert_date,interval 12 hour)>sysdate(),1,0) as p_edit
|
||||
from patient_master where id=" . $pno;
|
||||
$query = $this->db->query($sql);
|
||||
$data['data'] = $query->getResult();
|
||||
|
||||
if (count($data['data']) === 0) {
|
||||
return $this->response->setStatusCode(404)->setBody('Patient not found');
|
||||
}
|
||||
|
||||
$required_age = $data['data'][0]->age;
|
||||
$required_age_in_month = $data['data'][0]->age_in_month;
|
||||
$required_dob = $data['data'][0]->dob;
|
||||
$estimate_dob = $data['data'][0]->estimate_dob;
|
||||
|
||||
if ($required_age == '' && $estimate_dob == 1) {
|
||||
if ($required_age == '0') {
|
||||
if ($required_age_in_month == 0 || $required_age_in_month == '') {
|
||||
$edit = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($required_dob == '' && $estimate_dob == 0) {
|
||||
$edit = 1;
|
||||
}
|
||||
|
||||
$sql = "select o.opd_id,o.opd_code,o.doc_name,o.apointment_date,o.p_id,
|
||||
p.p_fname,if(o.apointment_date=curdate(),1,0) as new_opd,
|
||||
date_format(o.apointment_date,'%d-%m-%Y') as str_apointment_date
|
||||
from opd_master o join patient_master p on o.p_id=p.id
|
||||
where o.p_id=$pno
|
||||
order by o.opd_id desc
|
||||
limit 200";
|
||||
$query = $this->db->query($sql);
|
||||
$data['opd_List'] = $query->getResult();
|
||||
|
||||
$sql = "select m.id,m.invoice_code,Date_Format(m.inv_date,'%d-%m-%y') as str_inv_date,m.inv_name,
|
||||
m.attach_id,m.insurance_card_id,
|
||||
if(count(t.id)>0,group_concat(t.item_name SEPARATOR ' / '),'No-Item') as Item_List, m.net_amount,m.invoice_status
|
||||
from invoice_master m left join invoice_item t on m.id=t.inv_master_id
|
||||
where attach_type=0 and attach_id=$pno
|
||||
group by m.id
|
||||
order by m.id desc
|
||||
limit 200";
|
||||
$query = $this->db->query($sql);
|
||||
$data['invoice_list'] = $query->getResult();
|
||||
|
||||
$sql = "select i.*,m.ins_company_name,m.opd_allowed,m.charge_cash
|
||||
from hc_insurance_card i join hc_insurance m on i.insurance_id=m.id
|
||||
where i.p_id=$pno";
|
||||
$query = $this->db->query($sql);
|
||||
$data['data_insurance_card'] = $query->getResult();
|
||||
|
||||
$sql = "select *,Date_Format(date_registration,'%d-%m-%Y') as str_date_registration
|
||||
from organization_case_master where status=0 and case_type=0 and p_id=$pno";
|
||||
$query = $this->db->query($sql);
|
||||
$data['case_master_opd'] = $query->getResult();
|
||||
|
||||
$sql = "SELECT o.*,DATE_FORMAT(o.date_registration,'%d-%m-%Y') as str_date_registration ,
|
||||
i.ipd_code,i.register_date
|
||||
from organization_case_master o left JOIN ipd_master i ON o.ipd_id=i.id
|
||||
WHERE o.status=0 AND o.case_type=1 and o.p_id=$pno";
|
||||
$query = $this->db->query($sql);
|
||||
$data['case_master_ipd'] = $query->getResult();
|
||||
|
||||
$sql = "select * from file_upload_data where id=" . $data['data'][0]->profile_file_id;
|
||||
$query = $this->db->query($sql);
|
||||
$file_data = $query->getResult();
|
||||
|
||||
$profile_file_path = '/assets/images/no_image.svg';
|
||||
$profile_picture_path = '';
|
||||
|
||||
if ($this->db->fieldExists('profile_picture', 'patient_master')) {
|
||||
$profile_picture_path = (string) ($data['data'][0]->profile_picture ?? '');
|
||||
}
|
||||
|
||||
$sql = "SELECT * from blood_group order by id";
|
||||
$query = $this->db->query($sql);
|
||||
$data['blood_group'] = $query->getResult();
|
||||
|
||||
$sql = "select * from tag_master Order by tag_name";
|
||||
$query = $this->db->query($sql);
|
||||
$data['tag_master'] = $query->getResult();
|
||||
|
||||
$sql = "SELECT a.*,t.tag_name,t.tag_type_id
|
||||
FROM patient_tag_assign a JOIN tag_master t ON a.tag_id=t.id
|
||||
WHERE isdelete=0 and a.p_id=$pno";
|
||||
$query = $this->db->query($sql);
|
||||
$data['patient_tag_list'] = $query->getResult();
|
||||
|
||||
if (count($file_data) > 0) {
|
||||
$pos = strpos($file_data[0]->full_path, '/uploads/', 1);
|
||||
if ($pos !== false) {
|
||||
$profile_file_path = substr($file_data[0]->full_path, $pos);
|
||||
} elseif (!empty($file_data[0]->full_path)) {
|
||||
$profile_file_path = $file_data[0]->full_path;
|
||||
}
|
||||
} elseif ($profile_picture_path !== '') {
|
||||
$pos = strpos($profile_picture_path, '/uploads/', 1);
|
||||
if ($pos !== false) {
|
||||
$profile_file_path = substr($profile_picture_path, $pos);
|
||||
} else {
|
||||
$profile_file_path = $profile_picture_path;
|
||||
}
|
||||
}
|
||||
|
||||
$data['profile_file_path'] = $profile_file_path;
|
||||
|
||||
if ($edit == 0) {
|
||||
return view('billing/Person_profile_V', $data);
|
||||
}
|
||||
|
||||
return view('billing/Person_Edit_V', $data);
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response
|
||||
->setStatusCode(400)
|
||||
->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$chk_age = $this->request->getPost('chk_age');
|
||||
$age_month = (string) $this->request->getPost('input_age_month');
|
||||
$age_year = (string) $this->request->getPost('input_age_year');
|
||||
|
||||
$rules = [
|
||||
'input_name' => 'required|min_length[1]|max_length[30]',
|
||||
];
|
||||
|
||||
if ($chk_age === 'on') {
|
||||
$estimate_dob = 1;
|
||||
if ($age_year === '' && $age_month === '') {
|
||||
$rules['input_age_year'] = 'required|min_length[1]|max_length[4]';
|
||||
}
|
||||
} else {
|
||||
$estimate_dob = 0;
|
||||
$rules['datepicker_dob'] = 'required|min_length[1]|max_length[10]';
|
||||
}
|
||||
|
||||
$validation = service('validation');
|
||||
$validation->setRules($rules);
|
||||
if (!$validation->withRequest($this->request)->run()) {
|
||||
$errorText = implode("\n", $validation->getErrors());
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => $errorText,
|
||||
]);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'mphone1' => $this->request->getPost('input_mphone1'),
|
||||
'p_fname' => strtoupper((string) $this->request->getPost('input_name')),
|
||||
'gender' => $this->request->getPost('optionsRadios_gender'),
|
||||
'zip' => $this->request->getPost('input_zip'),
|
||||
'add1' => strtoupper((string) $this->request->getPost('input_address')),
|
||||
'city' => strtoupper((string) $this->request->getPost('input_city')),
|
||||
'district' => strtoupper((string) $this->request->getPost('input_district')),
|
||||
'state' => strtoupper((string) $this->request->getPost('input_state')),
|
||||
'title' => $this->request->getPost('cbo_title'),
|
||||
'p_relative' => strtoupper((string) $this->request->getPost('cbo_relation')),
|
||||
'p_rname' => strtoupper((string) $this->request->getPost('input_relative_name')),
|
||||
'email1' => strtoupper((string) $this->request->getPost('input_email')),
|
||||
'udai' => strtoupper((string) $this->request->getPost('input_Aadhar')),
|
||||
'estimate_dob' => $estimate_dob,
|
||||
'blood_group' => $this->request->getPost('input_blood_group'),
|
||||
];
|
||||
|
||||
if ($chk_age === 'on') {
|
||||
$data['age'] = $age_year;
|
||||
$data['age_in_month'] = $age_month;
|
||||
} else {
|
||||
$data['dob'] = $this->parseDate($this->request->getPost('datepicker_dob'));
|
||||
}
|
||||
|
||||
$pid = (int) $this->request->getPost('p_id');
|
||||
$patientModel = new PatientModel();
|
||||
$patientModel->updatePatient($data, $pid);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'showcontent' => 'Data Saved successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
public function update_aadhar()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response
|
||||
->setStatusCode(400)
|
||||
->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$pid = (int) $this->request->getPost('p_id');
|
||||
$udai = (string) $this->request->getPost('udai');
|
||||
|
||||
$patientModel = new PatientModel();
|
||||
$patientModel->updatePatient(['udai' => $udai], $pid);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'showcontent' => 'Data Saved successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
public function update_card()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response
|
||||
->setStatusCode(400)
|
||||
->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'input_insurance_id' => 'required|min_length[2]|max_length[30]',
|
||||
'input_card_holder_name' => 'required|min_length[1]|max_length[30]',
|
||||
];
|
||||
|
||||
$validation = service('validation');
|
||||
$validation->setRules($rules);
|
||||
if (!$validation->withRequest($this->request)->run()) {
|
||||
$errorText = implode("\n", $validation->getErrors());
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => $errorText,
|
||||
]);
|
||||
}
|
||||
|
||||
$pid = (int) $this->request->getPost('p_id');
|
||||
$insCompanyId = (int) $this->request->getPost('Insurance_id');
|
||||
$cardId = (int) $this->request->getPost('inscard_id');
|
||||
$issueDate = $this->parseDate($this->request->getPost('datepicker_issue_date'));
|
||||
$expiryDate = $this->parseDate($this->request->getPost('datepicker_expiry_date'));
|
||||
|
||||
$cardData = [
|
||||
'insurance_id' => $insCompanyId,
|
||||
'p_id' => $pid,
|
||||
'insurance_no' => (string) $this->request->getPost('input_insurance_id'),
|
||||
'card_holder_name' => strtoupper((string) $this->request->getPost('input_card_holder_name')),
|
||||
'issue_date' => $issueDate,
|
||||
'expiry_date' => $expiryDate,
|
||||
'relation_patient_cardholder' => strtoupper((string) $this->request->getPost('input_Relation')),
|
||||
];
|
||||
|
||||
$patientModel = new PatientModel();
|
||||
$insertId = $cardId;
|
||||
if ($cardId <= 0) {
|
||||
$insertId = $patientModel->insertCard($cardData);
|
||||
if ($insertId <= 0) {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => 'Unable to save insurance card.',
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$patientModel->updateCard($cardData, $cardId);
|
||||
}
|
||||
|
||||
$patientUpdate = [
|
||||
'insurance_card_id' => $insertId,
|
||||
'insurance_id' => $insCompanyId,
|
||||
'insurance_no' => $cardData['insurance_no'],
|
||||
'card_holder_name' => $cardData['card_holder_name'],
|
||||
'issue_date' => $issueDate,
|
||||
'expiry_date' => $expiryDate,
|
||||
'relation_patient_cardholder' => $cardData['relation_patient_cardholder'],
|
||||
];
|
||||
$patientModel->updatePatient($patientUpdate, $pid);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show_cards(int $pno, int $insId = 0)
|
||||
{
|
||||
$patient = $this->db->table('patient_master')->where('id', $pno)->get()->getRow();
|
||||
if (!$patient) {
|
||||
return $this->response->setStatusCode(404)->setBody('Patient not found');
|
||||
}
|
||||
|
||||
$cards = $this->db->table('hc_insurance_card c')
|
||||
->select('c.*, i.ins_company_name')
|
||||
->join('hc_insurance i', 'i.id = c.insurance_id', 'left')
|
||||
->where('c.p_id', $pno)
|
||||
->orderBy('c.id', 'DESC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$insList = $this->db->table('hc_insurance')
|
||||
->orderBy('ins_company_name', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
return view('billing/Patient_Cards_V', [
|
||||
'patient' => $patient,
|
||||
'cards' => $cards,
|
||||
'insList' => $insList,
|
||||
'selectedInsId' => $insId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show_profile_image(int $pno, int $edit = 0)
|
||||
{
|
||||
$patient = $this->db->table('patient_master')->where('id', $pno)->get()->getRow();
|
||||
if (!$patient) {
|
||||
return $this->response->setStatusCode(404)->setBody('Patient not found');
|
||||
}
|
||||
|
||||
$profileFilePath = $this->getProfileFilePath((int) ($patient->profile_file_id ?? 0));
|
||||
|
||||
return view('billing/Patient_Profile_Image_V', [
|
||||
'patient' => $patient,
|
||||
'profileFilePath' => $profileFilePath,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show_profile_opd(int $pno, int $edit = 0)
|
||||
{
|
||||
$patient = $this->db->table('patient_master')->where('id', $pno)->get()->getRow();
|
||||
if (!$patient) {
|
||||
return $this->response->setStatusCode(404)->setBody('Patient not found');
|
||||
}
|
||||
|
||||
$opdList = $this->db->table('opd_master')
|
||||
->select('opd_id, opd_code, doc_name, apointment_date, queue_no')
|
||||
->where('p_id', $pno)
|
||||
->orderBy('opd_id', 'DESC')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
$opdIds = array_column($opdList, 'opd_id');
|
||||
$filesByOpd = [];
|
||||
|
||||
if ($opdIds && $this->db->tableExists('file_upload_data')) {
|
||||
$fields = $this->db->getFieldNames('file_upload_data') ?? [];
|
||||
$builder = $this->db->table('file_upload_data');
|
||||
if (in_array('opd_id', $fields, true)) {
|
||||
$builder->whereIn('opd_id', $opdIds);
|
||||
} elseif (in_array('attach_id', $fields, true)) {
|
||||
$builder->whereIn('attach_id', $opdIds);
|
||||
}
|
||||
if (in_array('show_type', $fields, true)) {
|
||||
$builder->where('show_type', 0);
|
||||
}
|
||||
|
||||
$rows = $builder->orderBy('id', 'ASC')->get()->getResultArray();
|
||||
foreach ($rows as $row) {
|
||||
$opdId = (int) ($row['opd_id'] ?? ($row['attach_id'] ?? 0));
|
||||
if ($opdId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = (string) ($row['full_path'] ?? '');
|
||||
if ($path !== '') {
|
||||
$pos = strpos($path, '/uploads/', 1);
|
||||
if ($pos !== false) {
|
||||
$path = substr($path, $pos);
|
||||
}
|
||||
}
|
||||
|
||||
$ext = strtolower((string) ($row['file_ext'] ?? pathinfo($path, PATHINFO_EXTENSION)));
|
||||
$ext = $ext && $ext[0] !== '.' ? '.' . $ext : $ext;
|
||||
$isPdf = $ext === '.pdf';
|
||||
|
||||
$filesByOpd[$opdId][] = [
|
||||
'path' => $path,
|
||||
'isPdf' => $isPdf,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$opdGroups = [];
|
||||
foreach ($opdList as $row) {
|
||||
$opdId = (int) $row['opd_id'];
|
||||
$opdGroups[] = [
|
||||
'opd_id' => $opdId,
|
||||
'opd_code' => $row['opd_code'] ?? '',
|
||||
'doc_name' => $row['doc_name'] ?? '',
|
||||
'opd_date' => !empty($row['apointment_date']) ? date('d-m-Y', strtotime($row['apointment_date'])) : '',
|
||||
'queue_no' => !empty($row['queue_no']) ? ('Q:' . $row['queue_no']) : '',
|
||||
'files' => $filesByOpd[$opdId] ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
return view('billing/Patient_Profile_Opd_V', [
|
||||
'patient' => $patient,
|
||||
'opdGroups' => $opdGroups,
|
||||
]);
|
||||
}
|
||||
|
||||
public function save_profile_image(int $pid)
|
||||
{
|
||||
$patient = $this->db->table('patient_master')->where('id', $pid)->get()->getRow();
|
||||
if (!$patient) {
|
||||
return $this->response->setStatusCode(404)->setJSON([
|
||||
'success' => false,
|
||||
'message' => 'Patient not found',
|
||||
]);
|
||||
}
|
||||
|
||||
$dataUri = (string) ($this->request->getPost('image') ?? $this->request->getPost('webcam') ?? $this->request->getPost('data_uri'));
|
||||
if ($dataUri === '') {
|
||||
$raw = (string) $this->request->getBody();
|
||||
if (str_starts_with($raw, 'data:image')) {
|
||||
$dataUri = $raw;
|
||||
}
|
||||
}
|
||||
|
||||
if ($dataUri === '' || !str_contains($dataUri, 'base64,')) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => 'Invalid image data.',
|
||||
]);
|
||||
}
|
||||
|
||||
[$meta, $encoded] = explode('base64,', $dataUri, 2);
|
||||
$mime = 'image/jpeg';
|
||||
if (preg_match('/data:(image\/[a-zA-Z0-9.+-]+);/i', $meta, $match)) {
|
||||
$mime = strtolower($match[1]);
|
||||
}
|
||||
|
||||
$binary = base64_decode($encoded);
|
||||
if ($binary === false) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => 'Unable to decode image.',
|
||||
]);
|
||||
}
|
||||
|
||||
$extension = match ($mime) {
|
||||
'image/png' => 'png',
|
||||
'image/gif' => 'gif',
|
||||
'image/webp' => 'webp',
|
||||
default => 'jpg',
|
||||
};
|
||||
|
||||
$uploadPath = rtrim(FCPATH, '\\/') . '/uploads/patient';
|
||||
if (!is_dir($uploadPath)) {
|
||||
mkdir($uploadPath, 0755, true);
|
||||
}
|
||||
|
||||
$filename = 'profile_' . $pid . '_' . time() . '.' . $extension;
|
||||
$fullPath = $uploadPath . '/' . $filename;
|
||||
if (file_put_contents($fullPath, $binary) === false) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => 'Unable to save image.',
|
||||
]);
|
||||
}
|
||||
|
||||
$publicPath = '/uploads/patient/' . $filename;
|
||||
$insertId = $this->insertFileUploadRecordFromData($pid, 'profile', $publicPath, $mime, strlen($binary));
|
||||
|
||||
$updated = false;
|
||||
if ($insertId > 0) {
|
||||
$this->db->table('patient_master')
|
||||
->where('id', $pid)
|
||||
->update(['profile_file_id' => $insertId]);
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
if ($this->db->fieldExists('profile_picture', 'patient_master')) {
|
||||
$this->db->table('patient_master')
|
||||
->where('id', $pid)
|
||||
->update(['profile_picture' => $publicPath]);
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => $updated,
|
||||
'path' => $publicPath,
|
||||
'message' => $updated ? 'Profile image saved.' : 'Image saved, record not updated.',
|
||||
'csrf' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function patient_file_upload(int $pid)
|
||||
{
|
||||
$patient = $this->db->table('patient_master')->where('id', $pid)->get()->getRow();
|
||||
if (!$patient) {
|
||||
return $this->response->setStatusCode(404)->setBody('Patient not found');
|
||||
}
|
||||
|
||||
$docType = (string) $this->request->getPost('doc_type');
|
||||
$updateProfile = $this->request->getPost('update_profile') === '1';
|
||||
$message = '';
|
||||
|
||||
$file = $this->request->getFile('upload_file');
|
||||
if ($file && $file->isValid() && !$file->hasMoved()) {
|
||||
$uploadPath = rtrim(FCPATH, '\\/') . '/uploads/patient';
|
||||
if (!is_dir($uploadPath)) {
|
||||
mkdir($uploadPath, 0755, true);
|
||||
}
|
||||
|
||||
$newName = $file->getRandomName();
|
||||
if ($file->move($uploadPath, $newName)) {
|
||||
$publicPath = '/uploads/patient/' . $newName;
|
||||
$insertId = $this->insertFileUploadRecord($pid, $docType, $publicPath, $file);
|
||||
|
||||
if ($updateProfile && $insertId > 0) {
|
||||
$this->db->table('patient_master')
|
||||
->where('id', $pid)
|
||||
->update(['profile_file_id' => $insertId]);
|
||||
}
|
||||
|
||||
$message = $insertId > 0 ? 'File uploaded successfully.' : 'File uploaded, but record was not saved.';
|
||||
} else {
|
||||
$message = 'Unable to save the file.';
|
||||
}
|
||||
} elseif ($file && !$file->isValid()) {
|
||||
$message = $file->getErrorString();
|
||||
}
|
||||
|
||||
return view('billing/Patient_File_Upload_V', [
|
||||
'patient' => $patient,
|
||||
'docType' => $docType,
|
||||
'updateProfile' => $updateProfile,
|
||||
'message' => $message,
|
||||
]);
|
||||
}
|
||||
|
||||
public function city()
|
||||
{
|
||||
$q = strtolower((string) $this->request->getGet('term'));
|
||||
if ($q === '') {
|
||||
return $this->response->setJSON([]);
|
||||
}
|
||||
|
||||
$patientModel = new PatientModel();
|
||||
return $this->response->setJSON($patientModel->getCitySuggestions($q));
|
||||
}
|
||||
|
||||
public function get_name()
|
||||
{
|
||||
$q = strtolower((string) $this->request->getGet('term'));
|
||||
if ($q === '') {
|
||||
return $this->response->setJSON([]);
|
||||
}
|
||||
|
||||
$sql = "select * from name_list where name like '" . $this->db->escapeLikeString($q) . "%' order by name limit 20";
|
||||
$query = $this->db->query($sql);
|
||||
$rows = $query->getResultArray();
|
||||
|
||||
$rowSet = [];
|
||||
foreach ($rows as $row) {
|
||||
$rowSet[] = [
|
||||
'label' => trim($row['name']),
|
||||
'value' => trim($row['name']),
|
||||
];
|
||||
}
|
||||
|
||||
return $this->response->setJSON($rowSet);
|
||||
}
|
||||
|
||||
private function getProfileFilePath(int $fileId): string
|
||||
{
|
||||
$profileFilePath = '/assets/images/no_image.svg';
|
||||
if ($fileId <= 0) {
|
||||
return $profileFilePath;
|
||||
}
|
||||
|
||||
$query = $this->db->table('file_upload_data')->where('id', $fileId)->get();
|
||||
$row = $query->getRow();
|
||||
if ($row && isset($row->full_path)) {
|
||||
$path = (string) $row->full_path;
|
||||
if ($path !== '') {
|
||||
$profileFilePath = $path;
|
||||
}
|
||||
}
|
||||
|
||||
return $profileFilePath;
|
||||
}
|
||||
|
||||
private function insertFileUploadRecord(int $pid, string $docType, string $publicPath, $file): int
|
||||
{
|
||||
if (!$this->db->tableExists('file_upload_data')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('file_upload_data');
|
||||
if (!$fields) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$data = [];
|
||||
if (in_array('p_id', $fields, true)) {
|
||||
$data['p_id'] = $pid;
|
||||
}
|
||||
if (in_array('attach_id', $fields, true)) {
|
||||
$data['attach_id'] = $pid;
|
||||
}
|
||||
if (in_array('doc_type', $fields, true)) {
|
||||
$data['doc_type'] = $docType;
|
||||
}
|
||||
if (in_array('file_name', $fields, true)) {
|
||||
$data['file_name'] = $file->getClientName();
|
||||
}
|
||||
if (in_array('file_type', $fields, true)) {
|
||||
$data['file_type'] = $file->getClientMimeType();
|
||||
}
|
||||
if (in_array('file_size', $fields, true)) {
|
||||
$data['file_size'] = $file->getSize();
|
||||
}
|
||||
if (in_array('full_path', $fields, true)) {
|
||||
$data['full_path'] = $publicPath;
|
||||
}
|
||||
if (in_array('insert_date', $fields, true)) {
|
||||
$data['insert_date'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
if (in_array('created_at', $fields, true)) {
|
||||
$data['created_at'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
if (!$data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$builder = $this->db->table('file_upload_data');
|
||||
if (!$builder->insert($data)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $this->db->insertID();
|
||||
}
|
||||
|
||||
private function insertFileUploadRecordFromData(int $pid, string $docType, string $publicPath, string $mime, int $size): int
|
||||
{
|
||||
if (!$this->db->tableExists('file_upload_data')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('file_upload_data');
|
||||
if (!$fields) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$data = [];
|
||||
if (in_array('p_id', $fields, true)) {
|
||||
$data['p_id'] = $pid;
|
||||
}
|
||||
if (in_array('attach_id', $fields, true)) {
|
||||
$data['attach_id'] = $pid;
|
||||
}
|
||||
if (in_array('doc_type', $fields, true)) {
|
||||
$data['doc_type'] = $docType;
|
||||
}
|
||||
if (in_array('file_name', $fields, true)) {
|
||||
$data['file_name'] = basename($publicPath);
|
||||
}
|
||||
if (in_array('file_type', $fields, true)) {
|
||||
$data['file_type'] = $mime;
|
||||
}
|
||||
if (in_array('file_size', $fields, true)) {
|
||||
$data['file_size'] = $size;
|
||||
}
|
||||
if (in_array('full_path', $fields, true)) {
|
||||
$data['full_path'] = $publicPath;
|
||||
}
|
||||
if (in_array('insert_date', $fields, true)) {
|
||||
$data['insert_date'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
if (in_array('created_at', $fields, true)) {
|
||||
$data['created_at'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
if (!$data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$builder = $this->db->table('file_upload_data');
|
||||
if (!$builder->insert($data)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $this->db->insertID();
|
||||
}
|
||||
|
||||
private function parseDate(?string $date): ?string
|
||||
{
|
||||
if ($date === null || trim($date) === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$dt = \DateTime::createFromFormat('d/m/Y', $date);
|
||||
|
||||
return $dt ? $dt->format('Y-m-d') : null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
755
app/Controllers/Payment_Medical.php
Normal file
755
app/Controllers/Payment_Medical.php
Normal file
|
|
@ -0,0 +1,755 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
|
||||
class Payment_Medical extends BaseController
|
||||
{
|
||||
protected $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = \Config\Database::connect();
|
||||
}
|
||||
|
||||
private function ensurePharmacyAccess()
|
||||
{
|
||||
$user = service('auth')->user();
|
||||
|
||||
$allowed = false;
|
||||
if ($user && method_exists($user, 'can')) {
|
||||
$allowed = $user->can('pharmacy.access') || $user->can('billing.access');
|
||||
}
|
||||
|
||||
if (! $allowed && $user && method_exists($user, 'inGroup')) {
|
||||
$allowed = $user->inGroup('superadmin', 'admin', 'developer');
|
||||
}
|
||||
|
||||
if ($allowed) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->response
|
||||
->setStatusCode(403)
|
||||
->setBody('<div class="alert alert-danger m-3">Access denied for Pharmacy module.</div>');
|
||||
}
|
||||
|
||||
private function firstColumn(array $fields, array $candidates): ?string
|
||||
{
|
||||
foreach ($candidates as $candidate) {
|
||||
if (in_array($candidate, $fields, true)) {
|
||||
return $candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function rowValue(array $row, array $keys, $default = null)
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
if (array_key_exists($key, $row)) {
|
||||
return $row[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
private function buildBankSourceLabel(array $row): string
|
||||
{
|
||||
$sourceText = trim((string) $this->rowValue($row, [
|
||||
'pay_type',
|
||||
'source_name',
|
||||
'payment_source',
|
||||
'source',
|
||||
'name',
|
||||
'title',
|
||||
], ''));
|
||||
|
||||
$bankText = trim((string) $this->rowValue($row, [
|
||||
'bank_name',
|
||||
'bank',
|
||||
'bank_account_name',
|
||||
'account_name',
|
||||
], ''));
|
||||
|
||||
if ($sourceText !== '' && $bankText !== '') {
|
||||
return $sourceText . ' [' . $bankText . ']';
|
||||
}
|
||||
if ($sourceText !== '') {
|
||||
return $sourceText;
|
||||
}
|
||||
if ($bankText !== '') {
|
||||
return $bankText;
|
||||
}
|
||||
|
||||
$id = (int) ($row['id'] ?? 0);
|
||||
return $id > 0 ? ('Source #' . $id) : 'Default Bank Source';
|
||||
}
|
||||
|
||||
private function getActiveUsers(): array
|
||||
{
|
||||
if (! $this->db->tableExists('users')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('users') ?? [];
|
||||
$builder = $this->db->table('users');
|
||||
|
||||
$select = ['id'];
|
||||
foreach (['username', 'first_name', 'last_name', 'active'] as $f) {
|
||||
if (in_array($f, $fields, true)) {
|
||||
$select[] = $f;
|
||||
}
|
||||
}
|
||||
|
||||
$builder->select(implode(',', array_unique($select)));
|
||||
if (in_array('active', $fields, true)) {
|
||||
$builder->where('active', 1);
|
||||
}
|
||||
|
||||
return $builder->orderBy('id', 'DESC')->get()->getResultArray();
|
||||
}
|
||||
|
||||
private function getMedicalBankSources(): array
|
||||
{
|
||||
$sourceTable = null;
|
||||
if ($this->db->tableExists('medical_bank_source')) {
|
||||
$sourceTable = 'medical_bank_source';
|
||||
} elseif ($this->db->tableExists('medical_bank_payment_source')) {
|
||||
$sourceTable = 'medical_bank_payment_source';
|
||||
}
|
||||
|
||||
if ($sourceTable === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$sourceFields = $this->db->getFieldNames($sourceTable) ?? [];
|
||||
$bankFk = $this->firstColumn($sourceFields, ['bank_id', 'medical_bank_id', 'bankid']);
|
||||
|
||||
$builder = $this->db->table($sourceTable . ' s')->select('s.*');
|
||||
|
||||
if ($this->db->tableExists('medical_bank') && $bankFk !== null) {
|
||||
$bankFields = $this->db->getFieldNames('medical_bank') ?? [];
|
||||
$bankPk = $this->firstColumn($bankFields, ['id', 'bank_id']);
|
||||
$bankNameCol = $this->firstColumn($bankFields, ['bank_name', 'name', 'bank']);
|
||||
|
||||
if ($bankPk !== null && $bankNameCol !== null) {
|
||||
$builder
|
||||
->select('ifnull(m.' . $bankNameCol . ', "") as bank_name', false)
|
||||
->join('medical_bank m', 'm.' . $bankPk . '=s.' . $bankFk, 'left');
|
||||
} else {
|
||||
$builder->select('"" as bank_name', false);
|
||||
}
|
||||
} else {
|
||||
$builder->select('"" as bank_name', false);
|
||||
}
|
||||
|
||||
$list = $builder->orderBy('s.id', 'ASC')->get()->getResultArray();
|
||||
|
||||
foreach ($list as &$row) {
|
||||
$row['_label'] = $this->buildBankSourceLabel($row);
|
||||
}
|
||||
unset($row);
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
private function getActorName(): string
|
||||
{
|
||||
$user = service('auth')->user();
|
||||
if (! $user) {
|
||||
return 'system';
|
||||
}
|
||||
|
||||
$parts = [];
|
||||
if (isset($user->first_name) && (string) $user->first_name !== '') {
|
||||
$parts[] = (string) $user->first_name;
|
||||
}
|
||||
if (isset($user->last_name) && (string) $user->last_name !== '') {
|
||||
$parts[] = (string) $user->last_name;
|
||||
}
|
||||
|
||||
$name = trim(implode(' ', $parts));
|
||||
if ($name === '' && isset($user->username) && (string) $user->username !== '') {
|
||||
$name = (string) $user->username;
|
||||
}
|
||||
if ($name === '' && isset($user->email) && (string) $user->email !== '') {
|
||||
$name = (string) $user->email;
|
||||
}
|
||||
|
||||
$id = isset($user->id) ? (string) $user->id : '';
|
||||
return $id !== '' ? ($name . '[' . $id . ']') : $name;
|
||||
}
|
||||
|
||||
private function appendMedicalInvoiceLog(int $invoiceId, string $message): void
|
||||
{
|
||||
if ($invoiceId <= 0 || trim($message) === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('invoice_med_master') || ! $this->db->fieldExists('log', 'invoice_med_master')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$invoice = $this->db->table('invoice_med_master')->select('id,log')->where('id', $invoiceId)->get()->getRowArray();
|
||||
if (! $invoice) {
|
||||
return;
|
||||
}
|
||||
|
||||
$oldLog = trim((string) ($invoice['log'] ?? ''));
|
||||
$newLine = trim($message) . ' | By ' . $this->getActorName() . '[' . date('Y-m-d H:i:s') . ']';
|
||||
$merged = $oldLog === '' ? $newLine : ($oldLog . PHP_EOL . $newLine);
|
||||
|
||||
$this->db->table('invoice_med_master')->where('id', $invoiceId)->update([
|
||||
'log' => $merged,
|
||||
]);
|
||||
}
|
||||
|
||||
private function getMedicalInvoiceIdByPayId(int $payId): int
|
||||
{
|
||||
if ($payId <= 0 || ! $this->db->tableExists('payment_history_medical')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('payment_history_medical') ?? [];
|
||||
$invoiceCol = null;
|
||||
foreach (['Medical_invoice_id', 'medical_invoice_id'] as $candidate) {
|
||||
if (in_array($candidate, $fields, true)) {
|
||||
$invoiceCol = $candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($invoiceCol === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$row = $this->db->table('payment_history_medical')->select($invoiceCol)->where('id', $payId)->get()->getRowArray();
|
||||
return (int) ($row[$invoiceCol] ?? 0);
|
||||
}
|
||||
|
||||
private function resolvePaymentLogTable(): ?string
|
||||
{
|
||||
if ($this->db->tableExists('paymentmedical_history_log')) {
|
||||
return 'paymentmedical_history_log';
|
||||
}
|
||||
|
||||
if ($this->db->tableExists('payment_history_log')) {
|
||||
return 'payment_history_log';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function insertPaymentLog(int $payId, string $updateType, string $updateBy, string $updateLog = '', string $updateRemark = ''): void
|
||||
{
|
||||
$logTable = $this->resolvePaymentLogTable();
|
||||
if ($logTable === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames($logTable) ?? [];
|
||||
$insert = [];
|
||||
|
||||
if (in_array('pay_id', $fields, true)) {
|
||||
$insert['pay_id'] = $payId;
|
||||
}
|
||||
if (in_array('update_type', $fields, true)) {
|
||||
$insert['update_type'] = $updateType;
|
||||
}
|
||||
if (in_array('update_by', $fields, true)) {
|
||||
$insert['update_by'] = $updateBy;
|
||||
}
|
||||
if (in_array('update_log', $fields, true) && $updateLog !== '') {
|
||||
$insert['update_log'] = $updateLog;
|
||||
}
|
||||
if (in_array('update_remark', $fields, true)) {
|
||||
if ($updateRemark !== '') {
|
||||
$insert['update_remark'] = $updateRemark;
|
||||
} elseif (! in_array('update_log', $fields, true) && $updateLog !== '') {
|
||||
$insert['update_remark'] = $updateLog;
|
||||
}
|
||||
}
|
||||
if (in_array('insert_datetime', $fields, true)) {
|
||||
$insert['insert_datetime'] = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
if ($insert !== []) {
|
||||
$this->db->table($logTable)->insert($insert);
|
||||
}
|
||||
}
|
||||
|
||||
private function renderPaymentRecord(int $recNo): string
|
||||
{
|
||||
if (! $this->db->tableExists('payment_history_medical')) {
|
||||
return 'No Record Found';
|
||||
}
|
||||
|
||||
$payFields = $this->db->getFieldNames('payment_history_medical') ?? [];
|
||||
$idCol = $this->firstColumn($payFields, ['id']);
|
||||
if (! $idCol) {
|
||||
return 'No Record Found';
|
||||
}
|
||||
|
||||
$payment = $this->db->table('payment_history_medical')
|
||||
->where($idCol, $recNo)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if (! $payment) {
|
||||
return 'No Record Found';
|
||||
}
|
||||
|
||||
$customerType = (int) ($this->rowValue($payment, ['Customerof_type', 'customerof_type'], 0));
|
||||
$medicalInvoiceId = (int) ($this->rowValue($payment, ['Medical_invoice_id', 'medical_invoice_id'], 0));
|
||||
$ipdId = (int) ($this->rowValue($payment, ['ipd_id', 'IPD_ID'], 0));
|
||||
$paymentMode = (int) ($this->rowValue($payment, ['payment_mode'], 1));
|
||||
$payBankId = (int) ($this->rowValue($payment, ['pay_bank_id', 'bank_id'], 0));
|
||||
$amount = (float) ($this->rowValue($payment, ['amount'], 0));
|
||||
$creditDebit = (int) ($this->rowValue($payment, ['credit_debit'], 0));
|
||||
|
||||
$invoiceNo = '';
|
||||
$invoiceToName = '';
|
||||
$invType = '';
|
||||
|
||||
if (($customerType === 1 || $customerType === 3) && $this->db->tableExists('invoice_med_master')) {
|
||||
$inv = $this->db->table('invoice_med_master')->where('id', $medicalInvoiceId)->get()->getRowArray();
|
||||
if ($inv) {
|
||||
$invoiceToName = (string) ($inv['inv_name'] ?? '');
|
||||
$invoiceNo = (string) ($inv['inv_med_code'] ?? '');
|
||||
$invType = $customerType === 1 ? 'OPD' : 'CASH';
|
||||
}
|
||||
} elseif ($customerType === 2 && $this->db->tableExists('ipd_master')) {
|
||||
$ipd = $this->db->table('ipd_master')->where('id', $ipdId)->get()->getRowArray();
|
||||
if ($ipd) {
|
||||
$invoiceToName = (string) ($ipd['P_name'] ?? ($ipd['p_name'] ?? ''));
|
||||
$invoiceNo = (string) ($ipd['ipd_code'] ?? '');
|
||||
$invType = 'IPD Medical Bill';
|
||||
}
|
||||
}
|
||||
|
||||
$amountStr = $creditDebit === 0 ? $amount : ($amount * -1);
|
||||
|
||||
return view('medical/payment_edit', [
|
||||
'payment_history' => $payment,
|
||||
'all_user_list' => $this->getActiveUsers(),
|
||||
'invoice_no' => $invoiceNo,
|
||||
'invoice_to_name' => $invoiceToName,
|
||||
'inv_Type' => $invType,
|
||||
'rec_no' => $recNo,
|
||||
'amount_str' => $amountStr,
|
||||
'payment_mode' => $paymentMode,
|
||||
'pay_bank_id' => $payBankId,
|
||||
'bank_sources' => $this->getMedicalBankSources(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
if ($deny = $this->ensurePharmacyAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
return view('medical/payment_search');
|
||||
}
|
||||
|
||||
public function payment_record()
|
||||
{
|
||||
if ($deny = $this->ensurePharmacyAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
$raw = (string) ($this->request->getPost('txtsearch') ?? '');
|
||||
$recNo = (int) preg_replace('/\D+/', '', trim($raw));
|
||||
|
||||
if ($recNo <= 0) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
return $this->response->setBody($this->renderPaymentRecord($recNo));
|
||||
}
|
||||
|
||||
public function change_to_bank()
|
||||
{
|
||||
if ($deny = $this->ensurePharmacyAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
$payId = (int) ($this->request->getPost('pay_id') ?? 0);
|
||||
if ($payId <= 0 || ! $this->db->tableExists('payment_history_medical')) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$oldRow = $this->db->table('payment_history_medical')->where('id', $payId)->get()->getRowArray();
|
||||
if (! $oldRow) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('payment_history_medical') ?? [];
|
||||
$payTypeId = (int) ($this->request->getPost('cbo_pay_type') ?? 0);
|
||||
$cardTranId = trim((string) ($this->request->getPost('input_card_tran') ?? ''));
|
||||
$sourceLabel = '';
|
||||
|
||||
if ($payTypeId > 0) {
|
||||
foreach ($this->getMedicalBankSources() as $source) {
|
||||
if ((int) ($source['id'] ?? 0) === $payTypeId) {
|
||||
$sourceLabel = (string) ($source['_label'] ?? $this->buildBankSourceLabel($source));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$update = [];
|
||||
|
||||
if (in_array('payment_mode', $fields, true)) {
|
||||
$update['payment_mode'] = 2;
|
||||
}
|
||||
if (in_array('payment_mode_desc', $fields, true)) {
|
||||
$update['payment_mode_desc'] = $sourceLabel !== '' ? $sourceLabel : 'Bank/Online';
|
||||
}
|
||||
if (in_array('pay_bank_id', $fields, true)) {
|
||||
$update['pay_bank_id'] = $payTypeId;
|
||||
}
|
||||
if (in_array('bank_id', $fields, true) && ! in_array('pay_bank_id', $fields, true)) {
|
||||
$update['bank_id'] = $payTypeId;
|
||||
}
|
||||
if (in_array('card_bank', $fields, true)) {
|
||||
$update['card_bank'] = $sourceLabel;
|
||||
}
|
||||
if (in_array('cust_card', $fields, true)) {
|
||||
$update['cust_card'] = '';
|
||||
}
|
||||
if (in_array('card_remark', $fields, true)) {
|
||||
$update['card_remark'] = '';
|
||||
}
|
||||
if (in_array('card_tran_id', $fields, true)) {
|
||||
$update['card_tran_id'] = $cardTranId;
|
||||
}
|
||||
|
||||
if ($update !== []) {
|
||||
$this->db->table('payment_history_medical')->where('id', $payId)->update($update);
|
||||
$oldMode = ((int) ($oldRow['payment_mode'] ?? 1) === 1) ? 'CASH' : 'BANK';
|
||||
$newMode = 'BANK';
|
||||
$logText = 'Payment mode Change ' . $oldMode . ' to ' . $newMode;
|
||||
if ($sourceLabel !== '') {
|
||||
$logText .= ' [' . $sourceLabel . ']';
|
||||
}
|
||||
if ($cardTranId !== '') {
|
||||
$logText .= ' TranID:' . $cardTranId;
|
||||
}
|
||||
|
||||
$this->insertPaymentLog($payId, '2', $this->getActorName(), $logText);
|
||||
$this->appendMedicalInvoiceLog($this->getMedicalInvoiceIdByPayId($payId), 'Payment Update: ' . $logText);
|
||||
}
|
||||
|
||||
return $this->response->setBody($this->renderPaymentRecord($payId));
|
||||
}
|
||||
|
||||
public function change_to_cash()
|
||||
{
|
||||
if ($deny = $this->ensurePharmacyAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
$payId = (int) ($this->request->getPost('pay_id') ?? 0);
|
||||
if ($payId <= 0 || ! $this->db->tableExists('payment_history_medical')) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$oldRow = $this->db->table('payment_history_medical')->where('id', $payId)->get()->getRowArray();
|
||||
if (! $oldRow) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('payment_history_medical') ?? [];
|
||||
$update = [];
|
||||
|
||||
if (in_array('payment_mode', $fields, true)) {
|
||||
$update['payment_mode'] = 1;
|
||||
}
|
||||
if (in_array('payment_mode_desc', $fields, true)) {
|
||||
$update['payment_mode_desc'] = 'Cash';
|
||||
}
|
||||
if (in_array('pay_bank_id', $fields, true)) {
|
||||
$update['pay_bank_id'] = 0;
|
||||
}
|
||||
if (in_array('bank_id', $fields, true) && ! in_array('pay_bank_id', $fields, true)) {
|
||||
$update['bank_id'] = 0;
|
||||
}
|
||||
if (in_array('card_bank', $fields, true)) {
|
||||
$update['card_bank'] = '';
|
||||
}
|
||||
if (in_array('cust_card', $fields, true)) {
|
||||
$update['cust_card'] = '';
|
||||
}
|
||||
if (in_array('card_remark', $fields, true)) {
|
||||
$update['card_remark'] = '';
|
||||
}
|
||||
if (in_array('card_tran_id', $fields, true)) {
|
||||
$update['card_tran_id'] = '';
|
||||
}
|
||||
|
||||
if ($update !== []) {
|
||||
$this->db->table('payment_history_medical')->where('id', $payId)->update($update);
|
||||
$oldMode = ((int) ($oldRow['payment_mode'] ?? 1) === 1) ? 'CASH' : 'BANK';
|
||||
$logText = 'Payment mode Change ' . $oldMode . ' to CASH';
|
||||
$this->insertPaymentLog($payId, '1', $this->getActorName(), $logText);
|
||||
$this->appendMedicalInvoiceLog($this->getMedicalInvoiceIdByPayId($payId), 'Payment Update: ' . $logText);
|
||||
}
|
||||
|
||||
return $this->response->setBody($this->renderPaymentRecord($payId));
|
||||
}
|
||||
|
||||
public function update_amount()
|
||||
{
|
||||
if ($deny = $this->ensurePharmacyAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
$payId = (int) ($this->request->getPost('pay_id') ?? 0);
|
||||
$changeValue = (float) ($this->request->getPost('change_value') ?? 0);
|
||||
|
||||
if ($payId <= 0 || $changeValue <= 0 || ! $this->db->tableExists('payment_history_medical')) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$oldRow = $this->db->table('payment_history_medical')->where('id', $payId)->get()->getRowArray();
|
||||
if (! $oldRow) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$oldAmt = (float) ($oldRow['amount'] ?? 0);
|
||||
|
||||
$this->db->table('payment_history_medical')->where('id', $payId)->update([
|
||||
'amount' => $changeValue,
|
||||
]);
|
||||
|
||||
$logText = 'Amount value Change ' . number_format($oldAmt, 2, '.', '')
|
||||
. ' to '
|
||||
. number_format($changeValue, 2, '.', '');
|
||||
|
||||
$this->insertPaymentLog($payId, '3', $this->getActorName(), $logText);
|
||||
$this->appendMedicalInvoiceLog($this->getMedicalInvoiceIdByPayId($payId), 'Payment Update: ' . $logText);
|
||||
|
||||
return $this->response->setBody($this->renderPaymentRecord($payId));
|
||||
}
|
||||
|
||||
public function change_user()
|
||||
{
|
||||
if ($deny = $this->ensurePharmacyAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
$payId = (int) ($this->request->getPost('pay_id') ?? 0);
|
||||
$userId = (int) ($this->request->getPost('user_list') ?? 0);
|
||||
|
||||
if ($payId <= 0 || $userId <= 0 || ! $this->db->tableExists('payment_history_medical') || ! $this->db->tableExists('users')) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$payment = $this->db->table('payment_history_medical')->where('id', $payId)->get()->getRowArray();
|
||||
$user = $this->db->table('users')->where('id', $userId)->get()->getRowArray();
|
||||
|
||||
if (! $payment || ! $user) {
|
||||
return $this->response->setBody('No Record Found');
|
||||
}
|
||||
|
||||
$userLabel = trim((string) (($user['first_name'] ?? '') . ' ' . ($user['last_name'] ?? '')));
|
||||
if ($userLabel === '') {
|
||||
$userLabel = (string) ($user['username'] ?? ('User ' . $userId));
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('payment_history_medical') ?? [];
|
||||
$update = [];
|
||||
|
||||
if (in_array('update_by_id', $fields, true)) {
|
||||
$update['update_by_id'] = $userId;
|
||||
}
|
||||
if (in_array('update_by', $fields, true)) {
|
||||
$insertTime = (string) ($payment['insert_time'] ?? ($payment['insert_datetime'] ?? ''));
|
||||
$update['update_by'] = $userLabel . '[' . $insertTime . '][' . $userId . ']';
|
||||
}
|
||||
|
||||
if ($update !== []) {
|
||||
$this->db->table('payment_history_medical')->where('id', $payId)->update($update);
|
||||
$newUserText = $userLabel . '[' . $userId . ']';
|
||||
$oldUserText = (string) ($payment['update_by'] ?? '');
|
||||
if ($oldUserText === '') {
|
||||
$oldUserText = '-';
|
||||
}
|
||||
|
||||
$logText = 'Update User Change ' . $oldUserText . ' to ' . $newUserText;
|
||||
$this->insertPaymentLog(
|
||||
$payId,
|
||||
'3',
|
||||
$this->getActorName(),
|
||||
$logText,
|
||||
$logText
|
||||
);
|
||||
$this->appendMedicalInvoiceLog($this->getMedicalInvoiceIdByPayId($payId), 'Payment Update: ' . $logText);
|
||||
}
|
||||
|
||||
return $this->response->setBody($this->renderPaymentRecord($payId));
|
||||
}
|
||||
|
||||
private function parseLegacyDateRange(string $dateRange): array
|
||||
{
|
||||
$dateRange = trim($dateRange);
|
||||
if ($dateRange === '') {
|
||||
$today = date('Y-m-d');
|
||||
return [$today, $today];
|
||||
}
|
||||
|
||||
$parts = explode('S', $dateRange);
|
||||
$fromRaw = str_replace('T', ' ', trim((string) ($parts[0] ?? '')));
|
||||
$toRaw = str_replace('T', ' ', trim((string) ($parts[1] ?? ($parts[0] ?? ''))));
|
||||
|
||||
$from = date('Y-m-d', strtotime($fromRaw ?: 'today'));
|
||||
$to = date('Y-m-d', strtotime($toRaw ?: $from));
|
||||
|
||||
if ($from > $to) {
|
||||
[$from, $to] = [$to, $from];
|
||||
}
|
||||
|
||||
return [$from, $to];
|
||||
}
|
||||
|
||||
public function payment_log()
|
||||
{
|
||||
if ($deny = $this->ensurePharmacyAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
return view('medical/payment_log', [
|
||||
'today' => date('Y-m-d'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function payment_log_data()
|
||||
{
|
||||
if ($deny = $this->ensurePharmacyAccess()) {
|
||||
return $deny;
|
||||
}
|
||||
|
||||
$dateRange = trim((string) ($this->request->getPost('opd_date_range') ?? $this->request->getGet('opd_date_range') ?? ''));
|
||||
[$dateFrom, $dateTo] = $this->parseLegacyDateRange($dateRange);
|
||||
|
||||
$logTable = $this->resolvePaymentLogTable();
|
||||
|
||||
if (! $this->db->tableExists('payment_history_medical') || $logTable === null) {
|
||||
return view('medical/payment_log_data', [
|
||||
'rows' => [],
|
||||
'dateFrom' => $dateFrom,
|
||||
'dateTo' => $dateTo,
|
||||
]);
|
||||
}
|
||||
|
||||
$pFields = $this->db->getFieldNames('payment_history_medical') ?? [];
|
||||
$lFields = $this->db->getFieldNames($logTable) ?? [];
|
||||
|
||||
$resolveField = static function (array $fields, array $candidates): ?string {
|
||||
$fieldMap = [];
|
||||
foreach ($fields as $field) {
|
||||
$fieldMap[strtolower((string) $field)] = (string) $field;
|
||||
}
|
||||
|
||||
foreach ($candidates as $candidate) {
|
||||
$key = strtolower((string) $candidate);
|
||||
if (isset($fieldMap[$key])) {
|
||||
return $fieldMap[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
$customerTypeField = $resolveField($pFields, ['Customerof_type', 'customerof_type']);
|
||||
$invoiceCodeField = $resolveField($pFields, ['Medical_invoice_code', 'medical_invoice_code']);
|
||||
$ipdIdField = $resolveField($pFields, ['ipd_id', 'IPD_ID']);
|
||||
$insertTimeField = $resolveField($pFields, ['insert_time', 'insert_datetime', 'created_at']);
|
||||
|
||||
$logInsertField = $resolveField($lFields, ['insert_datetime', 'insert_time', 'created_at']);
|
||||
$updateByField = $resolveField($lFields, ['update_by']);
|
||||
$updateTypeField = $resolveField($lFields, ['update_type']);
|
||||
$updateLogField = $resolveField($lFields, ['update_log']);
|
||||
$updateRemarkField = $resolveField($lFields, ['update_remark']);
|
||||
$logIdField = $resolveField($lFields, ['id']);
|
||||
|
||||
$customerTypeCol = $customerTypeField !== null ? ('p.' . $customerTypeField) : '0';
|
||||
$invoiceCodeCol = $invoiceCodeField !== null ? ('p.' . $invoiceCodeField) : "'-'";
|
||||
$ipdIdCol = $ipdIdField !== null ? ('p.' . $ipdIdField) : "'-'";
|
||||
$insertTimeCol = $insertTimeField !== null ? ('p.' . $insertTimeField) : 'null';
|
||||
|
||||
$logInsertCol = $logInsertField !== null ? ('l.' . $logInsertField) : 'null';
|
||||
$updateByCol = $updateByField !== null ? ('l.' . $updateByField) : "'-'";
|
||||
$updateTypeCol = $updateTypeField !== null ? ('l.' . $updateTypeField) : '0';
|
||||
if ($updateLogField !== null && $updateRemarkField !== null) {
|
||||
$updateLogCol = 'COALESCE(NULLIF(l.' . $updateLogField . ',\'\'), l.' . $updateRemarkField . ', \'\')';
|
||||
} elseif ($updateLogField !== null) {
|
||||
$updateLogCol = 'l.' . $updateLogField;
|
||||
} elseif ($updateRemarkField !== null) {
|
||||
$updateLogCol = 'l.' . $updateRemarkField;
|
||||
} else {
|
||||
$updateLogCol = "''";
|
||||
}
|
||||
|
||||
$select = [
|
||||
'p.id as id',
|
||||
'ifnull(' . $invoiceCodeCol . ", '-') as Inv_code",
|
||||
'ifnull(' . $insertTimeCol . ', null) as insert_time',
|
||||
'ifnull(' . $logInsertCol . ', null) as log_insert',
|
||||
'ifnull(' . $updateByCol . ", '-') as update_by",
|
||||
'ifnull(' . $updateTypeCol . ', 0) as update_type',
|
||||
'ifnull(' . $updateLogCol . ", '') as update_log",
|
||||
'ifnull(p.amount,0) as amount',
|
||||
"(case {$customerTypeCol} when 1 then ifnull({$invoiceCodeCol}, '-') when 2 then ifnull({$ipdIdCol}, '-') when 3 then ifnull({$invoiceCodeCol}, '-') else 'Unknown' end) as invoice_code",
|
||||
"(case {$customerTypeCol} when 1 then 'UHID' when 2 then 'IPD' when 3 then 'CASH' else 'Unknown' end) as bill_type",
|
||||
"(case {$updateTypeCol} when 3 then 'Change Amount' when 2 then 'Cash to Bank' when 1 then 'Bank to Cash' else 'Unknown' end) as log_type",
|
||||
];
|
||||
|
||||
$builder = $this->db->table('payment_history_medical p')
|
||||
->select(implode(',', $select), false)
|
||||
->join($logTable . ' l', 'p.id=l.pay_id', 'inner');
|
||||
|
||||
if ($logInsertField !== null) {
|
||||
$fromEsc = $this->db->escape($dateFrom);
|
||||
$toEsc = $this->db->escape($dateTo);
|
||||
$builder->where("DATE(l.{$logInsertField}) BETWEEN {$fromEsc} AND {$toEsc}", null, false);
|
||||
}
|
||||
|
||||
if ($logIdField !== null) {
|
||||
$builder->orderBy('l.' . $logIdField, 'DESC');
|
||||
} elseif ($logInsertField !== null) {
|
||||
$builder->orderBy('l.' . $logInsertField, 'DESC');
|
||||
} else {
|
||||
$builder->orderBy('p.id', 'DESC');
|
||||
}
|
||||
|
||||
$rows = $builder->get()->getResultArray();
|
||||
|
||||
if ($rows === []) {
|
||||
$fallbackBuilder = $this->db->table('payment_history_medical p')
|
||||
->select(implode(',', $select), false)
|
||||
->join($logTable . ' l', 'p.id=l.pay_id', 'inner');
|
||||
|
||||
if ($logIdField !== null) {
|
||||
$fallbackBuilder->orderBy('l.' . $logIdField, 'DESC');
|
||||
} elseif ($logInsertField !== null) {
|
||||
$fallbackBuilder->orderBy('l.' . $logInsertField, 'DESC');
|
||||
} else {
|
||||
$fallbackBuilder->orderBy('p.id', 'DESC');
|
||||
}
|
||||
|
||||
$rows = $fallbackBuilder->limit(500)->get()->getResultArray();
|
||||
}
|
||||
|
||||
return view('medical/payment_log_data', [
|
||||
'rows' => $rows,
|
||||
'dateFrom' => $dateFrom,
|
||||
'dateTo' => $dateTo,
|
||||
]);
|
||||
}
|
||||
}
|
||||
497
app/Controllers/Report.php
Normal file
497
app/Controllers/Report.php
Normal file
|
|
@ -0,0 +1,497 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
class Report extends BaseController
|
||||
{
|
||||
public function collection_report()
|
||||
{
|
||||
$employees = $this->db->table('users')
|
||||
->select('id, username')
|
||||
->where('active', 1)
|
||||
->orderBy('username', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$payModes = [
|
||||
(object) ['id' => 1, 'mode_desc' => 'Cash'],
|
||||
(object) ['id' => 2, 'mode_desc' => 'Bank'],
|
||||
];
|
||||
|
||||
return view('report/collection_report', [
|
||||
'employees' => $employees,
|
||||
'pay_modes' => $payModes,
|
||||
]);
|
||||
}
|
||||
|
||||
public function report_total_payment_app_show(
|
||||
string $dateRange,
|
||||
string $employeeIds,
|
||||
string $payModeId,
|
||||
string $orderFirst = '0',
|
||||
int $output = 0
|
||||
) {
|
||||
[$minRange, $maxRange] = $this->parseDateRange($dateRange);
|
||||
|
||||
$builder = $this->db->table('payment_history p');
|
||||
$builder->select("p.id as pay_id, p.payment_date,")
|
||||
->select("date_format(p.payment_date,'%d-%m-%Y %H:%i') as str_payment_date", false)
|
||||
->select("case p.payof_type when 1 then 'OPD' when 2 then 'Charges' when 3 then 'ORG' when 4 then 'IPD' else 'Other' end as pay_type", false)
|
||||
->select('p.payof_id, p.payof_code')
|
||||
->select("if(p.credit_debit=0,p.amount,0) as cr_amount", false)
|
||||
->select("if(p.credit_debit=1,p.amount,0) as dr_amount", false)
|
||||
->select('p.remark, p.update_by')
|
||||
->select("case p.payof_type when 1 then o.P_name when 2 then inv.inv_name when 3 then oc.insurance_company_name when 4 then pat.p_fname else '' end as patient_name", false)
|
||||
->select("case p.payment_mode when 1 then 'Cash' when 2 then 'Bank' else 'Other' end as pay_mode", false)
|
||||
->select('b.bank_name as bank_name, s.pay_type as bank_type')
|
||||
->join('opd_master o', 'p.payof_type = 1 and o.opd_id = p.payof_id', 'left')
|
||||
->join('invoice_master inv', 'p.payof_type = 2 and inv.id = p.payof_id', 'left')
|
||||
->join('organization_case_master oc', 'p.payof_type = 3 and oc.id = p.payof_id', 'left')
|
||||
->join('ipd_master im', 'p.payof_type = 4 and im.id = p.payof_id', 'left')
|
||||
->join('patient_master pat', 'pat.id = im.p_id', 'left')
|
||||
->join('hospital_bank_payment_source s', 's.id = p.pay_bank_id', 'left')
|
||||
->join('hospital_bank b', 'b.id = s.bank_id', 'left')
|
||||
->where('p.payment_date >=', $minRange)
|
||||
->where('p.payment_date <=', $maxRange);
|
||||
|
||||
$empList = $this->normalizeIdList($employeeIds);
|
||||
if (! empty($empList)) {
|
||||
$builder->whereIn('p.update_by_id', $empList);
|
||||
}
|
||||
|
||||
$payModeId = (int) $payModeId;
|
||||
if ($payModeId < 1) {
|
||||
$builder->whereIn('p.payment_mode', [1, 2]);
|
||||
} else {
|
||||
$builder->where('p.payment_mode', $payModeId);
|
||||
}
|
||||
|
||||
$builder->orderBy('p.id', 'ASC');
|
||||
$orderFirst = (int) $orderFirst;
|
||||
if ($orderFirst === 1) {
|
||||
$builder->orderBy('p.update_by', 'ASC');
|
||||
} elseif ($orderFirst === 2) {
|
||||
$builder->orderBy('p.payment_mode', 'ASC');
|
||||
}
|
||||
|
||||
$rows = $builder->get()->getResult();
|
||||
|
||||
$totalCr = 0.0;
|
||||
$totalDr = 0.0;
|
||||
foreach ($rows as $row) {
|
||||
$totalCr += (float) ($row->cr_amount ?? 0);
|
||||
$totalDr += (float) ($row->dr_amount ?? 0);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'rows' => $rows,
|
||||
'min_range' => $minRange,
|
||||
'max_range' => $maxRange,
|
||||
'total_cr' => $totalCr,
|
||||
'total_dr' => $totalDr,
|
||||
'net_total' => $totalCr - $totalDr,
|
||||
];
|
||||
|
||||
$content = view('report/collection_report_table', $data);
|
||||
if ($output === 1) {
|
||||
ExportExcel($content, 'Payment');
|
||||
return $this->response->setBody('');
|
||||
}
|
||||
|
||||
return $this->response->setBody($content);
|
||||
}
|
||||
|
||||
private function parseDateRange(string $dateRange): array
|
||||
{
|
||||
$rangeParts = explode('S', $dateRange);
|
||||
$startRaw = $rangeParts[0] ?? '';
|
||||
$endRaw = $rangeParts[1] ?? '';
|
||||
|
||||
$startRaw = str_replace('T', ' ', $startRaw);
|
||||
$endRaw = str_replace('T', ' ', $endRaw);
|
||||
|
||||
$start = trim($startRaw);
|
||||
$end = trim($endRaw);
|
||||
|
||||
if ($start === '' || $end === '') {
|
||||
$today = date('Y-m-d');
|
||||
$start = $today . ' 00:00:00';
|
||||
$end = $today . ' 23:59:59';
|
||||
}
|
||||
|
||||
return [$start, $end];
|
||||
}
|
||||
|
||||
private function normalizeIdList(string $idList): array
|
||||
{
|
||||
$idList = trim($idList);
|
||||
if ($idList === '' || $idList === '0') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$idList = str_replace('S', ',', $idList);
|
||||
$parts = array_filter(array_map('trim', explode(',', $idList)));
|
||||
$ids = [];
|
||||
foreach ($parts as $part) {
|
||||
$value = (int) $part;
|
||||
if ($value > 0) {
|
||||
$ids[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
public function diagnosis_report()
|
||||
{
|
||||
$itemTypes = $this->db->table('hc_item_type')
|
||||
->select('itype_id, group_desc')
|
||||
->whereIn('is_ipd_opd', [0, 1])
|
||||
->orderBy('group_desc', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
return view('report/diagnosis_report', [
|
||||
'item_types' => $itemTypes,
|
||||
]);
|
||||
}
|
||||
|
||||
public function diagnosis_report_data(
|
||||
string $dateRange,
|
||||
string $invoiceType = '0',
|
||||
string $diagnosisIds = '0',
|
||||
int $output = 0
|
||||
) {
|
||||
[$minRange, $maxRange] = $this->parseDateRange($dateRange);
|
||||
|
||||
$builder = $this->db->table('invoice_master m');
|
||||
$builder->select('y.group_desc, t.item_name')
|
||||
->select('COUNT(t.id) as no_test', false)
|
||||
->select('SUM(t.item_qty) as no_qty', false)
|
||||
->select('SUM(ROUND(IF(m.invoice_status=1, (t.item_amount - (t.item_amount * m.discount_amount / m.total_amount)), 0), 2)) as total_amount', false)
|
||||
->select('SUM(IF(m.invoice_status=1, t.item_amount, 0)) as total_act_amount', false)
|
||||
->join('invoice_item t', 'm.id = t.inv_master_id', 'inner')
|
||||
->join('hc_item_type y', 't.item_type = y.itype_id', 'inner')
|
||||
->where('y.is_ipd_opd IN (0, 1)', null, false)
|
||||
->where('m.invoice_status', 1)
|
||||
->where('m.inv_date >=', $minRange)
|
||||
->where('m.inv_date <=', $maxRange);
|
||||
|
||||
// Invoice type filter
|
||||
$invoiceTypeInt = (int) $invoiceType;
|
||||
if ($invoiceTypeInt === 1) {
|
||||
// IPD
|
||||
$builder->where('m.ipd_id >', 0);
|
||||
} elseif ($invoiceTypeInt === 2) {
|
||||
// OPD
|
||||
$builder->where('m.ipd_id', 0)
|
||||
->where('m.insurance_case_id', 0);
|
||||
} elseif ($invoiceTypeInt === 3) {
|
||||
// Organization
|
||||
$builder->where('m.insurance_case_id >', 0);
|
||||
}
|
||||
|
||||
$diagList = $this->normalizeIdList($diagnosisIds);
|
||||
if (!empty($diagList)) {
|
||||
$builder->whereIn('t.item_type', $diagList);
|
||||
}
|
||||
|
||||
$builder->groupBy(['y.group_desc', 't.item_id'])
|
||||
->orderBy('y.group_desc', 'ASC')
|
||||
->orderBy('t.item_name', 'ASC');
|
||||
|
||||
$rows = $builder->get()->getResult();
|
||||
|
||||
$invoiceTypeLabel = ['All Types', 'IPD', 'OPD', 'Organization'][$invoiceTypeInt] ?? 'All Types';
|
||||
|
||||
$data = [
|
||||
'rows' => $rows,
|
||||
'min_range' => $minRange,
|
||||
'max_range' => $maxRange,
|
||||
'invoice_type_label' => $invoiceTypeLabel,
|
||||
];
|
||||
|
||||
$content = view('report/diagnosis_report_table', $data);
|
||||
|
||||
if ($output === 1) {
|
||||
ExportExcel($content, 'Diagnosis_Report');
|
||||
return $this->response->setBody('');
|
||||
}
|
||||
|
||||
return $this->response->setBody($content);
|
||||
}
|
||||
|
||||
// ==================== Insurance Credit Reports ====================
|
||||
|
||||
public function insurance_credit_main()
|
||||
{
|
||||
return view('report/insurance_credit_main');
|
||||
}
|
||||
|
||||
public function insurance_opd_report()
|
||||
{
|
||||
$insuranceGroups = $this->db->table('h_insurance_group')
|
||||
->orderBy('tpa_group', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$insuranceCompanies = $this->db->table('hc_insurance')
|
||||
->orderBy('short_name', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
return view('report/insurance_opd_report', [
|
||||
'insurance_groups' => $insuranceGroups,
|
||||
'insurance_companies' => $insuranceCompanies,
|
||||
]);
|
||||
}
|
||||
|
||||
public function insurance_ipd_report()
|
||||
{
|
||||
$insuranceGroups = $this->db->table('h_insurance_group')
|
||||
->orderBy('tpa_group', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$insuranceCompanies = $this->db->table('hc_insurance')
|
||||
->orderBy('short_name', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
return view('report/insurance_ipd_report', [
|
||||
'insurance_groups' => $insuranceGroups,
|
||||
'insurance_companies' => $insuranceCompanies,
|
||||
]);
|
||||
}
|
||||
|
||||
public function insurance_combined_report()
|
||||
{
|
||||
$insuranceGroups = $this->db->table('h_insurance_group')
|
||||
->orderBy('tpa_group', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
$insuranceCompanies = $this->db->table('hc_insurance')
|
||||
->orderBy('short_name', 'ASC')
|
||||
->get()
|
||||
->getResult();
|
||||
|
||||
return view('report/insurance_combined_report', [
|
||||
'insurance_groups' => $insuranceGroups,
|
||||
'insurance_companies' => $insuranceCompanies,
|
||||
]);
|
||||
}
|
||||
|
||||
public function insurance_opd_report_data(
|
||||
string $dateRange,
|
||||
string $insuranceId = '0',
|
||||
string $caseStatus = '-1',
|
||||
int $output = 0
|
||||
) {
|
||||
[$minRange, $maxRange] = $this->parseDateRange($dateRange);
|
||||
|
||||
$builder = $this->db->table('organization_case_master o');
|
||||
$builder->select('o.id, o.case_id_code')
|
||||
->select("CONCAT(o.insurance_no, '/', o.insurance_no_1) as case_info", false)
|
||||
->select('p.p_code, p.p_fname')
|
||||
->select('ins.short_name as insurance_company')
|
||||
->select("DATE_FORMAT(o.date_registration, '%d-%m-%Y') as str_date_registration", false)
|
||||
->select("(CASE o.status WHEN 0 THEN 'Pending' WHEN 1 THEN 'Bill Complete' WHEN 2 THEN 'Submitted' ELSE 'Unknown' END) as org_submit_status", false)
|
||||
->select('(o.inv_opd_amt + o.inv_opd_charge_amt) as charge_amount', false)
|
||||
->select('o.inv_opd_med_amt as med_amount')
|
||||
->select('((o.inv_opd_amt + o.inv_opd_charge_amt) + o.inv_opd_med_amt) as net_amount', false)
|
||||
->join('patient_master p', 'o.p_id = p.id', 'inner')
|
||||
->join('hc_insurance ins', 'ins.id = o.insurance_id', 'inner')
|
||||
->where('o.case_type', 0)
|
||||
->where('o.date_registration >=', $minRange)
|
||||
->where('o.date_registration <=', $maxRange)
|
||||
->where('((o.inv_opd_amt + o.inv_opd_charge_amt) + o.inv_opd_med_amt) >', 0);
|
||||
|
||||
// Insurance filter
|
||||
if ($insuranceId !== '0') {
|
||||
if (strpos($insuranceId, 'G') === 0) {
|
||||
// Insurance Group
|
||||
$groupId = (int) substr($insuranceId, 1);
|
||||
$builder->where('ins.group_ins', $groupId);
|
||||
} else {
|
||||
// Individual Insurance
|
||||
$builder->where('o.insurance_id', (int) $insuranceId);
|
||||
}
|
||||
}
|
||||
|
||||
// Status filter
|
||||
$statusInt = (int) $caseStatus;
|
||||
if ($statusInt >= 0) {
|
||||
$builder->where('o.status', $statusInt);
|
||||
}
|
||||
|
||||
$builder->orderBy('o.id', 'ASC');
|
||||
$rows = $builder->get()->getResult();
|
||||
|
||||
$data = [
|
||||
'rows' => $rows,
|
||||
'min_range' => $minRange,
|
||||
'max_range' => $maxRange,
|
||||
'case_type' => 'OPD',
|
||||
];
|
||||
|
||||
$content = view('report/insurance_opd_report_table', $data);
|
||||
|
||||
if ($output === 1) {
|
||||
ExportExcel($content, 'Insurance_OPD_Report');
|
||||
return $this->response->setBody('');
|
||||
}
|
||||
|
||||
return $this->response->setBody($content);
|
||||
}
|
||||
|
||||
public function insurance_ipd_report_data(
|
||||
string $dateRange,
|
||||
string $insuranceId = '0',
|
||||
string $caseStatus = '-1',
|
||||
int $output = 0
|
||||
) {
|
||||
[$minRange, $maxRange] = $this->parseDateRange($dateRange);
|
||||
|
||||
$builder = $this->db->table('organization_case_master o');
|
||||
$builder->select('o.id, o.case_id_code')
|
||||
->select("CONCAT(o.insurance_no, '/', o.insurance_no_1) as case_info", false)
|
||||
->select('i.ipd_code, p.p_code, p.p_fname')
|
||||
->select('ins.short_name as insurance_company')
|
||||
->select("DATE_FORMAT(i.register_date, '%d-%m-%Y') as str_register_date", false)
|
||||
->select("DATE_FORMAT(i.discharge_date, '%d-%m-%Y') as str_discharge_date", false)
|
||||
->select("(CASE o.status WHEN 0 THEN 'Pending' WHEN 1 THEN 'Bill Complete' WHEN 2 THEN 'Submitted' ELSE 'Unknown' END) as org_submit_status", false)
|
||||
->select('(i.charge_amount + i.chargeamount1 + i.chargeamount2) as charge_amount', false)
|
||||
->select('i.med_amount')
|
||||
->select('(i.Discount + i.Discount2 + i.Discount3) as discount', false)
|
||||
->select('((i.charge_amount + i.chargeamount1 + i.chargeamount2 + i.med_amount) - (i.Discount + i.Discount2 + i.Discount3)) as net_amount', false)
|
||||
->select('o.amount_recived, o.amount_deduction')
|
||||
->join('ipd_master i', 'o.id = i.case_id', 'inner')
|
||||
->join('patient_master p', 'i.p_id = p.id', 'inner')
|
||||
->join('hc_insurance ins', 'ins.id = o.insurance_id', 'inner')
|
||||
->where('o.case_type', 1)
|
||||
->where('i.ipd_status', 1)
|
||||
->where('i.register_date >=', $minRange)
|
||||
->where('i.register_date <=', $maxRange);
|
||||
|
||||
// Insurance filter
|
||||
if ($insuranceId !== '0') {
|
||||
if (strpos($insuranceId, 'G') === 0) {
|
||||
// Insurance Group
|
||||
$groupId = (int) substr($insuranceId, 1);
|
||||
$builder->where('ins.group_ins', $groupId);
|
||||
} else {
|
||||
// Individual Insurance
|
||||
$builder->where('o.insurance_id', (int) $insuranceId);
|
||||
}
|
||||
}
|
||||
|
||||
// Status filter
|
||||
$statusInt = (int) $caseStatus;
|
||||
if ($statusInt >= 0) {
|
||||
$builder->where('o.status', $statusInt);
|
||||
}
|
||||
|
||||
$builder->orderBy('i.id', 'ASC');
|
||||
$rows = $builder->get()->getResult();
|
||||
|
||||
$data = [
|
||||
'rows' => $rows,
|
||||
'min_range' => $minRange,
|
||||
'max_range' => $maxRange,
|
||||
'case_type' => 'IPD',
|
||||
];
|
||||
|
||||
$content = view('report/insurance_ipd_report_table', $data);
|
||||
|
||||
if ($output === 1) {
|
||||
ExportExcel($content, 'Insurance_IPD_Report');
|
||||
return $this->response->setBody('');
|
||||
}
|
||||
|
||||
return $this->response->setBody($content);
|
||||
}
|
||||
|
||||
public function insurance_combined_report_data(
|
||||
string $dateRange,
|
||||
string $caseType = '-1',
|
||||
string $insuranceId = '0',
|
||||
int $output = 0
|
||||
) {
|
||||
[$minRange, $maxRange] = $this->parseDateRange($dateRange);
|
||||
|
||||
$caseTypeInt = (int) $caseType;
|
||||
$data = [
|
||||
'min_range' => $minRange,
|
||||
'max_range' => $maxRange,
|
||||
'opd_rows' => [],
|
||||
'ipd_rows' => [],
|
||||
];
|
||||
|
||||
// Get OPD data if needed
|
||||
if ($caseTypeInt === -1 || $caseTypeInt === 0) {
|
||||
$builder = $this->db->table('organization_case_master o');
|
||||
$builder->select('ins.short_name as insurance_company')
|
||||
->select('COUNT(o.id) as total_cases', false)
|
||||
->select('SUM(o.inv_opd_amt + o.inv_opd_charge_amt) as total_charge', false)
|
||||
->select('SUM(o.inv_opd_med_amt) as total_med', false)
|
||||
->select('SUM((o.inv_opd_amt + o.inv_opd_charge_amt) + o.inv_opd_med_amt) as total_net', false)
|
||||
->join('hc_insurance ins', 'ins.id = o.insurance_id', 'inner')
|
||||
->where('o.case_type', 0)
|
||||
->where('o.date_registration >=', $minRange)
|
||||
->where('o.date_registration <=', $maxRange);
|
||||
|
||||
if ($insuranceId !== '0') {
|
||||
if (strpos($insuranceId, 'G') === 0) {
|
||||
$groupId = (int) substr($insuranceId, 1);
|
||||
$builder->where('ins.group_ins', $groupId);
|
||||
} else {
|
||||
$builder->where('o.insurance_id', (int) $insuranceId);
|
||||
}
|
||||
}
|
||||
|
||||
$builder->groupBy('ins.short_name')->orderBy('ins.short_name', 'ASC');
|
||||
$data['opd_rows'] = $builder->get()->getResult();
|
||||
}
|
||||
|
||||
// Get IPD data if needed
|
||||
if ($caseTypeInt === -1 || $caseTypeInt === 1) {
|
||||
$builder = $this->db->table('organization_case_master o');
|
||||
$builder->select('ins.short_name as insurance_company')
|
||||
->select('COUNT(i.id) as total_cases', false)
|
||||
->select('SUM(i.charge_amount + i.chargeamount1 + i.chargeamount2) as total_charge', false)
|
||||
->select('SUM(i.med_amount) as total_med', false)
|
||||
->select('SUM(i.Discount + i.Discount2 + i.Discount3) as total_discount', false)
|
||||
->select('SUM((i.charge_amount + i.chargeamount1 + i.chargeamount2 + i.med_amount) - (i.Discount + i.Discount2 + i.Discount3)) as total_net', false)
|
||||
->select('SUM(o.amount_recived) as total_received', false)
|
||||
->select('SUM(o.amount_deduction) as total_deducted', false)
|
||||
->join('ipd_master i', 'o.id = i.case_id', 'inner')
|
||||
->join('hc_insurance ins', 'ins.id = o.insurance_id', 'inner')
|
||||
->where('o.case_type', 1)
|
||||
->where('i.ipd_status', 1)
|
||||
->where('i.register_date >=', $minRange)
|
||||
->where('i.register_date <=', $maxRange);
|
||||
|
||||
if ($insuranceId !== '0') {
|
||||
if (strpos($insuranceId, 'G') === 0) {
|
||||
$groupId = (int) substr($insuranceId, 1);
|
||||
$builder->where('ins.group_ins', $groupId);
|
||||
} else {
|
||||
$builder->where('o.insurance_id', (int) $insuranceId);
|
||||
}
|
||||
}
|
||||
|
||||
$builder->groupBy('ins.short_name')->orderBy('ins.short_name', 'ASC');
|
||||
$data['ipd_rows'] = $builder->get()->getResult();
|
||||
}
|
||||
|
||||
$content = view('report/insurance_combined_report_table', $data);
|
||||
|
||||
if ($output === 1) {
|
||||
ExportExcel($content, 'Insurance_Combined_Report');
|
||||
return $this->response->setBody('');
|
||||
}
|
||||
|
||||
return $this->response->setBody($content);
|
||||
}
|
||||
}
|
||||
13
app/Controllers/Setting/Admin.php
Normal file
13
app/Controllers/Setting/Admin.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
|
||||
class Admin extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
return view('Setting/Admin/index');
|
||||
}
|
||||
}
|
||||
436
app/Controllers/Setting/AiSettings.php
Normal file
436
app/Controllers/Setting/AiSettings.php
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
|
||||
class AiSettings extends BaseController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
if (! $this->canManageAiSettings()) {
|
||||
return $this->response->setStatusCode(403)->setBody('Access denied');
|
||||
}
|
||||
|
||||
$geminiKey = $this->readSettingValue('GEMINI_API_KEY');
|
||||
$azureKey = $this->readSettingValue('AZURE_OPENAI_API_KEY');
|
||||
$docIntelKey = $this->readSettingValue('AZURE_DOCINTEL_KEY');
|
||||
|
||||
return view('Setting/Admin/ai_settings', [
|
||||
'gemini_key_masked' => $this->maskKey($geminiKey),
|
||||
'gemini_key_exists' => $geminiKey !== '',
|
||||
'azure_openai_endpoint' => $this->readSettingValue('AZURE_OPENAI_ENDPOINT'),
|
||||
'azure_openai_deployment' => $this->readSettingValue('AZURE_OPENAI_DEPLOYMENT'),
|
||||
'azure_openai_api_version' => $this->readSettingValue('AZURE_OPENAI_API_VERSION') ?: '2024-10-21',
|
||||
'azure_openai_key_masked' => $this->maskKey($azureKey),
|
||||
'azure_openai_key_exists' => $azureKey !== '',
|
||||
'azure_docintel_endpoint' => $this->readSettingValue('AZURE_DOCINTEL_ENDPOINT'),
|
||||
'azure_docintel_key_masked' => $this->maskKey($docIntelKey),
|
||||
'azure_docintel_key_exists' => $docIntelKey !== '',
|
||||
]);
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
if (! $this->canManageAiSettings()) {
|
||||
return $this->response->setStatusCode(403)->setJSON(['update' => 0, 'error_text' => 'Access denied']);
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('hospital_setting')) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'hospital_setting table not found']);
|
||||
}
|
||||
|
||||
$fields = [
|
||||
'GEMINI_API_KEY' => trim((string) $this->request->getPost('gemini_api_key')),
|
||||
'AZURE_OPENAI_ENDPOINT' => trim((string) $this->request->getPost('azure_openai_endpoint')),
|
||||
'AZURE_OPENAI_API_KEY' => trim((string) $this->request->getPost('azure_openai_api_key')),
|
||||
'AZURE_OPENAI_DEPLOYMENT' => trim((string) $this->request->getPost('azure_openai_deployment')),
|
||||
'AZURE_OPENAI_API_VERSION' => trim((string) $this->request->getPost('azure_openai_api_version')),
|
||||
'AZURE_DOCINTEL_ENDPOINT' => trim((string) $this->request->getPost('azure_docintel_endpoint')),
|
||||
'AZURE_DOCINTEL_KEY' => trim((string) $this->request->getPost('azure_docintel_key')),
|
||||
];
|
||||
|
||||
$savedCount = 0;
|
||||
foreach ($fields as $name => $value) {
|
||||
if ($value === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->upsertSettingValue($name, $value)) {
|
||||
$savedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($savedCount === 0) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Provide at least one setting value to save',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'error_text' => 'Saved ' . $savedCount . ' setting(s)',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function test()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
if (! $this->canManageAiSettings()) {
|
||||
return $this->response->setStatusCode(403)->setJSON(['update' => 0, 'error_text' => 'Access denied']);
|
||||
}
|
||||
|
||||
$provider = strtolower(trim((string) $this->request->getPost('provider')));
|
||||
if ($provider === '') {
|
||||
$provider = 'gemini';
|
||||
}
|
||||
|
||||
if ($provider === 'azure') {
|
||||
return $this->testAzureOpenAi();
|
||||
}
|
||||
|
||||
$apiKey = trim((string) $this->request->getPost('gemini_api_key'));
|
||||
if ($apiKey === '') {
|
||||
$apiKey = $this->readSettingValue('GEMINI_API_KEY');
|
||||
}
|
||||
|
||||
if ($apiKey === '') {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Gemini API key not configured']);
|
||||
}
|
||||
|
||||
try {
|
||||
$client = service('curlrequest', $this->geminiHttpOptions());
|
||||
$payload = [
|
||||
'contents' => [[
|
||||
'parts' => [[
|
||||
'text' => 'Reply with exactly: CONNECTED',
|
||||
]],
|
||||
]],
|
||||
'generationConfig' => [
|
||||
'temperature' => 0,
|
||||
'maxOutputTokens' => 20,
|
||||
],
|
||||
];
|
||||
|
||||
$lastStatus = 0;
|
||||
$lastBody = '';
|
||||
|
||||
foreach ($this->geminiModelCandidates() as $modelName) {
|
||||
$url = 'https://generativelanguage.googleapis.com/v1beta/models/' . $modelName . ':generateContent?key=' . urlencode($apiKey);
|
||||
$response = $client->post($url, [
|
||||
'headers' => ['Content-Type' => 'application/json'],
|
||||
'json' => $payload,
|
||||
]);
|
||||
|
||||
$status = $response->getStatusCode();
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
if ($status === 429) {
|
||||
usleep(1200000);
|
||||
$retry = $client->post($url, [
|
||||
'headers' => ['Content-Type' => 'application/json'],
|
||||
'json' => $payload,
|
||||
]);
|
||||
$status = $retry->getStatusCode();
|
||||
$body = (string) $retry->getBody();
|
||||
}
|
||||
|
||||
if ($status >= 200 && $status < 300) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'error_text' => 'Gemini connection successful (' . $modelName . ')',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$lastStatus = $status;
|
||||
$lastBody = $body;
|
||||
|
||||
if ($status !== 404) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => $this->geminiHttpFailureMessage($lastStatus, $lastBody),
|
||||
'detail' => mb_substr($lastBody, 0, 250),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => $this->normalizeGeminiError($e->getMessage()),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function testAzureOpenAi()
|
||||
{
|
||||
$endpoint = trim((string) $this->request->getPost('azure_openai_endpoint'));
|
||||
$apiKey = trim((string) $this->request->getPost('azure_openai_api_key'));
|
||||
$deployment = trim((string) $this->request->getPost('azure_openai_deployment'));
|
||||
$apiVersion = trim((string) $this->request->getPost('azure_openai_api_version'));
|
||||
|
||||
if ($endpoint === '') {
|
||||
$endpoint = $this->readSettingValue('AZURE_OPENAI_ENDPOINT');
|
||||
}
|
||||
if ($apiKey === '') {
|
||||
$apiKey = $this->readSettingValue('AZURE_OPENAI_API_KEY');
|
||||
}
|
||||
if ($deployment === '') {
|
||||
$deployment = $this->readSettingValue('AZURE_OPENAI_DEPLOYMENT');
|
||||
}
|
||||
if ($apiVersion === '') {
|
||||
$apiVersion = $this->readSettingValue('AZURE_OPENAI_API_VERSION');
|
||||
}
|
||||
if ($apiVersion === '') {
|
||||
$apiVersion = '2024-10-21';
|
||||
}
|
||||
|
||||
if ($endpoint === '' || $apiKey === '' || $deployment === '') {
|
||||
$missing = [];
|
||||
if ($endpoint === '') {
|
||||
$missing[] = 'endpoint';
|
||||
}
|
||||
if ($apiKey === '') {
|
||||
$missing[] = 'key';
|
||||
}
|
||||
if ($deployment === '') {
|
||||
$missing[] = 'deployment';
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Azure OpenAI settings incomplete: missing ' . implode(', ', $missing),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$endpoint = rtrim($endpoint, '/');
|
||||
$url = $endpoint . '/openai/deployments/' . rawurlencode($deployment) . '/chat/completions?api-version=' . rawurlencode($apiVersion);
|
||||
|
||||
try {
|
||||
$client = service('curlrequest', $this->geminiHttpOptions());
|
||||
$response = $client->post($url, [
|
||||
'headers' => [
|
||||
'api-key' => $apiKey,
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'json' => [
|
||||
'messages' => [[
|
||||
'role' => 'user',
|
||||
'content' => 'Reply with exactly: CONNECTED',
|
||||
]],
|
||||
'temperature' => 0,
|
||||
'max_tokens' => 20,
|
||||
],
|
||||
]);
|
||||
|
||||
$status = $response->getStatusCode();
|
||||
$body = (string) $response->getBody();
|
||||
|
||||
if ($status < 200 || $status >= 300) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Azure OpenAI test failed (HTTP ' . $status . ')',
|
||||
'detail' => mb_substr($body, 0, 300),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'error_text' => 'Azure OpenAI connection successful',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Azure OpenAI test failed: ' . $e->getMessage(),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function geminiHttpOptions(): array
|
||||
{
|
||||
$options = [
|
||||
'timeout' => 20,
|
||||
'http_errors' => false,
|
||||
];
|
||||
|
||||
if (defined('ENVIRONMENT') && in_array((string) ENVIRONMENT, ['development', 'testing'], true)) {
|
||||
$options['verify'] = false;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
private function normalizeGeminiError(string $message): string
|
||||
{
|
||||
$message = trim($message);
|
||||
|
||||
if (stripos($message, 'SSL certificate problem') !== false) {
|
||||
return 'Gemini test failed: SSL certificate trust issue in local PHP/cURL. Local use is possible; this build auto-relaxes SSL only in development/testing. If still failing, configure CA bundle in PHP.';
|
||||
}
|
||||
|
||||
return 'Gemini test failed: ' . $message;
|
||||
}
|
||||
|
||||
private function geminiHttpFailureMessage(int $status, string $body): string
|
||||
{
|
||||
if ($status === 429) {
|
||||
return 'Gemini test failed: Rate limit/quota exceeded (HTTP 429). Please wait 1-2 minutes, then retry. If it continues, check API quota/billing in Google AI Studio.';
|
||||
}
|
||||
|
||||
if ($status === 403) {
|
||||
return 'Gemini test failed: API key not permitted for this request (HTTP 403). Verify key and project permissions.';
|
||||
}
|
||||
|
||||
if ($status === 404) {
|
||||
return 'Gemini test failed: Model endpoint not found (HTTP 404). Please verify Gemini API availability for this key/project.';
|
||||
}
|
||||
|
||||
if ($status <= 0) {
|
||||
return 'Gemini test failed: No HTTP response received.';
|
||||
}
|
||||
|
||||
$message = 'Gemini test failed (HTTP ' . $status . ')';
|
||||
$decoded = json_decode($body, true);
|
||||
$apiMessage = trim((string) ($decoded['error']['message'] ?? ''));
|
||||
if ($apiMessage !== '') {
|
||||
$message .= ': ' . $apiMessage;
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
private function geminiModelCandidates(): array
|
||||
{
|
||||
return [
|
||||
'gemini-2.0-flash',
|
||||
'gemini-1.5-flash',
|
||||
'gemini-1.5-flash-latest',
|
||||
];
|
||||
}
|
||||
|
||||
private function canManageAiSettings(): bool
|
||||
{
|
||||
if (! function_exists('auth') || ! auth()->loggedIn()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function readSettingValue(string $name): string
|
||||
{
|
||||
if (defined($name)) {
|
||||
$definedValue = trim((string) constant($name));
|
||||
if ($definedValue !== '') {
|
||||
return $definedValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('hospital_setting')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$row = $this->db->table('hospital_setting')
|
||||
->select('s_value')
|
||||
->where('s_name', $name)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
$value = trim((string) ($row['s_value'] ?? ''));
|
||||
if ($value !== '') {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$rows = $this->db->table('hospital_setting')
|
||||
->select('s_name, s_value')
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
$target = strtoupper(trim($name));
|
||||
foreach ($rows as $item) {
|
||||
$itemName = strtoupper(trim((string) ($item['s_name'] ?? '')));
|
||||
if ($itemName === $target) {
|
||||
$itemValue = trim((string) ($item['s_value'] ?? ''));
|
||||
if ($itemValue !== '') {
|
||||
return $itemValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function upsertSettingValue(string $name, string $value): bool
|
||||
{
|
||||
$existing = $this->db->table('hospital_setting')
|
||||
->select('id, s_value')
|
||||
->where('s_name', $name)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
$oldValue = trim((string) ($existing['s_value'] ?? ''));
|
||||
if ($existing) {
|
||||
$ok = $this->db->table('hospital_setting')
|
||||
->where('id', (int) ($existing['id'] ?? 0))
|
||||
->update(['s_value' => $value]);
|
||||
} else {
|
||||
$ok = $this->db->table('hospital_setting')->insert([
|
||||
's_name' => $name,
|
||||
's_value' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($ok) {
|
||||
$this->auditClinicalUpdate('hospital_setting', $name, $name, $oldValue, $value);
|
||||
}
|
||||
|
||||
return (bool) $ok;
|
||||
}
|
||||
|
||||
private function maskKey(string $key): string
|
||||
{
|
||||
$key = trim($key);
|
||||
if ($key === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (mb_strlen($key) <= 8) {
|
||||
return str_repeat('*', mb_strlen($key));
|
||||
}
|
||||
|
||||
return mb_substr($key, 0, 4) . str_repeat('*', mb_strlen($key) - 8) . mb_substr($key, -4);
|
||||
}
|
||||
}
|
||||
209
app/Controllers/Setting/Bank.php
Normal file
209
app/Controllers/Setting/Bank.php
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\BankModel;
|
||||
|
||||
class Bank extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
$model = new BankModel();
|
||||
|
||||
return view('Setting/Bank/bank_search_v', [
|
||||
'banks' => $model->getBanks(),
|
||||
'sources' => $model->getPaymentSources(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createBank()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$name = trim((string) $this->request->getPost('bank_name'));
|
||||
if ($name === '') {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Bank name is required.']);
|
||||
}
|
||||
|
||||
$model = new BankModel();
|
||||
$insertId = $model->insertBank($name);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createBankWithSource()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$bankName = trim((string) $this->request->getPost('bank_name'));
|
||||
$payType = trim((string) $this->request->getPost('pay_type'));
|
||||
|
||||
if ($bankName === '') {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Bank name is required.']);
|
||||
}
|
||||
|
||||
$model = new BankModel();
|
||||
$bankId = $model->insertBank($bankName);
|
||||
if ($bankId <= 0) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Please check']);
|
||||
}
|
||||
|
||||
if ($payType !== '') {
|
||||
$model->insertPaymentSource($bankId, $payType);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $bankId,
|
||||
'error_text' => '',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function sources(int $bankId)
|
||||
{
|
||||
$model = new BankModel();
|
||||
|
||||
return $this->response->setJSON([
|
||||
'sources' => $model->getPaymentSourcesByBank($bankId),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateBank()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('bank_id');
|
||||
$name = trim((string) $this->request->getPost('bank_name'));
|
||||
|
||||
if ($id <= 0 || $name === '') {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid data']);
|
||||
}
|
||||
|
||||
$model = new BankModel();
|
||||
$updated = $model->updateBank($id, $name);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'error_text' => $updated ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteBank()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('bank_id');
|
||||
if ($id <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid bank ID']);
|
||||
}
|
||||
|
||||
$model = new BankModel();
|
||||
if ($model->countPaymentSourcesForBank($id) > 0) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Remove payment sources before deleting the bank.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$deleted = $model->deleteBank($id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createSource()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$bankId = (int) $this->request->getPost('bank_id');
|
||||
$payType = trim((string) $this->request->getPost('pay_type'));
|
||||
|
||||
if ($bankId <= 0 || $payType === '') {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Bank and pay type are required.']);
|
||||
}
|
||||
|
||||
$model = new BankModel();
|
||||
$insertId = $model->insertPaymentSource($bankId, $payType);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateSource()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('source_id');
|
||||
$bankId = (int) $this->request->getPost('bank_id');
|
||||
$payType = trim((string) $this->request->getPost('pay_type'));
|
||||
|
||||
if ($id <= 0 || $bankId <= 0 || $payType === '') {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid data']);
|
||||
}
|
||||
|
||||
$model = new BankModel();
|
||||
$updated = $model->updatePaymentSource($id, $bankId, $payType);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'error_text' => $updated ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteSource()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('source_id');
|
||||
if ($id <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid source ID']);
|
||||
}
|
||||
|
||||
$model = new BankModel();
|
||||
$deleted = $model->deletePaymentSource($id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
394
app/Controllers/Setting/BedManagement.php
Normal file
394
app/Controllers/Setting/BedManagement.php
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\BedAssignmentHistoryModel;
|
||||
use App\Models\BedCategoryModel;
|
||||
use App\Models\BedMaintenanceLogModel;
|
||||
use App\Models\BedMasterModel;
|
||||
use App\Models\WardModel;
|
||||
|
||||
class BedManagement extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
return view('Setting/Bed/index');
|
||||
}
|
||||
|
||||
private function normalizeDateTime(?string $value): ?string
|
||||
{
|
||||
$value = trim((string) $value);
|
||||
if ($value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return str_replace('T', ' ', $value);
|
||||
}
|
||||
|
||||
private function bedCodeExists(string $bedCode, int $excludeId = 0): bool
|
||||
{
|
||||
$builder = $this->db->table('bed_master')->where('bed_code', $bedCode);
|
||||
if ($excludeId > 0) {
|
||||
$builder->where('id !=', $excludeId);
|
||||
}
|
||||
|
||||
return $builder->countAllResults() > 0;
|
||||
}
|
||||
|
||||
private function wardBedExists(int $wardId, string $bedNumber, int $excludeId = 0): bool
|
||||
{
|
||||
$builder = $this->db->table('bed_master')
|
||||
->where('ward_id', $wardId)
|
||||
->where('bed_number', $bedNumber);
|
||||
if ($excludeId > 0) {
|
||||
$builder->where('id !=', $excludeId);
|
||||
}
|
||||
|
||||
return $builder->countAllResults() > 0;
|
||||
}
|
||||
|
||||
public function categories(): string
|
||||
{
|
||||
$model = new BedCategoryModel();
|
||||
|
||||
return view('Setting/Bed/category_list', [
|
||||
'categories' => $model->getAll(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function saveCategory()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('id');
|
||||
$code = trim((string) $this->request->getPost('category_code'));
|
||||
$name = trim((string) $this->request->getPost('category_name'));
|
||||
|
||||
if ($code === '' || $name === '') {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Category code and name are required.']);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'category_code' => $code,
|
||||
'category_name' => $name,
|
||||
'category_type' => $this->request->getPost('category_type'),
|
||||
'base_charge_per_day' => $this->request->getPost('base_charge_per_day') ?? 0,
|
||||
'nursing_charge_per_day' => $this->request->getPost('nursing_charge_per_day') ?? 0,
|
||||
'amenities' => $this->request->getPost('amenities'),
|
||||
'description' => $this->request->getPost('description'),
|
||||
'status' => $this->request->getPost('status') ?? 'active',
|
||||
];
|
||||
|
||||
$model = new BedCategoryModel();
|
||||
if ($id > 0) {
|
||||
$updated = $model->update($id, $data);
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$insertId = $model->insert($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteCategory()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('id');
|
||||
if ($id <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid category ID']);
|
||||
}
|
||||
|
||||
$model = new BedCategoryModel();
|
||||
$deleted = $model->delete($id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function beds(): string
|
||||
{
|
||||
$bedModel = new BedMasterModel();
|
||||
$wardModel = new WardModel();
|
||||
$categoryModel = new BedCategoryModel();
|
||||
|
||||
return view('Setting/Bed/bed_list', [
|
||||
'beds' => $bedModel->getAllWithRelations(),
|
||||
'wards' => $wardModel->getAllActive(),
|
||||
'categories' => $categoryModel->getAll(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function saveBed()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('id');
|
||||
$bedCode = trim((string) $this->request->getPost('bed_code'));
|
||||
$bedNumber = trim((string) $this->request->getPost('bed_number'));
|
||||
$wardId = (int) $this->request->getPost('ward_id');
|
||||
$categoryId = (int) $this->request->getPost('bed_category_id');
|
||||
|
||||
if ($bedCode === '' || $bedNumber === '' || $wardId <= 0 || $categoryId <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Bed code, number, ward and category are required.']);
|
||||
}
|
||||
|
||||
if ($this->bedCodeExists($bedCode, $id)) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Bed code already exists.']);
|
||||
}
|
||||
|
||||
if ($this->wardBedExists($wardId, $bedNumber, $id)) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Bed number already exists in this ward.']);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'bed_code' => $bedCode,
|
||||
'bed_number' => $bedNumber,
|
||||
'ward_id' => $wardId,
|
||||
'bed_category_id' => $categoryId,
|
||||
'bed_status' => $this->request->getPost('bed_status') ?? 'available',
|
||||
'bed_position' => $this->request->getPost('bed_position'),
|
||||
'has_oxygen' => $this->request->getPost('has_oxygen') ? 1 : 0,
|
||||
'has_suction' => $this->request->getPost('has_suction') ? 1 : 0,
|
||||
'has_monitor' => $this->request->getPost('has_monitor') ? 1 : 0,
|
||||
'has_ventilator' => $this->request->getPost('has_ventilator') ? 1 : 0,
|
||||
'is_isolation_bed' => $this->request->getPost('is_isolation_bed') ? 1 : 0,
|
||||
'base_charge_override' => $this->request->getPost('base_charge_override') ?: null,
|
||||
'nursing_charge_override' => $this->request->getPost('nursing_charge_override') ?: null,
|
||||
'status' => $this->request->getPost('status') ?? 'active',
|
||||
'remarks' => $this->request->getPost('remarks'),
|
||||
];
|
||||
|
||||
$model = new BedMasterModel();
|
||||
if ($id > 0) {
|
||||
$updated = $model->update($id, $data);
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$insertId = $model->insert($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteBed()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('id');
|
||||
if ($id <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid bed ID']);
|
||||
}
|
||||
|
||||
$model = new BedMasterModel();
|
||||
$deleted = $model->delete($id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function maintenance(): string
|
||||
{
|
||||
$bedModel = new BedMasterModel();
|
||||
$maintenanceModel = new BedMaintenanceLogModel();
|
||||
|
||||
return view('Setting/Bed/maintenance_list', [
|
||||
'beds' => $bedModel->getAllWithRelations(),
|
||||
'logs' => $maintenanceModel->getAllWithRelations(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function saveMaintenance()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('id');
|
||||
$bedId = (int) $this->request->getPost('bed_id');
|
||||
$type = trim((string) $this->request->getPost('maintenance_type'));
|
||||
|
||||
if ($bedId <= 0 || $type === '') {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Bed and maintenance type are required.']);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'bed_id' => $bedId,
|
||||
'maintenance_type' => $type,
|
||||
'scheduled_date' => $this->request->getPost('scheduled_date') ?: null,
|
||||
'completed_date' => $this->normalizeDateTime($this->request->getPost('completed_date')),
|
||||
'performed_by' => $this->request->getPost('performed_by'),
|
||||
'issue_description' => $this->request->getPost('issue_description'),
|
||||
'action_taken' => $this->request->getPost('action_taken'),
|
||||
'next_maintenance_date' => $this->request->getPost('next_maintenance_date') ?: null,
|
||||
'cost' => $this->request->getPost('cost') ?: 0,
|
||||
'status' => $this->request->getPost('status') ?? 'pending',
|
||||
];
|
||||
|
||||
$model = new BedMaintenanceLogModel();
|
||||
if ($id > 0) {
|
||||
$updated = $model->update($id, $data);
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$insertId = $model->insert($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteMaintenance()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('id');
|
||||
if ($id <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid maintenance ID']);
|
||||
}
|
||||
|
||||
$model = new BedMaintenanceLogModel();
|
||||
$deleted = $model->delete($id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function assignmentHistory(): string
|
||||
{
|
||||
$model = new BedAssignmentHistoryModel();
|
||||
$bedModel = new BedMasterModel();
|
||||
$wardModel = new WardModel();
|
||||
|
||||
return view('Setting/Bed/assignment_history', [
|
||||
'assignments' => $model->getAllWithRelations(),
|
||||
'beds' => $bedModel->getAllWithRelations(),
|
||||
'wards' => $wardModel->getAllActive(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function saveAssignment()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('id');
|
||||
$bedId = (int) $this->request->getPost('bed_id');
|
||||
$wardId = (int) $this->request->getPost('ward_id');
|
||||
$type = trim((string) $this->request->getPost('assignment_type'));
|
||||
$assignedDate = $this->normalizeDateTime($this->request->getPost('assigned_date'));
|
||||
|
||||
if ($bedId <= 0 || $wardId <= 0 || $type === '' || $assignedDate === null) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Bed, ward, assignment type and assigned date are required.']);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'ipd_id' => $this->request->getPost('ipd_id') ?: null,
|
||||
'bed_id' => $bedId,
|
||||
'assignment_type' => $type,
|
||||
'assigned_date' => $assignedDate,
|
||||
'discharged_date' => $this->normalizeDateTime($this->request->getPost('discharged_date')),
|
||||
'assigned_by' => $this->request->getPost('assigned_by') ?: null,
|
||||
'transfer_reason' => $this->request->getPost('transfer_reason'),
|
||||
'transfer_from_bed_id' => $this->request->getPost('transfer_from_bed_id') ?: null,
|
||||
'remarks' => $this->request->getPost('remarks'),
|
||||
'ward_id' => $wardId,
|
||||
'released_date' => $this->normalizeDateTime($this->request->getPost('released_date')),
|
||||
'total_days' => $this->request->getPost('total_days') ?: 0,
|
||||
'release_reason' => $this->request->getPost('release_reason'),
|
||||
];
|
||||
|
||||
$model = new BedAssignmentHistoryModel();
|
||||
if ($id > 0) {
|
||||
$updated = $model->update($id, $data);
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$insertId = $model->insert($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteAssignment()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('id');
|
||||
if ($id <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid assignment ID']);
|
||||
}
|
||||
|
||||
$model = new BedAssignmentHistoryModel();
|
||||
$deleted = $model->delete($id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
13
app/Controllers/Setting/Charges.php
Normal file
13
app/Controllers/Setting/Charges.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
|
||||
class Charges extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
return view('Setting/Charges/index');
|
||||
}
|
||||
}
|
||||
631
app/Controllers/Setting/Doctor.php
Normal file
631
app/Controllers/Setting/Doctor.php
Normal file
|
|
@ -0,0 +1,631 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\DoctorModel;
|
||||
|
||||
class Doctor extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
$doctorModel = new DoctorModel();
|
||||
|
||||
return view('Setting/Doctor/Doctor_Search_V', [
|
||||
'data' => $doctorModel->getDoctors(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(): string
|
||||
{
|
||||
$templateContext = $this->getDoctorTemplateContext();
|
||||
|
||||
return view('Setting/Doctor/Doctor_V', [
|
||||
'errors' => session('errors'),
|
||||
'template_options' => $templateContext['options'],
|
||||
'template_fields' => $templateContext['fields'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
$rules = [
|
||||
'input_name' => 'required',
|
||||
'input_email' => 'permit_empty|valid_email',
|
||||
'input_mphone1' => 'permit_empty|numeric',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
if ($this->request->isAJAX()) {
|
||||
$templateContext = $this->getDoctorTemplateContext();
|
||||
return view('Setting/Doctor/Doctor_V', [
|
||||
'errors' => $this->validator->getErrors(),
|
||||
'formData' => $this->request->getPost(),
|
||||
'template_options' => $templateContext['options'],
|
||||
'template_fields' => $templateContext['fields'],
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$regField = $this->resolveDoctorRegField();
|
||||
$shortDescription = trim((string) $this->request->getPost('txt_doc_sign'));
|
||||
$regInput = trim((string) $this->request->getPost('input_doc_reg_no'));
|
||||
if ($regInput === '' && $shortDescription !== '') {
|
||||
$regInput = $this->extractRegNoFromText($shortDescription);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'p_title' => $this->request->getPost('select_title'),
|
||||
'mphone1' => $this->request->getPost('input_mphone1'),
|
||||
'p_fname' => $this->request->getPost('input_name'),
|
||||
'gender' => $this->request->getPost('optionsRadios_gender'),
|
||||
'dob' => str_to_MysqlDate((string) $this->request->getPost('datepicker_dob')),
|
||||
'zip' => $this->request->getPost('input_zip'),
|
||||
'email1' => $this->request->getPost('input_email'),
|
||||
'doc_sign' => $shortDescription,
|
||||
];
|
||||
|
||||
$templateContext = $this->getDoctorTemplateContext();
|
||||
$templateFieldMap = [
|
||||
'opd_print_format' => 'tmpl_opd_print_format',
|
||||
'opd_blank_print' => 'tmpl_opd_blank_print',
|
||||
'rx_pre_print_letter_head_format' => 'tmpl_rx_pre_print_letter_head_format',
|
||||
'rx_blank_letter_head' => 'tmpl_rx_blank_letter_head',
|
||||
'rx_plain_paper' => 'tmpl_rx_plain_paper',
|
||||
];
|
||||
foreach ($templateFieldMap as $dbField => $inputField) {
|
||||
if (! in_array($dbField, $templateContext['fields'], true)) {
|
||||
continue;
|
||||
}
|
||||
$templateName = strtolower(trim((string) $this->request->getPost($inputField)));
|
||||
$templateName = preg_replace('/[^a-z0-9_\-]/', '', $templateName) ?? '';
|
||||
$data[$dbField] = $templateName;
|
||||
}
|
||||
|
||||
if ($regField !== null) {
|
||||
$data[$regField] = $regInput;
|
||||
}
|
||||
|
||||
$insertId = $doctorModel->insert($data);
|
||||
|
||||
if ($insertId <= 0) {
|
||||
$errors = ['Unable to create doctor.'];
|
||||
if ($this->request->isAJAX()) {
|
||||
$templateContext = $this->getDoctorTemplateContext();
|
||||
return view('Setting/Doctor/Doctor_V', [
|
||||
'errors' => $errors,
|
||||
'formData' => $this->request->getPost(),
|
||||
'template_options' => $templateContext['options'],
|
||||
'template_fields' => $templateContext['fields'],
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->with('errors', $errors);
|
||||
}
|
||||
|
||||
return $this->doctorRecord($insertId);
|
||||
}
|
||||
|
||||
public function doctorRecord(int $id): string
|
||||
{
|
||||
$doctorModel = new DoctorModel();
|
||||
$templateContext = $this->getDoctorTemplateContext();
|
||||
|
||||
return view('Setting/Doctor/Doctor_profile_V', [
|
||||
'data' => $doctorModel->getDoctorById($id),
|
||||
'doc_spec_a' => $doctorModel->getDoctorSpecs($id),
|
||||
'doc_spec_l' => $doctorModel->getSpecsList(),
|
||||
'doc_fee_type' => $doctorModel->getFeeTypes(),
|
||||
'doc_fee_list' => $doctorModel->getDoctorFees($id),
|
||||
'doc_ipd_fee_list' => $doctorModel->getDoctorIpdFees($id),
|
||||
'doc_ipd_fee_type' => $doctorModel->getIpdFeeTypes(),
|
||||
'template_options' => $templateContext['options'],
|
||||
'template_fields' => $templateContext['fields'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateRecord()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$regField = $this->resolveDoctorRegField();
|
||||
$shortDescription = trim((string) $this->request->getPost('txt_doc_sign'));
|
||||
$regInput = trim((string) $this->request->getPost('input_doc_reg_no'));
|
||||
if ($regInput === '' && $shortDescription !== '') {
|
||||
$regInput = $this->extractRegNoFromText($shortDescription);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'p_title' => $this->request->getPost('select_title'),
|
||||
'mphone1' => $this->request->getPost('input_mphone1'),
|
||||
'p_fname' => $this->request->getPost('input_name'),
|
||||
'gender' => $this->request->getPost('optionsRadios_gender'),
|
||||
'dob' => str_to_MysqlDate((string) $this->request->getPost('datepicker_dob')),
|
||||
'zip' => $this->request->getPost('input_zip'),
|
||||
'doc_sign' => $shortDescription,
|
||||
'email1' => $this->request->getPost('input_email'),
|
||||
];
|
||||
|
||||
$templateContext = $this->getDoctorTemplateContext();
|
||||
$templateFieldMap = [
|
||||
'opd_print_format' => 'tmpl_opd_print_format',
|
||||
'opd_blank_print' => 'tmpl_opd_blank_print',
|
||||
'rx_pre_print_letter_head_format' => 'tmpl_rx_pre_print_letter_head_format',
|
||||
'rx_blank_letter_head' => 'tmpl_rx_blank_letter_head',
|
||||
'rx_plain_paper' => 'tmpl_rx_plain_paper',
|
||||
];
|
||||
foreach ($templateFieldMap as $dbField => $inputField) {
|
||||
if (! in_array($dbField, $templateContext['fields'], true)) {
|
||||
continue;
|
||||
}
|
||||
$templateName = strtolower(trim((string) $this->request->getPost($inputField)));
|
||||
$templateName = preg_replace('/[^a-z0-9_\-]/', '', $templateName) ?? '';
|
||||
$data[$dbField] = $templateName;
|
||||
}
|
||||
|
||||
if ($regField !== null) {
|
||||
$data[$regField] = $regInput;
|
||||
}
|
||||
|
||||
$updated = $doctorModel->updateDoctor($data, $docId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : '',
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
]);
|
||||
}
|
||||
|
||||
public function doctorRecordSpec()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$isAdd = (int) $this->request->getPost('isadd') === 1;
|
||||
|
||||
if ($isAdd) {
|
||||
$specId = (int) $this->request->getPost('doc_spec');
|
||||
if ($specId > 0 && ! $doctorModel->specExists($docId, $specId)) {
|
||||
$doctorModel->insertSpec([
|
||||
'doc_id' => $docId,
|
||||
'med_spec_id' => $specId,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$specId = (int) $this->request->getPost('doc_spec_id');
|
||||
if ($specId > 0) {
|
||||
$doctorModel->removeSpec($specId);
|
||||
}
|
||||
}
|
||||
|
||||
$specListHtml = $this->renderSpecList($doctorModel->getDoctorSpecs($docId));
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => 1,
|
||||
'show_Specility_list' => $specListHtml,
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addFee()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['inser_id' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$feeType = (int) $this->request->getPost('fee_type');
|
||||
|
||||
$existing = $doctorModel->getDoctorFeeByType($docId, $feeType);
|
||||
if ($existing !== null) {
|
||||
$doctorModel->removeFee((int) $existing->id, $this->getFeeAuditData());
|
||||
}
|
||||
|
||||
$insertId = $doctorModel->insertFee([
|
||||
'doc_id' => $docId,
|
||||
'doc_fee_desc' => $this->request->getPost('input_fee_desc'),
|
||||
'doc_fee_type' => $feeType,
|
||||
'amount' => $this->request->getPost('input_fee_amount'),
|
||||
]);
|
||||
|
||||
$feeList = $doctorModel->getDoctorFees($docId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'inser_id' => $insertId > 0 ? 1 : 0,
|
||||
'showcontent' => $insertId > 0 ? 'Fee added successfully' : '',
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'show_fee_list' => $this->renderFeeList($feeList),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function addIpdFee()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['inser_id' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$feeType = (int) $this->request->getPost('fee_type');
|
||||
|
||||
$existing = $doctorModel->getDoctorIpdFeeByType($docId, $feeType);
|
||||
if ($existing !== null) {
|
||||
$doctorModel->removeIpdFee((int) $existing->id);
|
||||
}
|
||||
|
||||
$insertId = $doctorModel->insertIpdFee([
|
||||
'doc_id' => $docId,
|
||||
'doc_fee_desc' => $this->request->getPost('input_fee_desc'),
|
||||
'doc_fee_type' => $feeType,
|
||||
'amount' => $this->request->getPost('input_fee_amount'),
|
||||
]);
|
||||
|
||||
$feeList = $doctorModel->getDoctorIpdFees($docId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'inser_id' => $insertId > 0 ? 1 : 0,
|
||||
'showcontent' => $insertId > 0 ? 'IPD Fee added successfully' : '',
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
'show_fee_list' => $this->renderFeeList($feeList),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function removeFee()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$removeId = (int) $this->request->getPost('rid');
|
||||
|
||||
$deleted = $doctorModel->removeFee($removeId, $this->getFeeAuditData());
|
||||
|
||||
$feeList = $doctorModel->getDoctorFees($docId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'showcontent' => $deleted ? 'Fee Removed successfully' : '',
|
||||
'error_text' => $deleted ? '' : 'Please Check',
|
||||
'show_fee_list' => $this->renderFeeList($feeList),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function removeIpdFee()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$docId = (int) $this->request->getPost('doc_id');
|
||||
$removeId = (int) $this->request->getPost('rid');
|
||||
|
||||
$deleted = $doctorModel->removeIpdFee($removeId);
|
||||
|
||||
$feeList = $doctorModel->getDoctorIpdFees($docId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'showcontent' => $deleted ? 'IPD Fee Removed successfully' : '',
|
||||
'error_text' => $deleted ? '' : 'Please Check',
|
||||
'show_fee_list' => $this->renderFeeList($feeList),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function specs(): string
|
||||
{
|
||||
$doctorModel = new DoctorModel();
|
||||
|
||||
return view('Setting/Doctor/Spec_List', [
|
||||
'specs' => $doctorModel->getMedSpecs(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function ipdFeeTypes(): string
|
||||
{
|
||||
$doctorModel = new DoctorModel();
|
||||
|
||||
return view('Setting/Doctor/Ipd_FeeType_List', [
|
||||
'feeTypes' => $doctorModel->getIpdFeeTypes(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeIpdFeeType()
|
||||
{
|
||||
$name = trim((string) $this->request->getPost('fee_type'));
|
||||
if ($name === '') {
|
||||
return $this->renderIpdFeeTypeListWithErrors(['fee_type' => 'Fee type is required.']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$doctorModel->insertIpdFeeType($name);
|
||||
|
||||
return $this->renderIpdFeeTypeListWithMessage('IPD fee type added successfully.');
|
||||
}
|
||||
|
||||
public function updateIpdFeeType()
|
||||
{
|
||||
$id = (int) $this->request->getPost('id');
|
||||
$name = trim((string) $this->request->getPost('fee_type'));
|
||||
if ($id <= 0 || $name === '') {
|
||||
return $this->renderIpdFeeTypeListWithErrors(['fee_type' => 'Fee type is required.']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$doctorModel->updateIpdFeeType($id, $name);
|
||||
|
||||
return $this->renderIpdFeeTypeListWithMessage('IPD fee type updated successfully.');
|
||||
}
|
||||
|
||||
public function deleteIpdFeeType()
|
||||
{
|
||||
$id = (int) $this->request->getPost('id');
|
||||
if ($id <= 0) {
|
||||
return $this->renderIpdFeeTypeListWithErrors(['fee_type' => 'Invalid fee type.']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$doctorModel->deleteIpdFeeType($id);
|
||||
|
||||
return $this->renderIpdFeeTypeListWithMessage('IPD fee type deleted successfully.');
|
||||
}
|
||||
|
||||
public function storeSpec()
|
||||
{
|
||||
$name = trim((string) $this->request->getPost('SpecName'));
|
||||
if ($name === '') {
|
||||
return $this->renderSpecListWithErrors(['SpecName' => 'Spec name is required.']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$doctorModel->insertMedSpec($name);
|
||||
|
||||
return $this->renderSpecListWithMessage('Speciality added successfully.');
|
||||
}
|
||||
|
||||
public function updateSpec()
|
||||
{
|
||||
$id = (int) $this->request->getPost('id');
|
||||
$name = trim((string) $this->request->getPost('SpecName'));
|
||||
if ($id <= 0 || $name === '') {
|
||||
return $this->renderSpecListWithErrors(['SpecName' => 'Spec name is required.']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$doctorModel->updateMedSpec($id, $name);
|
||||
|
||||
return $this->renderSpecListWithMessage('Speciality updated successfully.');
|
||||
}
|
||||
|
||||
public function deleteSpec()
|
||||
{
|
||||
$id = (int) $this->request->getPost('id');
|
||||
if ($id <= 0) {
|
||||
return $this->renderSpecListWithErrors(['SpecName' => 'Invalid speciality.']);
|
||||
}
|
||||
|
||||
$doctorModel = new DoctorModel();
|
||||
$doctorModel->deleteMedSpec($id);
|
||||
|
||||
return $this->renderSpecListWithMessage('Speciality deleted successfully.');
|
||||
}
|
||||
|
||||
private function renderSpecList(array $specs): string
|
||||
{
|
||||
$html = '';
|
||||
foreach ($specs as $row) {
|
||||
$name = esc($row->SpecName ?? '');
|
||||
$docSpecId = (int) ($row->doc_spec_id ?? 0);
|
||||
$html .= '<div class="input-group input-group-sm">';
|
||||
$html .= '<input class="form-control" type="text" value="' . $name . '" readonly />';
|
||||
$html .= '<span class="input-group-btn">';
|
||||
$html .= '<button type="button" class="btn btn-info btn-flat" onclick="remove_doc_spec(' . $docSpecId . ')">Remove -</button>';
|
||||
$html .= '</span>';
|
||||
$html .= '</div>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function renderFeeList(array $feeList): string
|
||||
{
|
||||
$html = '<table class="table table-striped">';
|
||||
$html .= '<thead><tr><th>Fee Type</th><th>Description</th><th>Amount</th><th></th></tr></thead>';
|
||||
$html .= '<tbody>';
|
||||
foreach ($feeList as $row) {
|
||||
$feeType = esc($row->fee_type ?? '');
|
||||
$desc = esc($row->doc_fee_desc ?? '');
|
||||
$amount = esc($row->amount ?? '');
|
||||
$button = 'Not Define';
|
||||
if (! empty($row->id)) {
|
||||
$button = '<a href="javascript:remove_fees(' . (int) $row->id . ')">Remove</a>';
|
||||
}
|
||||
$html .= '<tr><td>' . $feeType . '</td><td>' . $desc . '</td><td>' . $amount . '</td><td>' . $button . '</td></tr>';
|
||||
}
|
||||
$html .= '</tbody></table>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function renderSpecListWithMessage(string $message)
|
||||
{
|
||||
$doctorModel = new DoctorModel();
|
||||
|
||||
return view('Setting/Doctor/Spec_List', [
|
||||
'specs' => $doctorModel->getMedSpecs(),
|
||||
'message' => $message,
|
||||
]);
|
||||
}
|
||||
|
||||
private function renderSpecListWithErrors(array $errors)
|
||||
{
|
||||
$doctorModel = new DoctorModel();
|
||||
|
||||
return view('Setting/Doctor/Spec_List', [
|
||||
'specs' => $doctorModel->getMedSpecs(),
|
||||
'errors' => $errors,
|
||||
]);
|
||||
}
|
||||
|
||||
private function renderIpdFeeTypeListWithMessage(string $message)
|
||||
{
|
||||
$doctorModel = new DoctorModel();
|
||||
|
||||
return view('Setting/Doctor/Ipd_FeeType_List', [
|
||||
'feeTypes' => $doctorModel->getIpdFeeTypes(),
|
||||
'message' => $message,
|
||||
]);
|
||||
}
|
||||
|
||||
private function renderIpdFeeTypeListWithErrors(array $errors)
|
||||
{
|
||||
$doctorModel = new DoctorModel();
|
||||
|
||||
return view('Setting/Doctor/Ipd_FeeType_List', [
|
||||
'feeTypes' => $doctorModel->getIpdFeeTypes(),
|
||||
'errors' => $errors,
|
||||
]);
|
||||
}
|
||||
|
||||
private function getFeeAuditData(): array
|
||||
{
|
||||
$user = auth()->user();
|
||||
$name = 'System';
|
||||
if ($user !== null) {
|
||||
$name = trim(($user->username ?? '') . ' ' . ($user->email ?? ''));
|
||||
}
|
||||
|
||||
return [
|
||||
'remove_update_by' => trim($name) . ' [' . date('d-m-Y H:i') . ']',
|
||||
];
|
||||
}
|
||||
|
||||
private function resolveDoctorRegField(): ?string
|
||||
{
|
||||
if (! $this->db->tableExists('doctor_master')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$fields = $this->db->getFieldNames('doctor_master');
|
||||
foreach (['nmc_reg_no', 'mci_reg_no', 'registration_no', 'reg_no', 'doctor_reg_no', 'doc_reg_no', 'council_reg_no'] as $field) {
|
||||
if (in_array($field, $fields, true)) {
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function extractRegNoFromText(string $text): string
|
||||
{
|
||||
$normalized = preg_replace('/\s+/', ' ', trim($text));
|
||||
if ($normalized === null || $normalized === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$patterns = [
|
||||
'/(?:reg(?:istration)?\s*(?:no|number)?\s*[:\-]?\s*)([A-Z0-9\/-]{4,})/i',
|
||||
'/(?:nmc|mci)\s*(?:reg(?:istration)?\s*(?:no|number)?\s*[:\-]?\s*)([A-Z0-9\/-]{4,})/i',
|
||||
];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
if (preg_match($pattern, $normalized, $matches) === 1 && ! empty($matches[1])) {
|
||||
return trim((string) $matches[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{fields:array<int,string>,options:array<int,string>}
|
||||
*/
|
||||
private function getDoctorTemplateContext(): array
|
||||
{
|
||||
$allTemplateFields = [
|
||||
'opd_print_format',
|
||||
'opd_blank_print',
|
||||
'rx_pre_print_letter_head_format',
|
||||
'rx_blank_letter_head',
|
||||
'rx_plain_paper',
|
||||
];
|
||||
|
||||
if (! $this->db->tableExists('doctor_master')) {
|
||||
return ['fields' => [], 'options' => []];
|
||||
}
|
||||
|
||||
$doctorFields = $this->db->getFieldNames('doctor_master') ?? [];
|
||||
$availableFields = array_values(array_intersect($allTemplateFields, $doctorFields));
|
||||
|
||||
$options = [];
|
||||
|
||||
$templateDir = APPPATH . 'Views/billing/opd_templates';
|
||||
if (is_dir($templateDir)) {
|
||||
$htmlFiles = glob($templateDir . '/*.html') ?: [];
|
||||
foreach ($htmlFiles as $file) {
|
||||
$name = strtolower(trim((string) basename((string) $file, '.html')));
|
||||
$name = preg_replace('/[^a-z0-9_\-]/', '', $name) ?? '';
|
||||
if ($name !== '') {
|
||||
$options[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$phpFiles = glob($templateDir . '/*.php') ?: [];
|
||||
foreach ($phpFiles as $file) {
|
||||
$name = strtolower(trim((string) basename((string) $file, '.php')));
|
||||
$name = preg_replace('/[^a-z0-9_\-]/', '', $name) ?? '';
|
||||
if ($name !== '') {
|
||||
$options[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($availableFields as $field) {
|
||||
$rows = $this->db->table('doctor_master')
|
||||
->select($field . ' as template_name')
|
||||
->where($field . ' IS NOT NULL', null, false)
|
||||
->where($field . ' !=', '')
|
||||
->distinct()
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$name = strtolower(trim((string) ($row['template_name'] ?? '')));
|
||||
$name = preg_replace('/[^a-z0-9_\-]/', '', $name) ?? '';
|
||||
if ($name !== '') {
|
||||
$options[] = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$options = array_values(array_unique($options));
|
||||
sort($options);
|
||||
|
||||
return [
|
||||
'fields' => $availableFields,
|
||||
'options' => $options,
|
||||
];
|
||||
}
|
||||
}
|
||||
113
app/Controllers/Setting/Insurance.php
Normal file
113
app/Controllers/Setting/Insurance.php
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\InsuranceModel;
|
||||
|
||||
class Insurance extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
$model = new InsuranceModel();
|
||||
|
||||
return view('Setting/Insurance/insurance_search_v', [
|
||||
'data' => $model->getAll(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(): string
|
||||
{
|
||||
return view('Setting/Insurance/insurance_create_V', [
|
||||
'errors' => session('errors'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'input_comp_name' => 'required',
|
||||
'input_email' => 'permit_empty|valid_email',
|
||||
'input_mphone1' => 'permit_empty',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => implode(' ', $this->validator->getErrors()),
|
||||
]);
|
||||
}
|
||||
|
||||
$model = new InsuranceModel();
|
||||
$data = [
|
||||
'ins_company_name' => $this->request->getPost('input_comp_name'),
|
||||
'ins_contact_number' => $this->request->getPost('input_mphone1'),
|
||||
'ins_contact_person_name' => $this->request->getPost('input_cname'),
|
||||
'ins_email' => $this->request->getPost('input_email'),
|
||||
'gst_no' => $this->request->getPost('input_gst_no'),
|
||||
'agreement_start_date' => str_to_MysqlDate((string) $this->request->getPost('input_agreement_start_date')),
|
||||
'agreement_end_date' => str_to_MysqlDate((string) $this->request->getPost('input_agreement_end_date')),
|
||||
];
|
||||
|
||||
$insertId = $model->insert($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
]);
|
||||
}
|
||||
|
||||
public function record(int $id): string
|
||||
{
|
||||
$model = new InsuranceModel();
|
||||
|
||||
return view('Setting/Insurance/insurance_profile_V', [
|
||||
'data_insurance' => $model->getById($id),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new InsuranceModel();
|
||||
$id = (int) $this->request->getPost('p_id');
|
||||
|
||||
$data = [
|
||||
'ins_company_name' => $this->request->getPost('input_comp_name'),
|
||||
'short_name' => $this->request->getPost('input_short_name'),
|
||||
'ins_contact_number' => $this->request->getPost('input_mphone1'),
|
||||
'ins_contact_person_name' => $this->request->getPost('input_cname'),
|
||||
'ins_email' => $this->request->getPost('input_email'),
|
||||
'gst_no' => $this->request->getPost('input_gst_no'),
|
||||
'agreement_start_date' => str_to_MysqlDate((string) $this->request->getPost('input_agreement_start_date')),
|
||||
'agreement_end_date' => str_to_MysqlDate((string) $this->request->getPost('input_agreement_end_date')),
|
||||
'active' => $this->request->getPost('chk_active') ? 1 : 0,
|
||||
'opd_allowed' => $this->request->getPost('chk_opd_allowed') ? 1 : 0,
|
||||
'opd_fee' => $this->request->getPost('input_opd_fee'),
|
||||
'opd_rate_direct' => $this->request->getPost('optionsRadios_opd_rate_direct'),
|
||||
'opd_desc' => $this->request->getPost('input_opd_fee_desc'),
|
||||
'opd_master_rate_discount' => $this->request->getPost('input_opd_master_rate_discount'),
|
||||
'opd_credit' => $this->request->getPost('chk_opd_credit') ? 1 : 0,
|
||||
'opd_cash' => $this->request->getPost('chk_opd_cash') ? 1 : 0,
|
||||
'charge_credit' => $this->request->getPost('chk_charge_credit') ? 1 : 0,
|
||||
'charge_rate_direct' => $this->request->getPost('optionsRadios_charge_rate_direct'),
|
||||
'charge_rate_dicount' => $this->request->getPost('input_charge_rate_dicount'),
|
||||
'med_credit' => $this->request->getPost('chk_med_credit') ? 1 : 0,
|
||||
];
|
||||
|
||||
$updated = $model->updateInsurance($data, $id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'showcontent' => $updated ? 'Data Saved successfully' : '',
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
]);
|
||||
}
|
||||
}
|
||||
208
app/Controllers/Setting/MedicalBank.php
Normal file
208
app/Controllers/Setting/MedicalBank.php
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\MedicalBankModel;
|
||||
|
||||
class MedicalBank extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
$model = new MedicalBankModel();
|
||||
|
||||
return view('Setting/MedicalBank/bank_search_v', [
|
||||
'banks' => $model->getBanks(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createBank()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$name = trim((string) $this->request->getPost('bank_name'));
|
||||
if ($name === '') {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Bank name is required.']);
|
||||
}
|
||||
|
||||
$model = new MedicalBankModel();
|
||||
$insertId = $model->insertBank($name);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createBankWithSource()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$bankName = trim((string) $this->request->getPost('bank_name'));
|
||||
$payType = trim((string) $this->request->getPost('pay_type'));
|
||||
|
||||
if ($bankName === '') {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Bank name is required.']);
|
||||
}
|
||||
|
||||
$model = new MedicalBankModel();
|
||||
$bankId = $model->insertBank($bankName);
|
||||
if ($bankId <= 0) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Please check']);
|
||||
}
|
||||
|
||||
if ($payType !== '') {
|
||||
$model->insertPaymentSource($bankId, $payType);
|
||||
}
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $bankId,
|
||||
'error_text' => '',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function sources(int $bankId)
|
||||
{
|
||||
$model = new MedicalBankModel();
|
||||
|
||||
return $this->response->setJSON([
|
||||
'sources' => $model->getPaymentSourcesByBank($bankId),
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateBank()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('bank_id');
|
||||
$name = trim((string) $this->request->getPost('bank_name'));
|
||||
|
||||
if ($id <= 0 || $name === '') {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid data']);
|
||||
}
|
||||
|
||||
$model = new MedicalBankModel();
|
||||
$updated = $model->updateBank($id, $name);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'error_text' => $updated ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteBank()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('bank_id');
|
||||
if ($id <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid bank ID']);
|
||||
}
|
||||
|
||||
$model = new MedicalBankModel();
|
||||
if ($model->countPaymentSourcesForBank($id) > 0) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => 'Remove payment sources before deleting the bank.',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
$deleted = $model->deleteBank($id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function createSource()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$bankId = (int) $this->request->getPost('bank_id');
|
||||
$payType = trim((string) $this->request->getPost('pay_type'));
|
||||
|
||||
if ($bankId <= 0 || $payType === '') {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Bank and pay type are required.']);
|
||||
}
|
||||
|
||||
$model = new MedicalBankModel();
|
||||
$insertId = $model->insertPaymentSource($bankId, $payType);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateSource()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('source_id');
|
||||
$bankId = (int) $this->request->getPost('bank_id');
|
||||
$payType = trim((string) $this->request->getPost('pay_type'));
|
||||
|
||||
if ($id <= 0 || $bankId <= 0 || $payType === '') {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid data']);
|
||||
}
|
||||
|
||||
$model = new MedicalBankModel();
|
||||
$updated = $model->updatePaymentSource($id, $bankId, $payType);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'error_text' => $updated ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function deleteSource()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int) $this->request->getPost('source_id');
|
||||
if ($id <= 0) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid source ID']);
|
||||
}
|
||||
|
||||
$model = new MedicalBankModel();
|
||||
$deleted = $model->deletePaymentSource($id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $deleted ? 1 : 0,
|
||||
'error_text' => $deleted ? '' : 'Please check',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
199
app/Controllers/Setting/Reffer.php
Normal file
199
app/Controllers/Setting/Reffer.php
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\RefferModel;
|
||||
|
||||
class Reffer extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
$model = new RefferModel();
|
||||
|
||||
return view('Setting/Reffer/reffer_index', [
|
||||
'refer_master' => $model->getAll(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(): string
|
||||
{
|
||||
$model = new RefferModel();
|
||||
|
||||
return view('Setting/Reffer/reffer_add', [
|
||||
'refer_type' => $model->getTypes(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $id): string
|
||||
{
|
||||
$model = new RefferModel();
|
||||
|
||||
return view('Setting/Reffer/reffer_edit', [
|
||||
'data' => $model->getById($id),
|
||||
'refer_type' => $model->getTypes(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['insertid' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'input_name' => 'required|min_length[1]|max_length[30]',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'error_text' => implode(' ', $this->validator->getErrors()),
|
||||
]);
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$userLabel = $user ? trim(($user->username ?? '') . '[' . ($user->id ?? '') . ']') : 'System';
|
||||
|
||||
$model = new RefferModel();
|
||||
$data = [
|
||||
'title' => $this->request->getPost('cbo_title'),
|
||||
'f_name' => strtoupper((string) $this->request->getPost('input_name')),
|
||||
'refer_type' => $this->request->getPost('cbo_refer_type'),
|
||||
'date_of_add' => date('Y-m-d H:i:s'),
|
||||
'insert_by' => $userLabel,
|
||||
'phone_number' => $this->request->getPost('input_phone_number'),
|
||||
'active' => 1,
|
||||
];
|
||||
|
||||
$insertId = $model->insert($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'error_text' => $insertId > 0 ? '' : 'Please Check',
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(int $id)
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$rules = [
|
||||
'input_name' => 'required|min_length[1]|max_length[30]',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
return $this->response->setJSON([
|
||||
'update' => 0,
|
||||
'error_text' => implode(' ', $this->validator->getErrors()),
|
||||
]);
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
$userLabel = $user ? trim(($user->username ?? '') . '[' . ($user->id ?? '') . ']') : 'System';
|
||||
|
||||
$model = new RefferModel();
|
||||
$data = [
|
||||
'title' => $this->request->getPost('cbo_title'),
|
||||
'f_name' => strtoupper((string) $this->request->getPost('input_name')),
|
||||
'refer_type' => $this->request->getPost('cbo_refer_type'),
|
||||
'date_of_add' => date('Y-m-d H:i:s'),
|
||||
'insert_by' => $userLabel,
|
||||
'phone_number' => $this->request->getPost('input_phone_number'),
|
||||
'active' => 1,
|
||||
];
|
||||
|
||||
$updated = $model->updateReffer($data, $id);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
]);
|
||||
}
|
||||
|
||||
public function activate(int $id, int $active)
|
||||
{
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setJSON(['update' => 0, 'error_text' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$model = new RefferModel();
|
||||
$updated = $model->updateStatus($id, $active ? 1 : 0);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update' => $updated ? 1 : 0,
|
||||
'error_text' => $updated ? '' : 'Please Check',
|
||||
]);
|
||||
}
|
||||
|
||||
public function typeList(): string
|
||||
{
|
||||
$model = new RefferModel();
|
||||
|
||||
return view('Setting/Reffer/reffer_type_list', [
|
||||
'types' => $model->getTypes(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeType()
|
||||
{
|
||||
$name = trim((string) $this->request->getPost('type_desc'));
|
||||
if ($name === '') {
|
||||
return $this->renderTypeListWithErrors(['type_desc' => 'Type is required.']);
|
||||
}
|
||||
|
||||
$model = new RefferModel();
|
||||
$model->insertType($name);
|
||||
|
||||
return $this->renderTypeListWithMessage('Type added successfully.');
|
||||
}
|
||||
|
||||
public function updateType()
|
||||
{
|
||||
$id = (int) $this->request->getPost('id');
|
||||
$name = trim((string) $this->request->getPost('type_desc'));
|
||||
if ($id <= 0 || $name === '') {
|
||||
return $this->renderTypeListWithErrors(['type_desc' => 'Type is required.']);
|
||||
}
|
||||
|
||||
$model = new RefferModel();
|
||||
$model->updateType($id, $name);
|
||||
|
||||
return $this->renderTypeListWithMessage('Type updated successfully.');
|
||||
}
|
||||
|
||||
public function deleteType()
|
||||
{
|
||||
$id = (int) $this->request->getPost('id');
|
||||
if ($id <= 0) {
|
||||
return $this->renderTypeListWithErrors(['type_desc' => 'Invalid type.']);
|
||||
}
|
||||
|
||||
$model = new RefferModel();
|
||||
$model->deleteType($id);
|
||||
|
||||
return $this->renderTypeListWithMessage('Type deleted successfully.');
|
||||
}
|
||||
|
||||
private function renderTypeListWithMessage(string $message)
|
||||
{
|
||||
$model = new RefferModel();
|
||||
|
||||
return view('Setting/Reffer/reffer_type_list', [
|
||||
'types' => $model->getTypes(),
|
||||
'message' => $message,
|
||||
]);
|
||||
}
|
||||
|
||||
private function renderTypeListWithErrors(array $errors)
|
||||
{
|
||||
$model = new RefferModel();
|
||||
|
||||
return view('Setting/Reffer/reffer_type_list', [
|
||||
'types' => $model->getTypes(),
|
||||
'errors' => $errors,
|
||||
]);
|
||||
}
|
||||
}
|
||||
652
app/Controllers/Setting/Template.php
Normal file
652
app/Controllers/Setting/Template.php
Normal file
|
|
@ -0,0 +1,652 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use App\Models\PathLabModel;
|
||||
|
||||
class Template extends BaseController
|
||||
{
|
||||
|
||||
private const PERMISSIONS = [
|
||||
'template.pathology',
|
||||
'template.ultrasound',
|
||||
'template.xray',
|
||||
'template.ct',
|
||||
'template.mri',
|
||||
'template.echo',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = db_connect();
|
||||
helper(['form']);
|
||||
}
|
||||
|
||||
private function requirePermission(string $permission)
|
||||
{
|
||||
$user = auth()->user();
|
||||
if (! $user || ! $user->can($permission)) {
|
||||
if ($this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(403)->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Permission denied',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setStatusCode(403)->setBody('Forbidden');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function requireAnyPermission(array $permissions)
|
||||
{
|
||||
$user = auth()->user();
|
||||
if (! $user) {
|
||||
return $this->response->setStatusCode(403)->setBody('Forbidden');
|
||||
}
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
if ($user->can($permission)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(403)->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Permission denied',
|
||||
'csrfName' => csrf_token(),
|
||||
'csrfHash' => csrf_hash(),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setStatusCode(403)->setBody('Forbidden');
|
||||
}
|
||||
|
||||
private function permissionForModality(int $modality): ?string
|
||||
{
|
||||
$map = [
|
||||
1 => 'template.ultrasound',
|
||||
2 => 'template.mri',
|
||||
3 => 'template.xray',
|
||||
4 => 'template.ct',
|
||||
6 => 'template.echo',
|
||||
];
|
||||
|
||||
return $map[$modality] ?? null;
|
||||
}
|
||||
|
||||
private function requireModalityPermission(int $modality)
|
||||
{
|
||||
$permission = $this->permissionForModality($modality);
|
||||
if ($permission === null) {
|
||||
if ($this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'update' => 0,
|
||||
'showcontent' => 'Invalid modality',
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->response->setStatusCode(400)->setBody('Invalid modality');
|
||||
}
|
||||
|
||||
return $this->requirePermission($permission);
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
if ($resp = $this->requireAnyPermission(self::PERMISSIONS)) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
return view('Setting/Template/index');
|
||||
}
|
||||
|
||||
public function report_list()
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$sql = "select g.RepoGrp, r.Title, r.mstRepoKey
|
||||
from (lab_repo r join lab_rgroups g on r.GrpKey=g.mstRGrpKey)
|
||||
join hc_items i on r.charge_id=i.id and i.itype in (5,6)";
|
||||
$query = $this->db->query($sql);
|
||||
$data['labReport_master'] = $query->getResult();
|
||||
|
||||
return view('PathLab_Report/lab_report_list', $data);
|
||||
}
|
||||
|
||||
public function report_ultrasound_list(int $modality = 2)
|
||||
{
|
||||
if ($resp = $this->requireModalityPermission($modality)) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$sql = "select * from radiology_ultrasound_template where modality=" . (int) $modality;
|
||||
$query = $this->db->query($sql);
|
||||
$data['labReport_master'] = $query->getResult();
|
||||
$data['modality'] = $modality;
|
||||
|
||||
return view('PathLab_Report/ultrasound_template_list', $data);
|
||||
}
|
||||
|
||||
public function report_test_list(int $repoId)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$sql = "select j.id, r.mstRepoKey, t.mstTestKey, t.Test, t.TestID, t.Result, j.EOrder
|
||||
from lab_repo r join lab_repotests j join lab_tests t
|
||||
on r.mstRepoKey=j.mstRepoKey and j.mstTestKey=t.mstTestKey
|
||||
where r.mstRepoKey=" . (int) $repoId . " order by j.EOrder";
|
||||
$query = $this->db->query($sql);
|
||||
$data['lab_Rep_Item_List'] = $query->getResult();
|
||||
$data['mstRepoKey'] = $repoId;
|
||||
|
||||
return view('PathLab_Report/lab_report_test_list', $data);
|
||||
}
|
||||
|
||||
public function test_search_page(int $repoId)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
return view('PathLab_Report/lab_test_search', [
|
||||
'repo_id' => $repoId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_parameter_load(int $mstTestKey, int $mstRepoKey)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$sql = "select * from lab_tests where mstTestKey=" . (int) $mstTestKey;
|
||||
$query = $this->db->query($sql);
|
||||
$data['lab_test_parameter'] = $query->getResult();
|
||||
|
||||
$sql = "select *, if(option_bold=1,'Bold','') as option_bold_str
|
||||
from lab_tests_option where mstTestKey=" . (int) $mstTestKey . " order by sort_id";
|
||||
$query = $this->db->query($sql);
|
||||
$data['lab_test_option'] = $query->getResult();
|
||||
|
||||
$data['mstRepoKey'] = $mstRepoKey;
|
||||
|
||||
return view('PathLab_Report/lab_report_item_edit', $data);
|
||||
}
|
||||
|
||||
public function reportedit_load(int $repoId = 0)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$sql = "select * from lab_repo where mstRepoKey=" . (int) $repoId;
|
||||
$query = $this->db->query($sql);
|
||||
$data['labReport_master'] = $query->getResult();
|
||||
|
||||
$itemId = 0;
|
||||
if (! empty($data['labReport_master'])) {
|
||||
$itemId = (int) ($data['labReport_master'][0]->charge_id ?? 0);
|
||||
}
|
||||
|
||||
$sql = "select * from hc_items where itype in (5,30,6)
|
||||
and id not in (select charge_id from lab_repo where charge_id>0 and charge_id<>" . (int) $itemId . ")
|
||||
order by idesc";
|
||||
$query = $this->db->query($sql);
|
||||
$data['hc_items'] = $query->getResult();
|
||||
|
||||
$sql = "select * from lab_rgroups";
|
||||
$query = $this->db->query($sql);
|
||||
$data['lab_rgroups'] = $query->getResult();
|
||||
|
||||
$sql = "select j.id, r.mstRepoKey, t.mstTestKey, t.Test, t.TestID, t.Result, j.EOrder
|
||||
from lab_repo r join lab_repotests j join lab_tests t
|
||||
on r.mstRepoKey=j.mstRepoKey and j.mstTestKey=t.mstTestKey
|
||||
where r.mstRepoKey=" . (int) $repoId . " order by j.EOrder";
|
||||
$query = $this->db->query($sql);
|
||||
$data['lab_Rep_Item_List'] = $query->getResult();
|
||||
|
||||
$sql = "select * from color";
|
||||
$query = $this->db->query($sql);
|
||||
$data['color_name'] = $query->getResult();
|
||||
|
||||
$data['repo_id'] = $repoId;
|
||||
|
||||
return view('PathLab_Report/lab_report_edit', $data);
|
||||
}
|
||||
|
||||
public function reportedit_ultrasound_load(int $modality = 2, int $repoId = 0)
|
||||
{
|
||||
if ($resp = $this->requireModalityPermission($modality)) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$sql = "select * from radiology_ultrasound_template where modality=" . (int) $modality . " and id=" . (int) $repoId;
|
||||
$query = $this->db->query($sql);
|
||||
$data['labReport_master'] = $query->getResult();
|
||||
|
||||
$sql = "select * from hc_items where itype=" . (int) $modality . " order by idesc";
|
||||
$query = $this->db->query($sql);
|
||||
$data['hc_items'] = $query->getResult();
|
||||
|
||||
$data['repo_id'] = $repoId;
|
||||
$data['modality'] = $modality;
|
||||
|
||||
return view('PathLab_Report/ultrasound_report_edit', $data);
|
||||
}
|
||||
|
||||
public function report_update()
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'update_record' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$repoId = (int) $this->request->getPost('repo_id');
|
||||
$inputReportName = trim((string) $this->request->getPost('input_Reportname'));
|
||||
$chargeId = (int) $this->request->getPost('charge_id');
|
||||
$groupId = (int) $this->request->getPost('group_id');
|
||||
$htmlData = (string) $this->request->getPost('HTMLData');
|
||||
|
||||
if ($repoId <= 0 || $inputReportName === '') {
|
||||
return $this->response->setJSON([
|
||||
'update_record' => 0,
|
||||
'showcontent' => 'Report name is required.',
|
||||
]);
|
||||
}
|
||||
|
||||
$pathLab = new PathLabModel();
|
||||
$pathLab->updateReport([
|
||||
'Title' => $inputReportName,
|
||||
'GrpKey' => $groupId,
|
||||
'charge_id' => $chargeId,
|
||||
'HTMLData' => $htmlData,
|
||||
], $repoId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update_record' => 1,
|
||||
'showcontent' => 'Data Saved successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
public function report_insert()
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'insertid' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$inputReportName = trim((string) $this->request->getPost('input_Reportname'));
|
||||
$chargeId = (int) $this->request->getPost('charge_id');
|
||||
$groupId = (int) $this->request->getPost('group_id');
|
||||
$htmlData = (string) $this->request->getPost('HTMLData');
|
||||
|
||||
if ($inputReportName === '') {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'showcontent' => 'Report name is required.',
|
||||
]);
|
||||
}
|
||||
|
||||
$pathLab = new PathLabModel();
|
||||
$insertId = $pathLab->insertReport([
|
||||
'Title' => $inputReportName,
|
||||
'GrpKey' => $groupId,
|
||||
'charge_id' => $chargeId,
|
||||
'HTMLData' => $htmlData,
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'showcontent' => $insertId > 0 ? 'Data Saved successfully' : 'Unable to save data',
|
||||
]);
|
||||
}
|
||||
|
||||
public function report_ultrasound_insert(int $modality)
|
||||
{
|
||||
if ($resp = $this->requireModalityPermission($modality)) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'insertid' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$inputReportName = trim((string) $this->request->getPost('input_Reportname'));
|
||||
$chargeId = (int) $this->request->getPost('charge_id');
|
||||
$groupId = (string) $this->request->getPost('group_id');
|
||||
$htmlData = (string) $this->request->getPost('HTMLData');
|
||||
$impression = (string) $this->request->getPost('Impression');
|
||||
|
||||
if ($inputReportName === '') {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'showcontent' => 'Report name is required.',
|
||||
]);
|
||||
}
|
||||
|
||||
$pathLab = new PathLabModel();
|
||||
$insertId = $pathLab->insertUltrasoundReport([
|
||||
'template_name' => $inputReportName,
|
||||
'title' => $groupId,
|
||||
'charge_id' => $chargeId,
|
||||
'Findings' => $htmlData,
|
||||
'Impression' => $impression,
|
||||
'modality' => $modality,
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'showcontent' => $insertId > 0 ? 'Data Saved successfully' : 'Unable to save data',
|
||||
]);
|
||||
}
|
||||
|
||||
public function report_ultrasound_update(int $modality = 2)
|
||||
{
|
||||
if ($resp = $this->requireModalityPermission($modality)) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'update_record' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$repoId = (int) $this->request->getPost('repo_id');
|
||||
$inputReportName = trim((string) $this->request->getPost('input_Reportname'));
|
||||
$chargeId = (int) $this->request->getPost('charge_id');
|
||||
$groupId = (string) $this->request->getPost('group_id');
|
||||
$htmlData = (string) $this->request->getPost('HTMLData');
|
||||
$impression = (string) $this->request->getPost('Impression');
|
||||
|
||||
if ($repoId <= 0 || $inputReportName === '') {
|
||||
return $this->response->setJSON([
|
||||
'update_record' => 0,
|
||||
'showcontent' => 'Report name is required.',
|
||||
]);
|
||||
}
|
||||
|
||||
$pathLab = new PathLabModel();
|
||||
$pathLab->updateUltrasoundReport([
|
||||
'template_name' => $inputReportName,
|
||||
'title' => $groupId,
|
||||
'charge_id' => $chargeId,
|
||||
'Findings' => $htmlData,
|
||||
'Impression' => $impression,
|
||||
'modality' => $modality,
|
||||
], $repoId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update_record' => 1,
|
||||
'showcontent' => 'Data Saved successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_parameter_edit()
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'update_value' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$mstTestKey = (int) $this->request->getPost('mstTestKey');
|
||||
$pathLab = new PathLabModel();
|
||||
|
||||
$data = [
|
||||
'Test' => (string) $this->request->getPost('input_Test_name'),
|
||||
'TestID' => (string) $this->request->getPost('input_test_code'),
|
||||
'Result' => (string) $this->request->getPost('input_Default'),
|
||||
'Formula' => (string) $this->request->getPost('input_Formula'),
|
||||
'VRule' => (string) $this->request->getPost('input_Validation'),
|
||||
'VMsg' => (string) $this->request->getPost('input_Message'),
|
||||
'Unit' => (string) $this->request->getPost('input_Unit'),
|
||||
'FixedNormals' => (string) $this->request->getPost('input_Fixed'),
|
||||
'isGenderSpecific' => (int) $this->request->getPost('input_isChecked'),
|
||||
'FixedNormalsWomen' => (string) $this->request->getPost('input_FixedNormalsWomen'),
|
||||
];
|
||||
|
||||
$pathLab->updateItemParameter($data, $mstTestKey);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'update_value' => 1,
|
||||
'showcontent' => 'Data Saved successfully',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_parameter_add()
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'insert_id' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$pathLab = new PathLabModel();
|
||||
$data = [
|
||||
'Test' => (string) $this->request->getPost('input_Test_name'),
|
||||
'TestID' => (string) $this->request->getPost('input_test_code'),
|
||||
'Result' => (string) $this->request->getPost('input_Default'),
|
||||
'Formula' => (string) $this->request->getPost('input_Formula'),
|
||||
'VRule' => (string) $this->request->getPost('input_Validation'),
|
||||
'VMsg' => (string) $this->request->getPost('input_Message'),
|
||||
'Unit' => (string) $this->request->getPost('input_Unit'),
|
||||
'FixedNormals' => (string) $this->request->getPost('input_Fixed'),
|
||||
];
|
||||
|
||||
$insertId = $pathLab->insertItemParameter($data);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insert_id' => $insertId,
|
||||
'showcontent' => $insertId > 0 ? 'Data Saved successfully' : 'Unable to save data',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_parameter_option_add()
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
if (! $this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
'insert_id' => 0,
|
||||
'showcontent' => 'Invalid request',
|
||||
]);
|
||||
}
|
||||
|
||||
$mstTestKey = (int) $this->request->getPost('mstTestKey');
|
||||
$pathLab = new PathLabModel();
|
||||
|
||||
$nextSort = 1;
|
||||
$row = $this->db->table('lab_tests_option')
|
||||
->selectMax('sort_id', 'max_sort')
|
||||
->where('mstTestKey', $mstTestKey)
|
||||
->get()
|
||||
->getRowArray();
|
||||
if (! empty($row['max_sort'])) {
|
||||
$nextSort = (int) $row['max_sort'] + 1;
|
||||
}
|
||||
|
||||
$insertId = $pathLab->insertItemParameterOption([
|
||||
'mstTestKey' => $mstTestKey,
|
||||
'option_value' => (string) $this->request->getPost('input_op_value'),
|
||||
'option_bold' => (int) $this->request->getPost('chk_bold'),
|
||||
'sort_id' => $nextSort,
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insert_id' => $insertId,
|
||||
'showcontent' => $insertId > 0 ? 'Data Saved successfully' : 'Unable to save data',
|
||||
'option_content' => $this->renderOptionTable($mstTestKey),
|
||||
]);
|
||||
}
|
||||
|
||||
public function remove_test_option(int $optionId, int $mstTestKey)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$this->db->table('lab_tests_option')->where('id', $optionId)->delete();
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insert_id' => 1,
|
||||
'showcontent' => 'Removed successfully',
|
||||
'option_content' => $this->renderOptionTable($mstTestKey),
|
||||
]);
|
||||
}
|
||||
|
||||
public function change_sort(int $mstTestKey, int $optionId, int $current, int $changeOptionId, int $change)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$pathLab = new PathLabModel();
|
||||
$pathLab->updateItemParameterOption(['sort_id' => 0], $optionId);
|
||||
$pathLab->updateItemParameterOption(['sort_id' => $current], $changeOptionId);
|
||||
$pathLab->updateItemParameterOption(['sort_id' => $change], $optionId);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insert_id' => 1,
|
||||
'showcontent' => 'Updated successfully',
|
||||
'option_content' => $this->renderOptionTable($mstTestKey),
|
||||
]);
|
||||
}
|
||||
|
||||
public function change_sort_item(int $repoId, int $optionId, int $current, int $changeOptionId, int $change)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$pathLab = new PathLabModel();
|
||||
$pathLab->updateItemSortorder(['EOrder' => 0], $optionId);
|
||||
$pathLab->updateItemSortorder(['EOrder' => $current], $changeOptionId);
|
||||
$pathLab->updateItemSortorder(['EOrder' => $change], $optionId);
|
||||
|
||||
return $this->report_test_list($repoId);
|
||||
}
|
||||
|
||||
public function add_test_repo(int $repoId, int $testId)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$exists = $this->db->table('lab_repotests')
|
||||
->where('mstRepoKey', $repoId)
|
||||
->where('mstTestKey', $testId)
|
||||
->countAllResults();
|
||||
|
||||
if ($exists > 0) {
|
||||
return $this->response->setJSON([
|
||||
'insertid' => 0,
|
||||
'showcontent' => 'Already Added',
|
||||
]);
|
||||
}
|
||||
|
||||
$row = $this->db->table('lab_repotests')
|
||||
->selectMax('EOrder', 'max_order')
|
||||
->where('mstRepoKey', $repoId)
|
||||
->get()
|
||||
->getRowArray();
|
||||
$nextOrder = (int) ($row['max_order'] ?? 0) + 1;
|
||||
|
||||
$pathLab = new PathLabModel();
|
||||
$insertId = $pathLab->insertItemSortorder([
|
||||
'mstRepoKey' => $repoId,
|
||||
'mstTestKey' => $testId,
|
||||
'EOrder' => $nextOrder,
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'insertid' => $insertId,
|
||||
'showcontent' => $insertId > 0 ? 'Add successfully' : 'Unable to add',
|
||||
]);
|
||||
}
|
||||
|
||||
public function remove_test_item(int $repoId, int $testId)
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$this->db->table('lab_repotests')
|
||||
->where('mstRepoKey', $repoId)
|
||||
->where('mstTestKey', $testId)
|
||||
->delete();
|
||||
}
|
||||
|
||||
public function test_item_search()
|
||||
{
|
||||
if ($resp = $this->requirePermission('template.pathology')) {
|
||||
return $resp;
|
||||
}
|
||||
|
||||
$testName = (string) $this->request->getPost('input_Test_name');
|
||||
$repoId = (int) $this->request->getPost('repo_id');
|
||||
|
||||
$sql = "select * from lab_tests where Test like '%" . $this->db->escapeLikeString($testName) . "%'";
|
||||
$query = $this->db->query($sql);
|
||||
$searchResult = $query->getResult();
|
||||
|
||||
$html = '<table class="table table-sm">';
|
||||
foreach ($searchResult as $row) {
|
||||
$html .= '<tr><td><a href="javascript:add_test(' . (int) $repoId . ',' . (int) $row->mstTestKey . ');">' . esc($row->Test) . '</a></td><td>[ ' . esc($row->TestID) . ' ]</td></tr>';
|
||||
}
|
||||
$html .= '</table>';
|
||||
|
||||
return $this->response->setBody($html);
|
||||
}
|
||||
|
||||
private function renderOptionTable(int $mstTestKey): string
|
||||
{
|
||||
$sql = "select *, if(option_bold=1,'Bold','') as option_bold_str
|
||||
from lab_tests_option where mstTestKey=" . (int) $mstTestKey . " order by sort_id";
|
||||
$query = $this->db->query($sql);
|
||||
$options = $query->getResult();
|
||||
|
||||
return view('PathLab_Report/_test_option_table', [
|
||||
'lab_test_option' => $options,
|
||||
'mstTestKey' => $mstTestKey,
|
||||
]);
|
||||
}
|
||||
}
|
||||
498
app/Controllers/Setting/UserManagement.php
Normal file
498
app/Controllers/Setting/UserManagement.php
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
use CodeIgniter\Shield\Entities\User;
|
||||
use CodeIgniter\Shield\Models\UserModel;
|
||||
|
||||
class UserManagement extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
$userModel = model(UserModel::class);
|
||||
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(): string
|
||||
{
|
||||
return view('Setting/Admin/UserManagement/create', [
|
||||
'roles' => setting('AuthGroups.groups'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store()
|
||||
{
|
||||
$rules = [
|
||||
'username' => 'required|min_length[3]|max_length[30]',
|
||||
'email' => 'required|valid_email|max_length[254]',
|
||||
'password' => 'required|min_length[8]',
|
||||
'role' => 'required',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
if ($this->request->isAJAX()) {
|
||||
return view('Setting/Admin/UserManagement/create', [
|
||||
'roles' => setting('AuthGroups.groups'),
|
||||
'errors' => $this->validator->getErrors(),
|
||||
'formData' => $this->request->getPost(),
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$role = strtolower((string) $this->request->getPost('role'));
|
||||
$allowedRoles = array_keys(setting('AuthGroups.groups'));
|
||||
if (! in_array($role, $allowedRoles, true)) {
|
||||
$errors = ['role' => 'Invalid role selected.'];
|
||||
if ($this->request->isAJAX()) {
|
||||
return view('Setting/Admin/UserManagement/create', [
|
||||
'roles' => setting('AuthGroups.groups'),
|
||||
'errors' => $errors,
|
||||
'formData' => $this->request->getPost(),
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->with('errors', $errors);
|
||||
}
|
||||
|
||||
$user = new User();
|
||||
$user->username = (string) $this->request->getPost('username');
|
||||
$user->email = (string) $this->request->getPost('email');
|
||||
$user->password = (string) $this->request->getPost('password');
|
||||
$user->active = 1;
|
||||
|
||||
$userModel = model(UserModel::class);
|
||||
$userModel->save($user);
|
||||
|
||||
$savedUser = $userModel->find($userModel->getInsertID());
|
||||
if ($savedUser !== null) {
|
||||
$savedUser->addGroup($role);
|
||||
}
|
||||
|
||||
if ($this->request->isAJAX()) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'message' => 'User created successfully.',
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->to('setting/admin/user-management')
|
||||
->with('message', 'User created successfully.');
|
||||
}
|
||||
|
||||
public function permissions(): string
|
||||
{
|
||||
$userModel = model(UserModel::class);
|
||||
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
$selectedUserId = (int) $this->request->getGet('user_id');
|
||||
$selectedUser = null;
|
||||
if ($selectedUserId) {
|
||||
$selectedUser = $userModel->withPermissions()->find($selectedUserId);
|
||||
}
|
||||
|
||||
return view('Setting/Admin/UserManagement/permissions', [
|
||||
'users' => $users,
|
||||
'permissions' => setting('AuthGroups.permissions'),
|
||||
'selectedUser' => $selectedUser,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(int $userId): string
|
||||
{
|
||||
$userModel = model(UserModel::class);
|
||||
$user = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->find($userId);
|
||||
|
||||
if ($user === null) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'errors' => ['User not found.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$emailIdentity = $user->getEmailIdentity();
|
||||
$email = $emailIdentity ? (string) ($emailIdentity->secret ?? '') : '';
|
||||
$meta = $this->decodeIdentityExtra($emailIdentity->extra ?? null);
|
||||
|
||||
return view('Setting/Admin/UserManagement/edit', [
|
||||
'user' => $user,
|
||||
'email' => $email,
|
||||
'person_name' => trim((string) ($meta['full_name'] ?? '')),
|
||||
'phone_no' => trim((string) ($meta['phone_no'] ?? '')),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(int $userId)
|
||||
{
|
||||
$userModel = model(UserModel::class);
|
||||
$user = $userModel->find($userId);
|
||||
if ($user === null) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'errors' => ['User not found.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$username = trim((string) $this->request->getPost('username'));
|
||||
$email = trim((string) $this->request->getPost('email'));
|
||||
$personName = trim((string) $this->request->getPost('person_name'));
|
||||
$phoneNo = trim((string) $this->request->getPost('phone_no'));
|
||||
$password = (string) $this->request->getPost('password');
|
||||
$active = $this->request->getPost('active') ? 1 : 0;
|
||||
|
||||
$errors = [];
|
||||
if ($username === '' || strlen($username) < 3 || strlen($username) > 30 || preg_match('/\A[a-zA-Z0-9\.]+\z/', $username) !== 1) {
|
||||
$errors['username'] = 'Login ID must be 3-30 chars and only letters, numbers, dot.';
|
||||
}
|
||||
if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$errors['email'] = 'Valid email is required.';
|
||||
}
|
||||
if ($personName !== '' && mb_strlen($personName) > 120) {
|
||||
$errors['person_name'] = 'Person name must be maximum 120 characters.';
|
||||
}
|
||||
if ($phoneNo !== '' && preg_match('/^[0-9+\-()\s]{7,20}$/', $phoneNo) !== 1) {
|
||||
$errors['phone_no'] = 'Phone format is invalid.';
|
||||
}
|
||||
if ($password !== '' && strlen($password) < 8) {
|
||||
$errors['password'] = 'Password must be at least 8 characters.';
|
||||
}
|
||||
|
||||
$tables = config('Auth')->tables;
|
||||
$usersTable = (string) ($tables['users'] ?? 'users');
|
||||
$identitiesTable = (string) ($tables['identities'] ?? 'auth_identities');
|
||||
|
||||
if (empty($errors)) {
|
||||
$duplicateUsername = $this->db->table($usersTable)
|
||||
->select('id')
|
||||
->where('username', $username)
|
||||
->where('id !=', $userId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (! empty($duplicateUsername)) {
|
||||
$errors['username'] = 'Login ID already used by another user.';
|
||||
}
|
||||
|
||||
$duplicateEmail = $this->db->table($identitiesTable)
|
||||
->select('id')
|
||||
->where('type', 'email_password')
|
||||
->where('secret', $email)
|
||||
->where('user_id !=', $userId)
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
if (! empty($duplicateEmail)) {
|
||||
$errors['email'] = 'Email already used by another user.';
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($errors)) {
|
||||
return view('Setting/Admin/UserManagement/edit', [
|
||||
'user' => $userModel->withIdentities()->find($userId),
|
||||
'email' => $email,
|
||||
'person_name' => $personName,
|
||||
'phone_no' => $phoneNo,
|
||||
'errors' => $errors,
|
||||
'formData' => [
|
||||
'username' => $username,
|
||||
'email' => $email,
|
||||
'person_name' => $personName,
|
||||
'phone_no' => $phoneNo,
|
||||
'active' => $active,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$user->username = $username;
|
||||
$user->email = $email;
|
||||
$user->active = $active;
|
||||
if ($password !== '') {
|
||||
$user->password = $password;
|
||||
}
|
||||
|
||||
$userModel->save($user);
|
||||
$this->syncIdentityMeta($userId, $personName, $phoneNo);
|
||||
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'message' => 'User updated successfully.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function resetPasswordForm(int $userId): string
|
||||
{
|
||||
$userModel = model(UserModel::class);
|
||||
$user = $userModel->find($userId);
|
||||
|
||||
if ($user === null) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'errors' => ['User not found.'],
|
||||
]);
|
||||
}
|
||||
|
||||
return view('Setting/Admin/UserManagement/reset_password', [
|
||||
'user' => $user,
|
||||
]);
|
||||
}
|
||||
|
||||
public function resetPassword(int $userId)
|
||||
{
|
||||
$userModel = model(UserModel::class);
|
||||
$user = $userModel->find($userId);
|
||||
if ($user === null) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'errors' => ['User not found.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$password = trim((string) $this->request->getPost('password'));
|
||||
$passwordConfirm = trim((string) $this->request->getPost('password_confirm'));
|
||||
$errors = [];
|
||||
|
||||
if (preg_match('/^\d{6}$/', $password) !== 1) {
|
||||
$errors['password'] = 'Temporary PIN must be exactly 6 digits.';
|
||||
}
|
||||
|
||||
if (! hash_equals($password, $passwordConfirm)) {
|
||||
$errors['password_confirm'] = 'PIN and confirm PIN do not match.';
|
||||
}
|
||||
|
||||
if (! empty($errors)) {
|
||||
return view('Setting/Admin/UserManagement/reset_password', [
|
||||
'user' => $user,
|
||||
'errors' => $errors,
|
||||
]);
|
||||
}
|
||||
|
||||
$tables = config('Auth')->tables;
|
||||
$identitiesTable = (string) ($tables['identities'] ?? 'auth_identities');
|
||||
if (! $this->db->tableExists($identitiesTable)) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'errors' => ['Auth identity table not found.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$identity = $this->db->table($identitiesTable)
|
||||
->select('id')
|
||||
->where('user_id', $userId)
|
||||
->where('type', 'email_password')
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
if (empty($identity['id'])) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'errors' => ['User login identity not found.'],
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->table($identitiesTable)
|
||||
->where('id', (int) $identity['id'])
|
||||
->update([
|
||||
'secret2' => password_hash($password, PASSWORD_DEFAULT),
|
||||
'force_reset' => 1,
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/index', [
|
||||
'users' => $users,
|
||||
'message' => 'Temporary 6-digit PIN set successfully. User must change password on next login.',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function decodeIdentityExtra($extra): array
|
||||
{
|
||||
if (is_array($extra)) {
|
||||
return $extra;
|
||||
}
|
||||
if (is_string($extra) && trim($extra) !== '') {
|
||||
$decoded = json_decode($extra, true);
|
||||
if (is_array($decoded)) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private function syncIdentityMeta(int $userId, string $personName, string $phoneNo): void
|
||||
{
|
||||
$tables = config('Auth')->tables;
|
||||
$identitiesTable = (string) ($tables['identities'] ?? 'auth_identities');
|
||||
if (! $this->db->tableExists($identitiesTable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$row = $this->db->table($identitiesTable)
|
||||
->select('id,extra')
|
||||
->where('user_id', $userId)
|
||||
->where('type', 'email_password')
|
||||
->get(1)
|
||||
->getRowArray();
|
||||
|
||||
if (empty($row) || empty($row['id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payload = $this->decodeIdentityExtra($row['extra'] ?? null);
|
||||
if ($personName === '') {
|
||||
unset($payload['full_name']);
|
||||
} else {
|
||||
$payload['full_name'] = $personName;
|
||||
}
|
||||
|
||||
if ($phoneNo === '') {
|
||||
unset($payload['phone_no']);
|
||||
} else {
|
||||
$payload['phone_no'] = $phoneNo;
|
||||
}
|
||||
|
||||
$this->db->table($identitiesTable)
|
||||
->where('id', (int) $row['id'])
|
||||
->update([
|
||||
'extra' => empty($payload) ? null : json_encode($payload, JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
}
|
||||
|
||||
public function savePermissions()
|
||||
{
|
||||
$rules = [
|
||||
'user_id' => 'required|is_natural_no_zero',
|
||||
];
|
||||
|
||||
if (! $this->validate($rules)) {
|
||||
if ($this->request->isAJAX()) {
|
||||
$users = model(UserModel::class)
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/permissions', [
|
||||
'users' => $users,
|
||||
'permissions' => setting('AuthGroups.permissions'),
|
||||
'selectedUser' => null,
|
||||
'errors' => $this->validator->getErrors(),
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
||||
}
|
||||
|
||||
$userId = (int) $this->request->getPost('user_id');
|
||||
$permissions = (array) $this->request->getPost('permissions');
|
||||
$permissions = array_values(array_filter(array_map('strtolower', $permissions)));
|
||||
|
||||
$allowedPermissions = array_keys(setting('AuthGroups.permissions'));
|
||||
$permissions = array_values(array_intersect($permissions, $allowedPermissions));
|
||||
|
||||
$userModel = model(UserModel::class);
|
||||
$user = $userModel->find($userId);
|
||||
if ($user === null) {
|
||||
$errors = ['user_id' => 'User not found.'];
|
||||
if ($this->request->isAJAX()) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
return view('Setting/Admin/UserManagement/permissions', [
|
||||
'users' => $users,
|
||||
'permissions' => setting('AuthGroups.permissions'),
|
||||
'selectedUser' => null,
|
||||
'errors' => $errors,
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->with('errors', $errors);
|
||||
}
|
||||
|
||||
$user->syncPermissions(...$permissions);
|
||||
|
||||
if ($this->request->isAJAX()) {
|
||||
$users = $userModel
|
||||
->withIdentities()
|
||||
->withGroups()
|
||||
->findAll();
|
||||
|
||||
$selectedUser = $userModel->withPermissions()->find($userId);
|
||||
|
||||
return view('Setting/Admin/UserManagement/permissions', [
|
||||
'users' => $users,
|
||||
'permissions' => setting('AuthGroups.permissions'),
|
||||
'selectedUser' => $selectedUser,
|
||||
'message' => 'Permissions updated successfully.',
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->to('setting/admin/user-management/permissions?user_id=' . $userId)
|
||||
->with('message', 'Permissions updated successfully.');
|
||||
}
|
||||
}
|
||||
0
app/Database/Migrations/.gitkeep
Normal file
0
app/Database/Migrations/.gitkeep
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreatePatientDuplicateLog extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'new_uhid' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'null' => false,
|
||||
],
|
||||
'name_of_person' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => false,
|
||||
],
|
||||
'new_patient_code' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 50,
|
||||
'null' => true,
|
||||
],
|
||||
'date_of_registration' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => false,
|
||||
],
|
||||
'update_by' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => false,
|
||||
],
|
||||
'remark_duplicate' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->createTable('patient_duplicate_log', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->forge->dropTable('patient_duplicate_log', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateDocIpdFeeType extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'fee_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 150,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->createTable('doc_ipd_fee_type', true);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropTable('doc_ipd_fee_type', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddGstAgreementToInsurance extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$fields = [
|
||||
'gst_no' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 50,
|
||||
'null' => true,
|
||||
],
|
||||
'agreement_start_date' => [
|
||||
'type' => 'DATE',
|
||||
'null' => true,
|
||||
],
|
||||
'agreement_end_date' => [
|
||||
'type' => 'DATE',
|
||||
'null' => true,
|
||||
],
|
||||
];
|
||||
|
||||
$this->forge->addColumn('hc_insurance', $fields);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropColumn('hc_insurance', ['gst_no', 'agreement_start_date', 'agreement_end_date']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateCheckItemRequestFunction extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
$sql = "CREATE FUNCTION IF NOT EXISTS `check_item_request`(
|
||||
`xcharge_id` INT,
|
||||
`xcharge_item_id` INT
|
||||
)
|
||||
RETURNS varchar(50) CHARSET utf8mb3 COLLATE utf8mb3_unicode_ci
|
||||
LANGUAGE SQL
|
||||
NOT DETERMINISTIC
|
||||
CONTAINS SQL
|
||||
SQL SECURITY DEFINER
|
||||
COMMENT ''
|
||||
BEGIN
|
||||
Declare xReturn varchar(50) default '0#0';
|
||||
Declare xNo_Count,xStatus varchar(5) default '0';
|
||||
|
||||
select count(*) into xNo_Count from lab_request where charge_id=xcharge_id and charge_item_id=xcharge_item_id;
|
||||
|
||||
if xNo_Count>0 then
|
||||
select status into xStatus from lab_request where charge_id=xcharge_id and charge_item_id=xcharge_item_id;
|
||||
End if;
|
||||
|
||||
Set xReturn=Concat(xNo_Count,';',xStatus);
|
||||
|
||||
return xReturn;
|
||||
END";
|
||||
|
||||
$this->db->query($sql);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->db->query("DROP FUNCTION IF EXISTS `check_item_request`");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class BackfillMedicalInvoiceCodes extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! $this->db->tableExists('invoice_med_master')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->db->fieldExists('id', 'invoice_med_master') || ! $this->db->fieldExists('inv_med_code', 'invoice_med_master')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$invDateExpression = $this->db->fieldExists('inv_date', 'invoice_med_master')
|
||||
? "COALESCE(NULLIF(inv_date, '0000-00-00'), CURDATE())"
|
||||
: 'CURDATE()';
|
||||
|
||||
$sql = "UPDATE invoice_med_master
|
||||
SET inv_med_code = CONCAT(
|
||||
'M',
|
||||
DATE_FORMAT({$invDateExpression}, '%y%m'),
|
||||
LPAD(CAST(id AS CHAR), 7, '0')
|
||||
)
|
||||
WHERE (inv_med_code IS NULL OR TRIM(inv_med_code) = '')
|
||||
AND id IS NOT NULL
|
||||
AND id > 0";
|
||||
|
||||
$this->db->query($sql);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Data backfill is intentionally not reversed.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateMedicalBankTables extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! $this->db->tableExists('medical_bank')) {
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'bank_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 150,
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->createTable('medical_bank', true);
|
||||
}
|
||||
|
||||
if (! $this->db->tableExists('medical_bank_payment_source')) {
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'bank_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'pay_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 150,
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('bank_id');
|
||||
$this->forge->createTable('medical_bank_payment_source', true);
|
||||
}
|
||||
|
||||
if ($this->db->tableExists('hospital_bank') && $this->db->tableExists('medical_bank')) {
|
||||
$countMedicalBank = (int) $this->db->table('medical_bank')->countAllResults();
|
||||
if ($countMedicalBank === 0) {
|
||||
$this->db->query('INSERT INTO medical_bank (bank_name) SELECT bank_name FROM hospital_bank');
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
$this->db->tableExists('hospital_bank_payment_source')
|
||||
&& $this->db->tableExists('hospital_bank')
|
||||
&& $this->db->tableExists('medical_bank')
|
||||
&& $this->db->tableExists('medical_bank_payment_source')
|
||||
) {
|
||||
$countMedicalSource = (int) $this->db->table('medical_bank_payment_source')->countAllResults();
|
||||
if ($countMedicalSource === 0) {
|
||||
$this->db->query(
|
||||
'INSERT INTO medical_bank_payment_source (bank_id, pay_type)
|
||||
SELECT mb.id, hps.pay_type
|
||||
FROM hospital_bank_payment_source hps
|
||||
INNER JOIN hospital_bank hb ON hb.id = hps.bank_id
|
||||
INNER JOIN medical_bank mb ON mb.bank_name = hb.bank_name'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropTable('medical_bank_payment_source', true);
|
||||
$this->forge->dropTable('medical_bank', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddPharmacyStockReportIndexes extends Migration
|
||||
{
|
||||
private function tableExists(string $table): bool
|
||||
{
|
||||
return $this->db->tableExists($table);
|
||||
}
|
||||
|
||||
private function fieldExists(string $table, string $field): bool
|
||||
{
|
||||
return $this->db->fieldExists($field, $table);
|
||||
}
|
||||
|
||||
private function indexExists(string $table, string $indexName): bool
|
||||
{
|
||||
if (! $this->tableExists($table)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rows = $this->db->query('SHOW INDEX FROM `' . $table . '` WHERE Key_name = ?', [$indexName])->getResultArray();
|
||||
return ! empty($rows);
|
||||
}
|
||||
|
||||
private function addIndexIfMissing(string $table, string $indexName, string $columns): void
|
||||
{
|
||||
if (! $this->tableExists($table) || $this->indexExists($table, $indexName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->query('ALTER TABLE `' . $table . '` ADD INDEX `' . $indexName . '` (' . $columns . ')');
|
||||
}
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
if ($this->tableExists('purchase_invoice_item')) {
|
||||
$this->addIndexIfMissing('purchase_invoice_item', 'idx_pii_item_code', '`item_code`');
|
||||
$this->addIndexIfMissing('purchase_invoice_item', 'idx_pii_purchase_id', '`purchase_id`');
|
||||
|
||||
if ($this->fieldExists('purchase_invoice_item', 'stock_date')) {
|
||||
$this->addIndexIfMissing('purchase_invoice_item', 'idx_pii_stock_date', '`stock_date`');
|
||||
}
|
||||
|
||||
if ($this->fieldExists('purchase_invoice_item', 'remove_item') && $this->fieldExists('purchase_invoice_item', 'item_return')) {
|
||||
$this->addIndexIfMissing('purchase_invoice_item', 'idx_pii_status_flags', '`remove_item`,`item_return`');
|
||||
}
|
||||
|
||||
if ($this->fieldExists('purchase_invoice_item', 'expiry_date')) {
|
||||
$this->addIndexIfMissing('purchase_invoice_item', 'idx_pii_expiry_date', '`expiry_date`');
|
||||
}
|
||||
|
||||
if ($this->fieldExists('purchase_invoice_item', 'batch_no')) {
|
||||
$this->addIndexIfMissing('purchase_invoice_item', 'idx_pii_item_batch', '`item_code`,`batch_no`');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->tableExists('purchase_invoice')) {
|
||||
if ($this->fieldExists('purchase_invoice', 'date_of_invoice') && $this->fieldExists('purchase_invoice', 'sid')) {
|
||||
$this->addIndexIfMissing('purchase_invoice', 'idx_pi_date_supplier', '`date_of_invoice`,`sid`');
|
||||
}
|
||||
if ($this->fieldExists('purchase_invoice', 'sid')) {
|
||||
$this->addIndexIfMissing('purchase_invoice', 'idx_pi_supplier', '`sid`');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->tableExists('inv_med_item')) {
|
||||
if ($this->fieldExists('inv_med_item', 'inv_med_id') && $this->fieldExists('inv_med_item', 'item_code')) {
|
||||
$this->addIndexIfMissing('inv_med_item', 'idx_imi_invoice_item', '`inv_med_id`,`item_code`');
|
||||
}
|
||||
if ($this->fieldExists('inv_med_item', 'item_code')) {
|
||||
$this->addIndexIfMissing('inv_med_item', 'idx_imi_item_code', '`item_code`');
|
||||
}
|
||||
if ($this->fieldExists('inv_med_item', 'sale_return')) {
|
||||
$this->addIndexIfMissing('inv_med_item', 'idx_imi_sale_return', '`sale_return`');
|
||||
}
|
||||
if ($this->fieldExists('inv_med_item', 'item_return')) {
|
||||
$this->addIndexIfMissing('inv_med_item', 'idx_imi_item_return', '`item_return`');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->tableExists('invoice_med_master')) {
|
||||
if ($this->fieldExists('invoice_med_master', 'inv_date')) {
|
||||
$this->addIndexIfMissing('invoice_med_master', 'idx_imm_inv_date', '`inv_date`');
|
||||
}
|
||||
if ($this->fieldExists('invoice_med_master', 'sale_return') && $this->fieldExists('invoice_med_master', 'inv_date')) {
|
||||
$this->addIndexIfMissing('invoice_med_master', 'idx_imm_sale_return_date', '`sale_return`,`inv_date`');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$drops = [
|
||||
'purchase_invoice_item' => [
|
||||
'idx_pii_item_code',
|
||||
'idx_pii_purchase_id',
|
||||
'idx_pii_stock_date',
|
||||
'idx_pii_status_flags',
|
||||
'idx_pii_expiry_date',
|
||||
'idx_pii_item_batch',
|
||||
],
|
||||
'purchase_invoice' => [
|
||||
'idx_pi_date_supplier',
|
||||
'idx_pi_supplier',
|
||||
],
|
||||
'inv_med_item' => [
|
||||
'idx_imi_invoice_item',
|
||||
'idx_imi_item_code',
|
||||
'idx_imi_sale_return',
|
||||
'idx_imi_item_return',
|
||||
],
|
||||
'invoice_med_master' => [
|
||||
'idx_imm_inv_date',
|
||||
'idx_imm_sale_return_date',
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($drops as $table => $indexes) {
|
||||
if (! $this->tableExists($table)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($indexes as $index) {
|
||||
if ($this->indexExists($table, $index)) {
|
||||
$this->db->query('ALTER TABLE `' . $table . '` DROP INDEX `' . $index . '`');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateMedicalProductCategoryTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if ($this->db->tableExists('med_product_cat_master')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'med_cat_desc' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 100,
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->createTable('med_product_cat_master', true);
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
if ($this->db->tableExists('med_product_cat_master')) {
|
||||
$this->forge->dropTable('med_product_cat_master', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AlignMedicalProductCategoryTableSchema extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
if (! $this->db->tableExists('med_product_cat_master')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->db->fieldExists('id', 'med_product_cat_master')) {
|
||||
$this->forge->addColumn('med_product_cat_master', [
|
||||
'id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
if (! $this->db->fieldExists('med_cat_desc', 'med_product_cat_master')) {
|
||||
$this->forge->addColumn('med_product_cat_master', [
|
||||
'med_cat_desc' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 100,
|
||||
'null' => false,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$this->db->query("ALTER TABLE `med_product_cat_master` MODIFY `id` INT UNSIGNED NOT NULL AUTO_INCREMENT");
|
||||
$this->db->query("ALTER TABLE `med_product_cat_master` MODIFY `med_cat_desc` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL");
|
||||
|
||||
$hasPrimary = false;
|
||||
$indexRows = $this->db->query("SHOW INDEX FROM `med_product_cat_master`")->getResultArray();
|
||||
foreach ($indexRows as $indexRow) {
|
||||
if (($indexRow['Key_name'] ?? '') === 'PRIMARY') {
|
||||
$hasPrimary = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! $hasPrimary) {
|
||||
$this->db->query("ALTER TABLE `med_product_cat_master` ADD PRIMARY KEY (`id`)");
|
||||
}
|
||||
|
||||
$this->db->query("ALTER TABLE `med_product_cat_master` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci");
|
||||
$this->db->query("ALTER TABLE `med_product_cat_master` ENGINE=MyISAM");
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
// No-op to avoid destructive schema rollback for existing production tables.
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateClinicalAuditTrailTable extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'BIGINT',
|
||||
'constraint' => 20,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'module' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => false,
|
||||
],
|
||||
'record_id' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => false,
|
||||
],
|
||||
'field_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => false,
|
||||
],
|
||||
'old_value' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'new_value' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'user_id' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => false,
|
||||
],
|
||||
'action_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => false,
|
||||
],
|
||||
'hash' => [
|
||||
'type' => 'CHAR',
|
||||
'constraint' => 64,
|
||||
'null' => false,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['module', 'record_id']);
|
||||
$this->forge->addKey('action_at');
|
||||
$this->forge->addUniqueKey('hash');
|
||||
$this->forge->createTable('clinical_audit_trail', true);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropTable('clinical_audit_trail', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateOpdFhirDocumentTable extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'BIGINT',
|
||||
'constraint' => 20,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'opd_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'opd_session_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'bundle_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => false,
|
||||
],
|
||||
'bundle_json' => [
|
||||
'type' => 'LONGTEXT',
|
||||
'null' => false,
|
||||
],
|
||||
'generated_by' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => false,
|
||||
],
|
||||
'generated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => false,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('opd_id');
|
||||
$this->forge->addKey('opd_session_id');
|
||||
$this->forge->addKey('bundle_type');
|
||||
$this->forge->createTable('opd_fhir_documents', true);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropTable('opd_fhir_documents', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateComplaintsMasterTable extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->forge->addField([
|
||||
'Code' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'Name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => false,
|
||||
],
|
||||
'show_in_short' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 0,
|
||||
],
|
||||
'name_hinglish' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => true,
|
||||
],
|
||||
'keywords' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'ai_hint' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 255,
|
||||
'null' => true,
|
||||
],
|
||||
'is_active' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 1,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('Code', true);
|
||||
$this->forge->addKey('show_in_short');
|
||||
$this->forge->addKey('is_active');
|
||||
$this->forge->createTable('complaints_master', true);
|
||||
|
||||
$rows = [
|
||||
['Code' => 1, 'Name' => 'FEVER', 'show_in_short' => 1, 'name_hinglish' => 'bukhar', 'keywords' => 'fever,bukhar,taap,high temperature', 'ai_hint' => 'fever with duration and pattern'],
|
||||
['Code' => 2, 'Name' => 'PAIN JOINTS', 'show_in_short' => 1, 'name_hinglish' => 'jodo ka dard', 'keywords' => 'joint pain,jodo ka dard,arthralgia', 'ai_hint' => 'joint pain with site and severity'],
|
||||
['Code' => 4, 'Name' => 'PAIN BACK', 'show_in_short' => 1, 'name_hinglish' => 'kamar dard', 'keywords' => 'back pain,kamar dard,low back pain', 'ai_hint' => 'back pain with radiation and activity relation'],
|
||||
['Code' => 5, 'Name' => 'PAIN CHEST', 'show_in_short' => 1, 'name_hinglish' => 'chhati mein dard', 'keywords' => 'chest pain,chhati dard,retrosternal pain', 'ai_hint' => 'chest pain with exertional relation'],
|
||||
['Code' => 6, 'Name' => 'PAIN', 'show_in_short' => 1, 'name_hinglish' => 'dard', 'keywords' => 'pain,dard,ache', 'ai_hint' => 'pain with site duration and score'],
|
||||
['Code' => 7, 'Name' => 'BREATHING DIFFICULTY', 'show_in_short' => 1, 'name_hinglish' => 'saans lene mein dikkat', 'keywords' => 'breathing difficulty,dyspnea,saans ki dikkat', 'ai_hint' => 'dyspnea with onset and positional variation'],
|
||||
['Code' => 10, 'Name' => 'GHABRAHAT', 'show_in_short' => 1, 'name_hinglish' => 'ghabrahat', 'keywords' => 'ghabrahat,anxiety,palpitation', 'ai_hint' => 'anxiety-like symptoms with trigger'],
|
||||
['Code' => 13, 'Name' => 'COUGH DRY', 'show_in_short' => 1, 'name_hinglish' => 'sukhi khansi', 'keywords' => 'dry cough,sukhi khansi,cough', 'ai_hint' => 'cough with type and duration'],
|
||||
['Code' => 14, 'Name' => 'COUGH WITH EXPECTORATION', 'show_in_short' => 1, 'name_hinglish' => 'balgam wali khansi', 'keywords' => 'productive cough,balgam,cough with expectoration', 'ai_hint' => 'cough with sputum color/amount'],
|
||||
['Code' => 18, 'Name' => 'VOMITING', 'show_in_short' => 1, 'name_hinglish' => 'ulti', 'keywords' => 'vomiting,ulti,emesis', 'ai_hint' => 'vomiting frequency and associated nausea'],
|
||||
['Code' => 20, 'Name' => 'DIARRHOEA', 'show_in_short' => 1, 'name_hinglish' => 'dast', 'keywords' => 'diarrhoea,dast,loose stool', 'ai_hint' => 'loose stools with frequency/dehydration signs'],
|
||||
['Code' => 21, 'Name' => 'CONSTIPATION', 'show_in_short' => 1, 'name_hinglish' => 'kabz', 'keywords' => 'constipation,kabz,hard stool', 'ai_hint' => 'constipation with stool frequency'],
|
||||
['Code' => 28, 'Name' => 'JAUNDICE', 'show_in_short' => 1, 'name_hinglish' => 'peeliya', 'keywords' => 'jaundice,peeliya,yellow eyes', 'ai_hint' => 'jaundice with urine/stool color changes'],
|
||||
['Code' => 34, 'Name' => 'BURNING EPIGASTRIUM', 'show_in_short' => 0, 'name_hinglish' => 'pet mein jalan', 'keywords' => 'epigastric burning,acidity,pet mein jalan', 'ai_hint' => 'burning epigastric pain relation with food'],
|
||||
['Code' => 35, 'Name' => 'MICTURETION WITH BURNING', 'show_in_short' => 1, 'name_hinglish' => 'peshab mein jalan', 'keywords' => 'burning micturition,peshab mein jalan,dysuria', 'ai_hint' => 'dysuria with urinary frequency'],
|
||||
['Code' => 38, 'Name' => 'MICTURETION WITH INCREASED FREQUENCY', 'show_in_short' => 0, 'name_hinglish' => 'bar bar peshab', 'keywords' => 'urinary frequency,bar bar peshab', 'ai_hint' => 'increased frequency with urgency'],
|
||||
['Code' => 40, 'Name' => 'HAEMATURIA', 'show_in_short' => 0, 'name_hinglish' => 'peshab mein khoon', 'keywords' => 'haematuria,blood in urine,peshab mein khoon', 'ai_hint' => 'hematuria with clots/pain'],
|
||||
['Code' => 45, 'Name' => 'HEADACHE', 'show_in_short' => 1, 'name_hinglish' => 'sir dard', 'keywords' => 'headache,sir dard,head pain', 'ai_hint' => 'headache with site/severity/photophobia'],
|
||||
['Code' => 47, 'Name' => 'GIDDINESS', 'show_in_short' => 1, 'name_hinglish' => 'chakkar', 'keywords' => 'giddiness,chakkar,dizziness', 'ai_hint' => 'giddiness with postural relation'],
|
||||
['Code' => 48, 'Name' => 'VERTIGO', 'show_in_short' => 1, 'name_hinglish' => 'ghoomna sa lagna', 'keywords' => 'vertigo,room spinning,ghoomna', 'ai_hint' => 'vertigo with duration and triggers'],
|
||||
['Code' => 53, 'Name' => 'SLEEP', 'show_in_short' => 0, 'name_hinglish' => 'neend ki dikkat', 'keywords' => 'sleep disturbance,insomnia,neend', 'ai_hint' => 'sleep disturbance pattern'],
|
||||
['Code' => 56, 'Name' => 'WEAKNESS', 'show_in_short' => 1, 'name_hinglish' => 'kamzori', 'keywords' => 'weakness,kamzori,fatigue', 'ai_hint' => 'weakness generalized/focal with onset'],
|
||||
['Code' => 58, 'Name' => 'PAIN IN ABDOMEN', 'show_in_short' => 1, 'name_hinglish' => 'pet dard', 'keywords' => 'abdominal pain,pet dard,pain abdomen', 'ai_hint' => 'abdominal pain with site and food relation'],
|
||||
['Code' => 59, 'Name' => 'NAUSEA', 'show_in_short' => 1, 'name_hinglish' => 'mann ghabrana', 'keywords' => 'nausea,mann ghabrana', 'ai_hint' => 'nausea with vomiting relation'],
|
||||
['Code' => 62, 'Name' => 'NASAL DISCHARGE', 'show_in_short' => 0, 'name_hinglish' => 'naak bahna', 'keywords' => 'nasal discharge,runny nose,naak bahna', 'ai_hint' => 'nasal discharge with color and duration'],
|
||||
['Code' => 66, 'Name' => 'DRIPPING NOSE', 'show_in_short' => 0, 'name_hinglish' => 'naak se paani', 'keywords' => 'dripping nose,runny nose,naak se paani', 'ai_hint' => 'rhinorrhea details'],
|
||||
['Code' => 77, 'Name' => 'WEIGHT LOSS', 'show_in_short' => 0, 'name_hinglish' => 'wazan kam hona', 'keywords' => 'weight loss,wazan kam', 'ai_hint' => 'weight loss over duration'],
|
||||
['Code' => 84, 'Name' => 'SWEATING', 'show_in_short' => 0, 'name_hinglish' => 'pasina', 'keywords' => 'sweating,pasina,diaphoresis', 'ai_hint' => 'sweating pattern day/night'],
|
||||
['Code' => 91, 'Name' => 'HEARTBURN', 'show_in_short' => 0, 'name_hinglish' => 'seene mein jalan', 'keywords' => 'heartburn,acidity,seene mein jalan', 'ai_hint' => 'heartburn and meal relation'],
|
||||
['Code' => 103, 'Name' => 'URINE DARK', 'show_in_short' => 0, 'name_hinglish' => 'gaadha peshab', 'keywords' => 'dark urine,gaadha peshab', 'ai_hint' => 'dark urine with hydration status'],
|
||||
['Code' => 107, 'Name' => 'WHEEZING', 'show_in_short' => 0, 'name_hinglish' => 'seeti jaisi saans', 'keywords' => 'wheezing,seeti saans', 'ai_hint' => 'wheeze with trigger and nocturnal symptoms'],
|
||||
['Code' => 108, 'Name' => 'FATIGUE', 'show_in_short' => 0, 'name_hinglish' => 'thakan', 'keywords' => 'fatigue,thakan,tiredness', 'ai_hint' => 'fatigue with functional limitation'],
|
||||
['Code' => 110, 'Name' => 'SKIN RASH', 'show_in_short' => 0, 'name_hinglish' => 'daane/chakate', 'keywords' => 'skin rash,daane,itching rash', 'ai_hint' => 'rash distribution and itching'],
|
||||
['Code' => 119, 'Name' => 'ANEMIA', 'show_in_short' => 0, 'name_hinglish' => 'khoon ki kami', 'keywords' => 'anemia,khoon ki kami,pallor', 'ai_hint' => 'anemia related symptoms'],
|
||||
['Code' => 122, 'Name' => 'DEHYDRATION', 'show_in_short' => 0, 'name_hinglish' => 'pani ki kami', 'keywords' => 'dehydration,pani ki kami,dry mouth', 'ai_hint' => 'dehydration signs and intake'],
|
||||
['Code' => 123, 'Name' => 'BODYACHE', 'show_in_short' => 1, 'name_hinglish' => 'body pain', 'keywords' => 'bodyache,body pain,sharir dard', 'ai_hint' => 'generalized bodyache with fever relation'],
|
||||
['Code' => 127, 'Name' => 'TIREDNESS', 'show_in_short' => 1, 'name_hinglish' => 'thakawat', 'keywords' => 'tiredness,thakawat,fatigue', 'ai_hint' => 'tiredness severity and impact'],
|
||||
['Code' => 129, 'Name' => 'BACK PAIN', 'show_in_short' => 1, 'name_hinglish' => 'peeth dard', 'keywords' => 'back pain,peeth dard,kamar dard', 'ai_hint' => 'back pain with red flags'],
|
||||
['Code' => 131, 'Name' => 'COUGH WITH YELLOW EXPECTORATION', 'show_in_short' => 1, 'name_hinglish' => 'peela balgam', 'keywords' => 'yellow sputum,peela balgam,productive cough', 'ai_hint' => 'sputum color and duration'],
|
||||
['Code' => 132, 'Name' => 'COUGH WITH WHITE EXPECTORATION', 'show_in_short' => 1, 'name_hinglish' => 'safed balgam', 'keywords' => 'white sputum,safed balgam,cough', 'ai_hint' => 'sputum characteristics'],
|
||||
['Code' => 133, 'Name' => 'FEVER, CONTINUOUS', 'show_in_short' => 1, 'name_hinglish' => 'lagatar bukhar', 'keywords' => 'continuous fever,lagatar bukhar', 'ai_hint' => 'continuous fever with duration'],
|
||||
['Code' => 134, 'Name' => 'FEVER, INTERMITTENT', 'show_in_short' => 1, 'name_hinglish' => 'ruk ruk kar bukhar', 'keywords' => 'intermittent fever,ruk ruk kar bukhar', 'ai_hint' => 'intermittent fever spikes'],
|
||||
['Code' => 135, 'Name' => 'FEVER, REMITTANT', 'show_in_short' => 1, 'name_hinglish' => 'utarta chadhta bukhar', 'keywords' => 'remittent fever,utarta chadhta bukhar', 'ai_hint' => 'remittent fever pattern'],
|
||||
['Code' => 137, 'Name' => 'WEIGHT GAIN', 'show_in_short' => 0, 'name_hinglish' => 'wazan badhna', 'keywords' => 'weight gain,wazan badhna', 'ai_hint' => 'weight gain trend'],
|
||||
['Code' => 144, 'Name' => 'DIZZINESS', 'show_in_short' => 1, 'name_hinglish' => 'chakkar aana', 'keywords' => 'dizziness,chakkar,giddiness', 'ai_hint' => 'dizziness trigger and duration'],
|
||||
['Code' => 164, 'Name' => 'BURNING MICTURETION', 'show_in_short' => 1, 'name_hinglish' => 'peshab mein jalan', 'keywords' => 'burning micturition,dysuria,peshab mein jalan', 'ai_hint' => 'dysuria with urgency/frequency'],
|
||||
['Code' => 185, 'Name' => 'ITCHING', 'show_in_short' => 0, 'name_hinglish' => 'khujli', 'keywords' => 'itching,khujli,pruritus', 'ai_hint' => 'itching site and duration'],
|
||||
['Code' => 190, 'Name' => 'THROAT PAIN', 'show_in_short' => 0, 'name_hinglish' => 'gale mein dard', 'keywords' => 'throat pain,sore throat,gale mein dard', 'ai_hint' => 'sore throat with fever/cough'],
|
||||
['Code' => 191, 'Name' => 'SNEEZING', 'show_in_short' => 0, 'name_hinglish' => 'chheenk', 'keywords' => 'sneezing,chheenk,allergy', 'ai_hint' => 'sneezing with allergen exposure'],
|
||||
['Code' => 205, 'Name' => 'BLOOD IN STOOL', 'show_in_short' => 1, 'name_hinglish' => 'stool mein khoon', 'keywords' => 'blood in stool,stool mein khoon', 'ai_hint' => 'blood in stool quantity/frequency'],
|
||||
['Code' => 227, 'Name' => 'IRRITABILITY', 'show_in_short' => 0, 'name_hinglish' => 'chidhchidhapan', 'keywords' => 'irritability,chidhchidhapan,mood changes', 'ai_hint' => 'behavioral symptoms with sleep relation'],
|
||||
['Code' => 228, 'Name' => 'DEPRESSION', 'show_in_short' => 0, 'name_hinglish' => 'udasi', 'keywords' => 'depression,udasi,low mood', 'ai_hint' => 'low mood with duration and impact'],
|
||||
['Code' => 232, 'Name' => 'IRRITATION', 'show_in_short' => 1, 'name_hinglish' => 'jalan/irritation', 'keywords' => 'irritation,jalan,burning sensation', 'ai_hint' => 'site specific irritation details'],
|
||||
];
|
||||
|
||||
$now = date('Y-m-d H:i:s');
|
||||
foreach ($rows as &$row) {
|
||||
$row['created_at'] = $now;
|
||||
$row['updated_at'] = $now;
|
||||
$row['is_active'] = 1;
|
||||
}
|
||||
unset($row);
|
||||
|
||||
if (! empty($rows)) {
|
||||
$this->db->table('complaints_master')->insertBatch($rows);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropTable('complaints_master', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateBridgeSyncQueueTable extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'BIGINT',
|
||||
'constraint' => 20,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'channel' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 50,
|
||||
'default' => 'bridge',
|
||||
],
|
||||
'event_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 120,
|
||||
'null' => false,
|
||||
],
|
||||
'entity_type' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 120,
|
||||
'null' => true,
|
||||
],
|
||||
'entity_id' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => true,
|
||||
],
|
||||
'payload_json' => [
|
||||
'type' => 'LONGTEXT',
|
||||
'null' => false,
|
||||
],
|
||||
'payload_hash' => [
|
||||
'type' => 'CHAR',
|
||||
'constraint' => 64,
|
||||
'null' => false,
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
'default' => 'pending',
|
||||
'null' => false,
|
||||
],
|
||||
'attempts' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'default' => 0,
|
||||
'null' => false,
|
||||
],
|
||||
'max_attempts' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'default' => 10,
|
||||
'null' => false,
|
||||
],
|
||||
'next_attempt_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'last_error' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'locked_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'locked_by' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => true,
|
||||
],
|
||||
'sent_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('status');
|
||||
$this->forge->addKey('next_attempt_at');
|
||||
$this->forge->addKey('payload_hash');
|
||||
$this->forge->addKey(['channel', 'event_type']);
|
||||
$this->forge->createTable('bridge_sync_queue', true);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropTable('bridge_sync_queue', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class CreateLabAiExtractionTables extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'BIGINT',
|
||||
'constraint' => 20,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'invoice_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'lab_type' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'file_upload_id' => [
|
||||
'type' => 'INT',
|
||||
'constraint' => 11,
|
||||
'unsigned' => true,
|
||||
'null' => true,
|
||||
],
|
||||
'panel_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 120,
|
||||
'null' => true,
|
||||
],
|
||||
'ai_provider' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 50,
|
||||
'default' => 'azure-openai',
|
||||
],
|
||||
'model_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 120,
|
||||
'null' => true,
|
||||
],
|
||||
'ocr_text' => [
|
||||
'type' => 'LONGTEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'raw_response_json' => [
|
||||
'type' => 'LONGTEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'status' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
'default' => 'completed',
|
||||
],
|
||||
'doctor_verified' => [
|
||||
'type' => 'TINYINT',
|
||||
'constraint' => 1,
|
||||
'default' => 0,
|
||||
],
|
||||
'verified_by' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => true,
|
||||
],
|
||||
'verified_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey(['invoice_id', 'lab_type']);
|
||||
$this->forge->addKey('file_upload_id');
|
||||
$this->forge->addKey('doctor_verified');
|
||||
$this->forge->createTable('lab_ai_extraction_batches', true);
|
||||
|
||||
$this->forge->addField([
|
||||
'id' => [
|
||||
'type' => 'BIGINT',
|
||||
'constraint' => 20,
|
||||
'unsigned' => true,
|
||||
'auto_increment' => true,
|
||||
],
|
||||
'batch_id' => [
|
||||
'type' => 'BIGINT',
|
||||
'constraint' => 20,
|
||||
'unsigned' => true,
|
||||
'null' => false,
|
||||
],
|
||||
'test_name' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 180,
|
||||
'null' => false,
|
||||
],
|
||||
'test_value' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 120,
|
||||
'null' => true,
|
||||
],
|
||||
'unit' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => true,
|
||||
],
|
||||
'reference_range' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 180,
|
||||
'null' => true,
|
||||
],
|
||||
'abnormal_flag' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 20,
|
||||
'null' => true,
|
||||
],
|
||||
'raw_line' => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
],
|
||||
'created_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
'updated_at' => [
|
||||
'type' => 'DATETIME',
|
||||
'null' => true,
|
||||
],
|
||||
]);
|
||||
$this->forge->addKey('id', true);
|
||||
$this->forge->addKey('batch_id');
|
||||
$this->forge->addKey('test_name');
|
||||
$this->forge->createTable('lab_ai_extraction_values', true);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->forge->dropTable('lab_ai_extraction_values', true);
|
||||
$this->forge->dropTable('lab_ai_extraction_batches', true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddDoctorRegistrationNoToDoctorMaster extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! $this->db->tableExists('doctor_master')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->db->fieldExists('doctor_reg_no', 'doctor_master')) {
|
||||
$this->forge->addColumn('doctor_master', [
|
||||
'doctor_reg_no' => [
|
||||
'type' => 'VARCHAR',
|
||||
'constraint' => 80,
|
||||
'null' => true,
|
||||
'after' => 'mphone1',
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if ($this->db->tableExists('doctor_master') && $this->db->fieldExists('doctor_reg_no', 'doctor_master')) {
|
||||
$this->forge->dropColumn('doctor_master', 'doctor_reg_no');
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user