feat(medical-store): ABDM-compatible multi-building pharmacy, POS desktop keyboard workflow, unit dispensing, and split payments
This commit is contained in:
parent
ee7cf59c49
commit
765286e7fa
14
.gitignore
vendored
14
.gitignore
vendored
|
|
@ -144,3 +144,17 @@ public/uploads/*
|
|||
!public/assets/
|
||||
!public/assets/img/
|
||||
!public/assets/img/**
|
||||
|
||||
# Android build & local properties
|
||||
android_opd_queue_tv/.gradle/
|
||||
android_opd_queue_tv/*/build/
|
||||
android_opd_queue_tv/build/
|
||||
android_opd_queue_tv/local.properties
|
||||
|
||||
# Temporary and extraction directories
|
||||
docx_extracted/
|
||||
writable/debug/*
|
||||
writable/github_update_cache.json
|
||||
E-AtriaHMS.docx
|
||||
E-AtriaHMS.zip
|
||||
|
||||
|
|
|
|||
77
HMS_MEDICAL_STORE_SESSION.md
Normal file
77
HMS_MEDICAL_STORE_SESSION.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# HMS Multi-Building Medical Store & ABDM Pharmacy System
|
||||
**Session Name:** `HMS Multi-Store Pharmacy & ABDM Integration`
|
||||
**Antigravity Conversation ID:** `3731d0c5-f4df-435e-b54f-f690562e18e3`
|
||||
**Last Updated:** September 8, 2026
|
||||
|
||||
---
|
||||
|
||||
## Quick Resume Instructions After Computer Restart
|
||||
|
||||
### 1. In Antigravity IDE
|
||||
1. Open Antigravity IDE and reopen the workspace `HMS_CI4_OLD`.
|
||||
2. In the Chat panel, click the **Chat History / Clock icon** (or open the left conversation drawer).
|
||||
3. Select this session: **`HMS Multi-Store Pharmacy & ABDM Integration`** (ID: `3731d0c5-f4df-435e-b54f-f690562e18e3`).
|
||||
4. Type your message and continue seamlessly!
|
||||
|
||||
*Tip: If you ever open a new chat, you can type `@HMS_MEDICAL_STORE_SESSION.md` or `@conversation` to instantly restore all context.*
|
||||
|
||||
---
|
||||
|
||||
## System Access & Credentials Summary
|
||||
|
||||
### Development Server
|
||||
- Command: `php spark serve` (in `d:\Workplace\HMS_CI4_OLD`)
|
||||
- Server URL: `http://localhost:8080`
|
||||
|
||||
### HMS Admin Management
|
||||
- **URL:** [http://localhost:8080/setting/admin/medical-store](http://localhost:8080/setting/admin/medical-store)
|
||||
- **Features:** Store configuration, DL 20B/21B licenses, GSTIN, Pharmacist details, ABDM HFR/HIP/HPR registries, 60-min OTP generator, terminal device authorization, and Marg ERP CSV import.
|
||||
|
||||
### Direct Counter Desks (React PWA)
|
||||
- **Counter A (Main Hospital Block A):**
|
||||
- Direct Link: [http://localhost:8080/MedicalStore/storeA](http://localhost:8080/MedicalStore/storeA)
|
||||
- Store Code: `ST-MAIN`
|
||||
- Permanent Security Key: `STORE-SEC-A91B4C72`
|
||||
- ABDM HFR ID: `IN0710001234`
|
||||
- Pharmacist HPR ID: `91-8822-4411-9901`
|
||||
- **Counter B (OPD Block B):**
|
||||
- Direct Link: [http://localhost:8080/MedicalStore/storeB](http://localhost:8080/MedicalStore/storeB)
|
||||
- Store Code: `ST-OPD-B2`
|
||||
- Permanent Security Key: `STORE-SEC-B84F29D1`
|
||||
- ABDM HFR ID: `IN0710001234-OPD`
|
||||
- Pharmacist HPR ID: `91-8822-4411-9902`
|
||||
|
||||
---
|
||||
|
||||
## Core Technical Reference
|
||||
|
||||
1. **Zero Legacy Disturbance:**
|
||||
- Legacy pharmacy tables (`invoice_med_master`, `inv_med_item`, `med_*`) and controllers remain 100% untouched.
|
||||
- All new tables use the **`mst_*`** prefix (15 tables).
|
||||
2. **ABDM Compatibility (M1 & M2):**
|
||||
- Patient search by 14-digit ABHA Number or ABHA Address.
|
||||
- Care Context generation: `PHARM-{store_code}-{invoice_no}`.
|
||||
- NRCES FHIR R4 Bundle profile: `https://nrces.in/ndhm/fhir/r4/StructureDefinition/MedicationDispenseDocument`.
|
||||
- Coded with SNOMED-CT clinical terminology.
|
||||
- Gateway Bridge queue integration: `abdm_sync_record`.
|
||||
- Bundle preview endpoint: `GET /api/v1/medical-store/abdm/bundle/{sale_id}`.
|
||||
3. **Multi-Format Invoices:**
|
||||
- 80mm Thermal Slip (Fast 1–5 item OTC/OPD).
|
||||
- A5 Invoice (Normal OPD/Walk-in with GST summary).
|
||||
- A4 Hospital Tax Invoice (IPD admissions & large bills).
|
||||
4. **Marg ERP Migration:**
|
||||
- Supported CSV import with auto-detected columns. Sample test file: `scratch/test_marg_sample.csv`.
|
||||
5. **Double-Entry Accounting & Statutory Drug Register:**
|
||||
- Automated ledger postings, Daily Cash Book, GSTR-1 outward reports, and mandatory Schedule H1 drug register.
|
||||
6. **Retail Loose Tablet & Unit Dispensing:**
|
||||
- Exact per-tablet pricing (`Strip MRP / units_per_pack`), exact stock deduction in individual tablets, and support for Loose Tab, Strip, and Combo sales.
|
||||
7. **Split / Mixed Payment Mode & Audit:**
|
||||
- Supports partial payments (e.g. ₹35 Cash + ₹100 UPI) with 12-digit UTR and bank name capturing for bank reconciliation and audit.
|
||||
8. **Keyboard-First Zero-Mouse POS Workflow (Marg ERP Standard):**
|
||||
- High-contrast single-line Quick Keys ribbon.
|
||||
- Hotkeys: `F2` (Medicine Search), `F4` (Patient Search), `F7` (Whole Discount), `F8` (Payment Mode), `F9 / Ctrl+Enter` (Complete Sale & Print), `Alt+T` (Loose Tab), `Alt+S` (Strip), `Shift+Delete` (Remove Item).
|
||||
- Auto-focus on Medicine Search on page load; `Enter` on quantity immediately commits and jumps focus back to Medicine Lookup for the next scan.
|
||||
9. **Compact "Qty & Unit" Cell:**
|
||||
- Single-line input group with type selector dropdown (`Tab`, `Strip`, `Str+Tab`) positioned before the quantity box.
|
||||
- Automatically defaults to `Tab` (loose units).
|
||||
|
||||
13
android_opd_queue_tv/gradle/gradle-daemon-jvm.properties
Normal file
13
android_opd_queue_tv/gradle/gradle-daemon-jvm.properties
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/b96cc4b9c59b5bff244af296e50d5ea3/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/fdfa2f9fadcf75fb9616fde209d60b55/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/b96cc4b9c59b5bff244af296e50d5ea3/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fdfa2f9fadcf75fb9616fde209d60b55/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/97b61e8788c7490a5f53d8951b11ea7a/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/feb8af2956f2e263086e0a8f9a1df390/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/b96cc4b9c59b5bff244af296e50d5ea3/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/fdfa2f9fadcf75fb9616fde209d60b55/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/eff42deed1d8947129a4e66cd07a89f4/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/8fe418192094ee8db0da620bcb6b1629/redirect
|
||||
toolchainVendor=JETBRAINS
|
||||
toolchainVersion=25
|
||||
BIN
android_opd_queue_tv/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
android_opd_queue_tv/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
android_opd_queue_tv/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
android_opd_queue_tv/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
248
android_opd_queue_tv/gradlew
vendored
Normal file
248
android_opd_queue_tv/gradlew
vendored
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
93
android_opd_queue_tv/gradlew.bat
vendored
Normal file
93
android_opd_queue_tv/gradlew.bat
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
|
@ -1413,6 +1413,14 @@ $routes->group('setting', static function($routes) {
|
|||
$routes->post('admin/opd-queue-tv/save', 'Setting\\OpdQueueSetting::save');
|
||||
$routes->post('admin/opd-queue-tv/upload-banner', 'Setting\\OpdQueueSetting::uploadBanner');
|
||||
$routes->post('admin/opd-queue-tv/delete-banner', 'Setting\\OpdQueueSetting::deleteBanner');
|
||||
$routes->get('admin/medical-store', 'Setting\\MedicalStoreAdmin::index');
|
||||
$routes->post('admin/medical-store/save', 'Setting\\MedicalStoreAdmin::save');
|
||||
$routes->post('admin/medical-store/delete', 'Setting\\MedicalStoreAdmin::delete');
|
||||
$routes->post('admin/medical-store/generate-otp', 'Setting\\MedicalStoreAdmin::generateOtp');
|
||||
$routes->post('admin/medical-store/regenerate-key', 'Setting\\MedicalStoreAdmin::regenerateSecurityKey');
|
||||
$routes->post('admin/medical-store/revoke-device', 'Setting\\MedicalStoreAdmin::revokeDevice');
|
||||
$routes->post('admin/medical-store/import-marg', 'Setting\\MedicalStoreAdmin::importMarg');
|
||||
|
||||
$routes->get('admin/bed-management', 'Setting\\BedManagement::index', ['filter' => $settingsBedFilter]);
|
||||
$routes->get('admin/departments', 'Setting\\BedManagement::departments', ['filter' => $settingsBedFilter]);
|
||||
$routes->post('admin/departments/save', 'Setting\\BedManagement::saveDepartment', ['filter' => $settingsBedFilter]);
|
||||
|
|
@ -1641,5 +1649,45 @@ $routes->group('api/v1', ['namespace' => 'App\Controllers\Api\v1'], static funct
|
|||
$routes->get('doctor/ipd/list/(:num)', 'DoctorApi::ipdList/$1');
|
||||
$routes->get('doctor/ipd/workspace/(:num)', 'DoctorApi::patientWorkspace/$1');
|
||||
$routes->post('doctor/ipd/treatment/save/(:num)', 'DoctorApi::saveTreatmentNote/$1');
|
||||
|
||||
// Medical Store PWA APIs
|
||||
$routes->get('medical-store/stores', 'MedicalStoreApi::stores');
|
||||
$routes->post('medical-store/stores/save', 'MedicalStoreApi::saveStore');
|
||||
$routes->get('medical-store/patient/search', 'MedicalStoreApi::searchPatient');
|
||||
$routes->get('medical-store/patient/prescription/(:segment)/(:num)', 'MedicalStoreApi::getPrescription/$1/$2');
|
||||
$routes->get('medical-store/items/search', 'MedicalStoreApi::searchItems');
|
||||
$routes->post('medical-store/stock/opening', 'MedicalStoreApi::saveOpeningStock');
|
||||
$routes->get('medical-store/stock/list', 'MedicalStoreApi::stockList');
|
||||
$routes->get('medical-store/stock/alerts', 'MedicalStoreApi::stockAlerts');
|
||||
$routes->post('medical-store/sales/save', 'MedicalStoreApi::saveSale');
|
||||
$routes->get('medical-store/sales/invoice/(:num)', 'MedicalStoreApi::getInvoice/$1');
|
||||
$routes->get('medical-store/sales/recent', 'MedicalStoreApi::recentSales');
|
||||
$routes->get('medical-store/suppliers', 'MedicalStoreApi::suppliers');
|
||||
$routes->post('medical-store/suppliers/save', 'MedicalStoreApi::saveSupplier');
|
||||
$routes->post('medical-store/purchase/save', 'MedicalStoreApi::savePurchase');
|
||||
$routes->post('medical-store/purchase/payment', 'MedicalStoreApi::saveSupplierPayment');
|
||||
$routes->post('medical-store/transfer/request', 'MedicalStoreApi::requestTransfer');
|
||||
$routes->post('medical-store/transfer/dispatch', 'MedicalStoreApi::dispatchTransfer');
|
||||
$routes->post('medical-store/transfer/receive', 'MedicalStoreApi::receiveTransfer');
|
||||
$routes->get('medical-store/accounting/supplier-ledger/(:num)', 'MedicalStoreApi::getSupplierLedger/$1');
|
||||
$routes->get('medical-store/accounting/patient-ledger/(:segment)', 'MedicalStoreApi::getPatientLedger/$1');
|
||||
$routes->get('medical-store/accounting/daybook', 'MedicalStoreApi::getDaybook');
|
||||
$routes->get('medical-store/accounting/gst-report', 'MedicalStoreApi::getGstReport');
|
||||
$routes->get('medical-store/accounting/bank-reconciliation', 'MedicalStoreApi::getBankReconciliation');
|
||||
$routes->post('medical-store/accounting/reconcile-bank', 'MedicalStoreApi::reconcileBank');
|
||||
$routes->get('medical-store/compliance/schedule-h1-register', 'MedicalStoreApi::getScheduleH1Register');
|
||||
$routes->post('medical-store/device/verify', 'MedicalStoreApi::verifyDevice');
|
||||
$routes->post('medical-store/device/check', 'MedicalStoreApi::checkDeviceStatus');
|
||||
$routes->post('medical-store/stock/import-marg', 'MedicalStoreApi::importMarg');
|
||||
$routes->get('medical-store/abdm/bundle/(:num)', 'MedicalStoreApi::getAbdmBundle/$1');
|
||||
$routes->post('medical-store/abdm/link-abha', 'MedicalStoreApi::linkAbha');
|
||||
});
|
||||
|
||||
// Dedicated Direct Store Links (e.g. /MedicalStore/storeA, /MedicalStore/storeB)
|
||||
$routes->get('MedicalStore', 'Api\v1\MedicalStoreApi::pwaIndex');
|
||||
$routes->get('MedicalStore/(:any)', 'Api\v1\MedicalStoreApi::pwaIndex/$1');
|
||||
$routes->get('app/medical-store', 'Api\v1\MedicalStoreApi::pwaIndex');
|
||||
$routes->get('app/medical-store/(:any)', 'Api\v1\MedicalStoreApi::pwaIndex/$1');
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
2167
app/Controllers/Api/v1/MedicalStoreApi.php
Normal file
2167
app/Controllers/Api/v1/MedicalStoreApi.php
Normal file
File diff suppressed because it is too large
Load Diff
452
app/Controllers/Setting/MedicalStoreAdmin.php
Normal file
452
app/Controllers/Setting/MedicalStoreAdmin.php
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controllers\Setting;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
|
||||
class MedicalStoreAdmin extends BaseController
|
||||
{
|
||||
protected $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = \Config\Database::connect();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$q = trim((string)($this->request->getGet('q') ?? ''));
|
||||
|
||||
$builder = $this->db->table('mst_stores');
|
||||
if (!empty($q)) {
|
||||
$builder->groupStart()
|
||||
->like('store_name', $q)
|
||||
->orLike('store_code', $q)
|
||||
->orLike('store_slug', $q)
|
||||
->orLike('building_name', $q)
|
||||
->orLike('drug_license_no_20b', $q)
|
||||
->orLike('gstin', $q)
|
||||
->groupEnd();
|
||||
}
|
||||
|
||||
$stores = $builder->orderBy('is_main_store', 'DESC')->orderBy('store_id', 'ASC')->get()->getResultArray();
|
||||
|
||||
// Enforce security keys and slugs
|
||||
foreach ($stores as &$st) {
|
||||
$needsUpdate = false;
|
||||
$updates = [];
|
||||
|
||||
if (empty($st['store_slug'])) {
|
||||
$st['store_slug'] = strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $st['store_code'] ?: ('store' . $st['store_id'])));
|
||||
$updates['store_slug'] = $st['store_slug'];
|
||||
$needsUpdate = true;
|
||||
}
|
||||
|
||||
if (empty($st['security_key'])) {
|
||||
$st['security_key'] = 'HMS-' . strtoupper(bin2hex(random_bytes(3))) . '-' . rand(100, 999);
|
||||
$updates['security_key'] = $st['security_key'];
|
||||
$needsUpdate = true;
|
||||
}
|
||||
|
||||
if ($needsUpdate) {
|
||||
$this->db->table('mst_stores')->where('store_id', $st['store_id'])->update($updates);
|
||||
}
|
||||
|
||||
// Fetch authorized devices count
|
||||
$deviceCount = $this->db->table('mst_store_devices')
|
||||
->where('store_id', $st['store_id'])
|
||||
->where('status', 'authorized')
|
||||
->countAllResults();
|
||||
$st['authorized_devices_count'] = $deviceCount;
|
||||
}
|
||||
|
||||
// Fetch recent authorized devices across all stores
|
||||
$devices = $this->db->table('mst_store_devices d')
|
||||
->select('d.*, s.store_name, s.store_code')
|
||||
->join('mst_stores s', 's.store_id = d.store_id')
|
||||
->orderBy('d.device_id', 'DESC')
|
||||
->limit(30)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
return view('Setting/MedicalStore/medical_store_index', [
|
||||
'stores' => $stores,
|
||||
'devices' => $devices,
|
||||
'searchQuery' => $q
|
||||
]);
|
||||
}
|
||||
|
||||
public function save()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['ok' => false, 'error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$id = (int)($this->request->getPost('store_id') ?? 0);
|
||||
$storeCode = trim((string)($this->request->getPost('store_code') ?? ''));
|
||||
$storeSlug = strtolower(trim((string)($this->request->getPost('store_slug') ?? '')));
|
||||
$storeName = trim((string)($this->request->getPost('store_name') ?? ''));
|
||||
|
||||
if (empty($storeName) || empty($storeCode)) {
|
||||
return $this->response->setJSON(['ok' => false, 'error' => 'Store Name and Store Code are required.']);
|
||||
}
|
||||
|
||||
if (empty($storeSlug)) {
|
||||
$storeSlug = strtolower(preg_replace('/[^a-zA-Z0-9]/', '', $storeCode));
|
||||
}
|
||||
|
||||
// Check unique slug
|
||||
$checkSlug = $this->db->table('mst_stores')
|
||||
->where('store_slug', $storeSlug)
|
||||
->where('store_id !=', $id)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($checkSlug) {
|
||||
return $this->response->setJSON(['ok' => false, 'error' => "URL Link Slug '{$storeSlug}' is already assigned to another store. Please choose a unique slug."]);
|
||||
}
|
||||
|
||||
$secKey = trim((string)($this->request->getPost('security_key') ?? ''));
|
||||
if (empty($secKey)) {
|
||||
$secKey = 'HMS-' . strtoupper(bin2hex(random_bytes(3))) . '-' . rand(100, 999);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'store_code' => $storeCode,
|
||||
'store_slug' => $storeSlug,
|
||||
'store_name' => $storeName,
|
||||
'building_name' => trim((string)($this->request->getPost('building_name') ?? '')),
|
||||
'floor_no' => trim((string)($this->request->getPost('floor_no') ?? '')),
|
||||
'room_no' => trim((string)($this->request->getPost('room_no') ?? '')),
|
||||
'is_main_store' => !empty($this->request->getPost('is_main_store')) ? 1 : 0,
|
||||
'drug_license_no_20b' => trim((string)($this->request->getPost('drug_license_no_20b') ?? '')),
|
||||
'drug_license_no_21b' => trim((string)($this->request->getPost('drug_license_no_21b') ?? '')),
|
||||
'drug_license_no_20f_x' => trim((string)($this->request->getPost('drug_license_no_20f_x') ?? '')),
|
||||
'gstin' => strtoupper(trim((string)($this->request->getPost('gstin') ?? ''))),
|
||||
'pan_no' => strtoupper(trim((string)($this->request->getPost('pan_no') ?? ''))),
|
||||
'fssai_no' => trim((string)($this->request->getPost('fssai_no') ?? '')),
|
||||
'state_code' => trim((string)($this->request->getPost('state_code') ?? '07')),
|
||||
'state_name' => trim((string)($this->request->getPost('state_name') ?? 'Delhi')),
|
||||
'registered_pharmacist_name' => trim((string)($this->request->getPost('registered_pharmacist_name') ?? '')),
|
||||
'pharmacist_reg_no' => trim((string)($this->request->getPost('pharmacist_reg_no') ?? '')),
|
||||
'contact_phone' => trim((string)($this->request->getPost('contact_phone') ?? '')),
|
||||
'contact_email' => trim((string)($this->request->getPost('contact_email') ?? '')),
|
||||
'address' => trim((string)($this->request->getPost('address') ?? '')),
|
||||
'invoice_prefix' => trim((string)($this->request->getPost('invoice_prefix') ?? 'INV/')),
|
||||
'next_invoice_no' => !empty($this->request->getPost('next_invoice_no')) ? (int)$this->request->getPost('next_invoice_no') : 1001,
|
||||
'bank_name' => trim((string)($this->request->getPost('bank_name') ?? '')),
|
||||
'bank_account_no' => trim((string)($this->request->getPost('bank_account_no') ?? '')),
|
||||
'bank_ifsc' => trim((string)($this->request->getPost('bank_ifsc') ?? '')),
|
||||
'upi_id' => trim((string)($this->request->getPost('upi_id') ?? '')),
|
||||
'abdm_hfr_id' => trim((string)($this->request->getPost('abdm_hfr_id') ?? '')),
|
||||
'abdm_hip_id' => trim((string)($this->request->getPost('abdm_hip_id') ?? '')),
|
||||
'pharmacist_hpr_id' => trim((string)($this->request->getPost('pharmacist_hpr_id') ?? '')),
|
||||
'terms_conditions' => trim((string)($this->request->getPost('terms_conditions') ?? '')),
|
||||
'security_key' => $secKey,
|
||||
'is_active' => isset($_POST['is_active']) ? (int)$this->request->getPost('is_active') : 1,
|
||||
];
|
||||
|
||||
if ($id > 0) {
|
||||
$this->db->table('mst_stores')->where('store_id', $id)->update($data);
|
||||
$msg = 'Medical Store details updated successfully.';
|
||||
} else {
|
||||
$this->db->table('mst_stores')->insert($data);
|
||||
$id = $this->db->insertID();
|
||||
$msg = 'New Medical Store Counter created successfully.';
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['ok' => true, 'message' => $msg, 'store_id' => $id, 'store_slug' => $storeSlug]);
|
||||
}
|
||||
|
||||
public function generateOtp()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['ok' => false, 'error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$storeId = (int)($this->request->getPost('store_id') ?? 0);
|
||||
$store = $this->db->table('mst_stores')->where('store_id', $storeId)->get()->getRowArray();
|
||||
if (!$store) {
|
||||
return $this->response->setJSON(['ok' => false, 'error' => 'Store not found']);
|
||||
}
|
||||
|
||||
$otp = (string)rand(100000, 999999);
|
||||
$expiry = date('Y-m-d H:i:s', strtotime('+60 minutes'));
|
||||
|
||||
$this->db->table('mst_stores')->where('store_id', $storeId)->update([
|
||||
'current_otp' => $otp,
|
||||
'otp_expiry' => $expiry
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'ok' => true,
|
||||
'message' => 'Terminal Verification OTP generated successfully.',
|
||||
'otp' => $otp,
|
||||
'expiry' => date('h:i A (d-m-Y)', strtotime($expiry)),
|
||||
'store_name' => $store['store_name']
|
||||
]);
|
||||
}
|
||||
|
||||
public function regenerateSecurityKey()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['ok' => false, 'error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$storeId = (int)($this->request->getPost('store_id') ?? 0);
|
||||
$newKey = 'HMS-' . strtoupper(bin2hex(random_bytes(3))) . '-' . rand(100, 999);
|
||||
|
||||
$this->db->table('mst_stores')->where('store_id', $storeId)->update([
|
||||
'security_key' => $newKey
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'ok' => true,
|
||||
'message' => 'New Security Key generated successfully.',
|
||||
'security_key' => $newKey
|
||||
]);
|
||||
}
|
||||
|
||||
public function revokeDevice()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['ok' => false, 'error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$deviceId = (int)($this->request->getPost('device_id') ?? 0);
|
||||
$this->db->table('mst_store_devices')->where('device_id', $deviceId)->update([
|
||||
'status' => 'revoked'
|
||||
]);
|
||||
|
||||
return $this->response->setJSON(['ok' => true, 'message' => 'Terminal computer access revoked successfully.']);
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
if (!$this->request->isAJAX()) {
|
||||
return $this->response->setStatusCode(400)->setJSON(['ok' => false, 'error' => 'Invalid request']);
|
||||
}
|
||||
|
||||
$storeId = (int)($this->request->getPost('store_id') ?? 0);
|
||||
// Soft deactivate store
|
||||
$this->db->table('mst_stores')->where('store_id', $storeId)->update(['is_active' => 0]);
|
||||
|
||||
return $this->response->setJSON(['ok' => true, 'message' => 'Store deactivated successfully.']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marg Pharmacy Software / Excel CSV Inventory Import
|
||||
*/
|
||||
public function importMarg()
|
||||
{
|
||||
$storeId = (int)($this->request->getPost('store_id') ?? 0);
|
||||
if ($storeId <= 0) {
|
||||
return $this->response->setJSON(['ok' => false, 'error' => 'Please select a destination Medical Store.']);
|
||||
}
|
||||
|
||||
$file = $this->request->getFile('import_file');
|
||||
if (!$file || !$file->isValid()) {
|
||||
return $this->response->setJSON(['ok' => false, 'error' => 'Please upload a valid CSV or Excel file.']);
|
||||
}
|
||||
|
||||
$ext = strtolower($file->getClientExtension());
|
||||
if (!in_array($ext, ['csv', 'txt'])) {
|
||||
return $this->response->setJSON(['ok' => false, 'error' => 'Please upload CSV formatted export from Marg ERP or Excel.']);
|
||||
}
|
||||
|
||||
$handle = fopen($file->getTempName(), 'r');
|
||||
if (!$handle) {
|
||||
return $this->response->setJSON(['ok' => false, 'error' => 'Unable to read uploaded file.']);
|
||||
}
|
||||
|
||||
$header = fgetcsv($handle, 4096, ',');
|
||||
if (!$header) {
|
||||
fclose($handle);
|
||||
return $this->response->setJSON(['ok' => false, 'error' => 'CSV file is empty.']);
|
||||
}
|
||||
|
||||
// Normalize header names
|
||||
$headerMap = [];
|
||||
foreach ($header as $idx => $h) {
|
||||
$cleaned = strtolower(trim(preg_replace('/[^a-zA-Z0-9]/', '', $h)));
|
||||
$headerMap[$cleaned] = $idx;
|
||||
}
|
||||
|
||||
// Helper function to find column index
|
||||
$findCol = function(array $aliases) use ($headerMap) {
|
||||
foreach ($aliases as $a) {
|
||||
$cleaned = strtolower(trim(preg_replace('/[^a-zA-Z0-9]/', '', $a)));
|
||||
if (isset($headerMap[$cleaned])) return $headerMap[$cleaned];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
$colName = $findCol(['itemname', 'product', 'particulars', 'medicinename', 'name', 'item']);
|
||||
$colGeneric = $findCol(['generic', 'genericname', 'molecule', 'composition']);
|
||||
$colCat = $findCol(['category', 'type', 'itemtype']);
|
||||
$colPack = $findCol(['packing', 'pack', 'packsize']);
|
||||
$colBatch = $findCol(['batch', 'batchno', 'batchnumber']);
|
||||
$colExpiry = $findCol(['exp', 'expiry', 'expdate', 'expirydate']);
|
||||
$colMrp = $findCol(['mrp', 'maxretailprice']);
|
||||
$colPtr = $findCol(['ptr', 'purchaserate', 'costrate', 'rate', 'cost', 'purrate']);
|
||||
$colHsn = $findCol(['hsn', 'hsncode', 'hsnno']);
|
||||
$colGst = $findCol(['gst', 'gstpct', 'gstper', 'tax', 'taxpct']);
|
||||
$colQty = $findCol(['qty', 'quantity', 'stock', 'openingstock', 'opqty']);
|
||||
$colBarcode = $findCol(['barcode', 'itemcode', 'code']);
|
||||
|
||||
if ($colName === null) {
|
||||
fclose($handle);
|
||||
return $this->response->setJSON(['ok' => false, 'error' => "Could not locate 'Item Name' / 'Product' column in CSV header."]);
|
||||
}
|
||||
|
||||
$importedRows = 0;
|
||||
$newItems = 0;
|
||||
$newBatches = 0;
|
||||
$totalValuation = 0;
|
||||
|
||||
$this->db->transStart();
|
||||
|
||||
while (($row = fgetcsv($handle, 4096, ',')) !== false) {
|
||||
$name = trim($row[$colName] ?? '');
|
||||
if (empty($name)) continue;
|
||||
|
||||
$generic = ($colGeneric !== null) ? trim($row[$colGeneric] ?? '') : '';
|
||||
$cat = ($colCat !== null) ? trim($row[$colCat] ?? 'Tablet') : 'Tablet';
|
||||
$pack = ($colPack !== null) ? trim($row[$colPack] ?? '10 Tablets') : '10 Tablets';
|
||||
$batchNo = ($colBatch !== null) ? trim($row[$colBatch] ?? 'OPN-01') : 'OPN-01';
|
||||
$expRaw = ($colExpiry !== null) ? trim($row[$colExpiry] ?? '') : '';
|
||||
$mrp = ($colMrp !== null) ? (float)preg_replace('/[^0-9.]/', '', $row[$colMrp] ?? '0') : 0;
|
||||
$ptr = ($colPtr !== null) ? (float)preg_replace('/[^0-9.]/', '', $row[$colPtr] ?? '0') : ($mrp * 0.75);
|
||||
$hsn = ($colHsn !== null) ? trim($row[$colHsn] ?? '3004') : '3004';
|
||||
$gst = ($colGst !== null) ? (float)preg_replace('/[^0-9.]/', '', $row[$colGst] ?? '12') : 12;
|
||||
$qty = ($colQty !== null) ? (int)preg_replace('/[^0-9]/', '', $row[$colQty] ?? '10') : 10;
|
||||
$barcode = ($colBarcode !== null) ? trim($row[$colBarcode] ?? '') : '';
|
||||
|
||||
// Parse Marg Expiry formats (MM/YY, MM/YYYY, DD-MM-YYYY, YYYY-MM-DD)
|
||||
$expiryDate = date('Y-12-31', strtotime('+1 year'));
|
||||
if (!empty($expRaw)) {
|
||||
if (preg_match('/^(\d{1,2})[\/\-](\d{2})$/', $expRaw, $m)) {
|
||||
$expiryDate = '20' . $m[2] . '-' . str_pad($m[1], 2, '0', STR_PAD_LEFT) . '-28';
|
||||
} elseif (preg_match('/^(\d{1,2})[\/\-](\d{4})$/', $expRaw, $m)) {
|
||||
$expiryDate = $m[2] . '-' . str_pad($m[1], 2, '0', STR_PAD_LEFT) . '-28';
|
||||
} elseif (strtotime($expRaw)) {
|
||||
$expiryDate = date('Y-m-d', strtotime($expRaw));
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Find or insert into mst_items (shared drug catalog)
|
||||
$itemRow = $this->db->table('mst_items')->where('item_name', $name)->get()->getRowArray();
|
||||
if ($itemRow) {
|
||||
$itemId = (int)$itemRow['item_id'];
|
||||
} else {
|
||||
$this->db->table('mst_items')->insert([
|
||||
'item_name' => $name,
|
||||
'generic_name' => $generic,
|
||||
'category' => $cat ?: 'Tablet',
|
||||
'hsn_code' => $hsn ?: '3004',
|
||||
'gst_rate' => $gst ?: 12,
|
||||
'unit_pack' => $pack ?: '10 Tablets',
|
||||
'barcode' => $barcode,
|
||||
'drug_schedule' => 'Schedule H',
|
||||
'manufacturer_name' => 'Imported Catalog'
|
||||
]);
|
||||
$itemId = $this->db->insertID();
|
||||
$newItems++;
|
||||
}
|
||||
|
||||
// 2. Find or insert into mst_batches for this store
|
||||
$batchRow = $this->db->table('mst_batches')
|
||||
->where('store_id', $storeId)
|
||||
->where('item_id', $itemId)
|
||||
->where('batch_no', $batchNo)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($batchRow) {
|
||||
$batchId = (int)$batchRow['batch_id'];
|
||||
$this->db->table('mst_batches')->where('batch_id', $batchId)->update([
|
||||
'expiry_date' => $expiryDate,
|
||||
'mrp' => $mrp,
|
||||
'ptr' => $ptr,
|
||||
'purchase_rate_net' => $ptr * (1 + $gst / 100),
|
||||
'gst_rate' => $gst
|
||||
]);
|
||||
} else {
|
||||
$this->db->table('mst_batches')->insert([
|
||||
'store_id' => $storeId,
|
||||
'item_id' => $itemId,
|
||||
'batch_no' => $batchNo,
|
||||
'mfg_date' => date('Y-01-01'),
|
||||
'expiry_date' => $expiryDate,
|
||||
'mrp' => $mrp,
|
||||
'ptr' => $ptr,
|
||||
'purchase_rate_net' => $ptr * (1 + $gst / 100),
|
||||
'gst_rate' => $gst,
|
||||
'barcode' => $barcode
|
||||
]);
|
||||
$batchId = $this->db->insertID();
|
||||
$newBatches++;
|
||||
}
|
||||
|
||||
// 3. Update stock in mst_stock
|
||||
$stockRow = $this->db->table('mst_stock')
|
||||
->where('store_id', $storeId)
|
||||
->where('item_id', $itemId)
|
||||
->where('batch_id', $batchId)
|
||||
->get()
|
||||
->getRowArray();
|
||||
|
||||
if ($stockRow) {
|
||||
$this->db->table('mst_stock')->where('stock_id', $stockRow['stock_id'])->update([
|
||||
'current_qty' => $stockRow['current_qty'] + $qty
|
||||
]);
|
||||
} else {
|
||||
$this->db->table('mst_stock')->insert([
|
||||
'store_id' => $storeId,
|
||||
'item_id' => $itemId,
|
||||
'batch_id' => $batchId,
|
||||
'current_qty' => $qty
|
||||
]);
|
||||
}
|
||||
|
||||
$lineVal = $qty * $ptr;
|
||||
$totalValuation += $lineVal;
|
||||
$importedRows++;
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
|
||||
// Record opening stock valuation journal voucher in double-entry ledgers
|
||||
if ($totalValuation > 0) {
|
||||
$voucherNo = 'MARG-IMP-' . $storeId . '-' . date('YmdHis');
|
||||
$stockHead = $this->db->table('mst_account_heads')->where('head_code', '1003')->get()->getRowArray();
|
||||
$equityHead = $this->db->table('mst_account_heads')->where('head_code', '3004')->get()->getRowArray();
|
||||
|
||||
if ($stockHead && $equityHead) {
|
||||
$this->db->table('mst_ledger_entries')->insert([
|
||||
'store_id' => $storeId, 'voucher_no' => $voucherNo, 'voucher_type' => 'OPENING_STOCK', 'voucher_date' => date('Y-m-d'),
|
||||
'account_head_id' => $stockHead['head_id'], 'debit_amount' => $totalValuation, 'credit_amount' => 0,
|
||||
'narration' => "Marg ERP Opening Stock Inward ($importedRows lines)"
|
||||
]);
|
||||
$this->db->table('mst_ledger_entries')->insert([
|
||||
'store_id' => $storeId, 'voucher_no' => $voucherNo, 'voucher_type' => 'OPENING_STOCK', 'voucher_date' => date('Y-m-d'),
|
||||
'account_head_id' => $equityHead['head_id'], 'debit_amount' => 0, 'credit_amount' => $totalValuation,
|
||||
'narration' => "Marg ERP Opening Capital Credit"
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
return $this->response->setJSON([
|
||||
'ok' => true,
|
||||
'message' => "Successfully imported {$importedRows} inventory lines from Marg Pharmacy file.",
|
||||
'details' => [
|
||||
'imported_rows' => $importedRows,
|
||||
'new_catalog_items'=> $newItems,
|
||||
'new_batches' => $newBatches,
|
||||
'total_valuation' => round($totalValuation, 2)
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -3797,4 +3797,233 @@ class FhirR4Builder
|
|||
'asNeeded' => false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build ABDM FHIR R4 MedicationDispense Document Bundle
|
||||
*
|
||||
* @param array<string, mixed> $patient
|
||||
* @param array<string, mixed> $store
|
||||
* @param array<string, mixed> $sale
|
||||
* @param array<int, array<string, mixed>> $items
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function buildPharmacyDispenseBundle(array $patient, array $store, array $sale, array $items): array
|
||||
{
|
||||
$issuedAt = $this->isoTimestamp();
|
||||
$bundleUuid = $this->generateUuid();
|
||||
$compositionUuid = $this->generateUuid();
|
||||
$patientUuid = $this->generateUuid();
|
||||
$practitionerUuid = $this->generateUuid();
|
||||
$organizationUuid = $this->generateUuid();
|
||||
|
||||
$patientRef = 'urn:uuid:' . $patientUuid;
|
||||
$practitionerRef = 'urn:uuid:' . $practitionerUuid;
|
||||
$organizationRef = 'urn:uuid:' . $organizationUuid;
|
||||
|
||||
$resourceEntries = [];
|
||||
|
||||
// 1. Practitioner (Pharmacist or Prescribing Doctor)
|
||||
$practName = trim((string)(($sale['doctor_name'] ?? '') ?: (($store['registered_pharmacist_name'] ?? '') ?: 'Pharmacist')));
|
||||
$practRegNo = trim((string)(($sale['doctor_reg_no'] ?? '') ?: (($store['pharmacist_reg_no'] ?? '') ?: '')));
|
||||
$practHprId = trim((string)($store['pharmacist_hpr_id'] ?? ''));
|
||||
|
||||
$practIdentifiers = [];
|
||||
if ($practHprId !== '') {
|
||||
$practIdentifiers[] = [
|
||||
'type' => ['coding' => [['system' => 'http://terminology.hl7.org/CodeSystem/v2-0203', 'code' => 'PRN', 'display' => 'Provider number']]],
|
||||
'system' => 'https://hpr.abdm.gov.in',
|
||||
'value' => $practHprId
|
||||
];
|
||||
}
|
||||
if ($practRegNo !== '') {
|
||||
$practIdentifiers[] = [
|
||||
'type' => ['coding' => [['system' => 'http://terminology.hl7.org/CodeSystem/v2-0203', 'code' => 'MD', 'display' => 'Medical License number']]],
|
||||
'system' => 'https://doctor.ndhm.gov.in',
|
||||
'value' => $practRegNo
|
||||
];
|
||||
}
|
||||
|
||||
$resourceEntries[] = [
|
||||
'fullUrl' => $practitionerRef,
|
||||
'resource' => [
|
||||
'resourceType' => 'Practitioner',
|
||||
'id' => $practitionerUuid,
|
||||
'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/Practitioner']],
|
||||
'identifier' => $practIdentifiers,
|
||||
'name' => [['text' => $practName]]
|
||||
]
|
||||
];
|
||||
|
||||
// 2. Organization (Hospital Pharmacy / Store)
|
||||
$hfrId = trim((string)(($store['abdm_hfr_id'] ?? '') ?: (($store['store_code'] ?? '') ?: 'IN0710001234')));
|
||||
$resourceEntries[] = [
|
||||
'fullUrl' => $organizationRef,
|
||||
'resource' => [
|
||||
'resourceType' => 'Organization',
|
||||
'id' => $organizationUuid,
|
||||
'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/Organization']],
|
||||
'identifier' => [[
|
||||
'type' => ['coding' => [['system' => 'http://terminology.hl7.org/CodeSystem/v2-0203', 'code' => 'PRN', 'display' => 'Provider number']]],
|
||||
'system' => 'https://facility.ndhm.gov.in',
|
||||
'value' => $hfrId
|
||||
]],
|
||||
'name' => (string)(($store['store_name'] ?? '') ?: 'Hospital Medical Store'),
|
||||
'telecom' => [
|
||||
['system' => 'phone', 'value' => (string)(($store['contact_phone'] ?? '') ?: '+91 9999999999')],
|
||||
['system' => 'email', 'value' => (string)(($store['contact_email'] ?? '') ?: 'pharmacy@hospital.in')]
|
||||
],
|
||||
'address' => [[
|
||||
'line' => [(string)(($store['address'] ?? '') ?: 'Hospital Building')],
|
||||
'city' => (string)(($store['state_name'] ?? '') ?: 'Delhi'),
|
||||
'state' => (string)(($store['state_name'] ?? '') ?: 'Delhi'),
|
||||
'postalCode' => '110001',
|
||||
'country' => 'IN'
|
||||
]]
|
||||
]
|
||||
];
|
||||
|
||||
// 3. Patient
|
||||
$patientResource = $this->buildPatientResource($patient);
|
||||
$patientResource['id'] = $patientUuid;
|
||||
// Inject ABHA identifiers if provided in sale or patient
|
||||
$abhaNumber = trim((string)(($sale['abha_id'] ?? '') ?: ($patient['abha_id'] ?? '')));
|
||||
$abhaAddress = trim((string)(($sale['abha_address'] ?? '') ?: ($patient['abha_address'] ?? '')));
|
||||
|
||||
if (!isset($patientResource['identifier'])) {
|
||||
$patientResource['identifier'] = [];
|
||||
}
|
||||
if ($abhaNumber !== '') {
|
||||
$patientResource['identifier'][] = [
|
||||
'type' => ['coding' => [['system' => 'https://nrces.in/ndhm/fhir/r4/CodeSystem/ndhm-identifier-type-code', 'code' => 'ABHA', 'display' => 'Ayushman Bharat Health Account']]],
|
||||
'system' => 'https://healthid.ndhm.gov.in',
|
||||
'value' => $abhaNumber
|
||||
];
|
||||
}
|
||||
if ($abhaAddress !== '') {
|
||||
$patientResource['identifier'][] = [
|
||||
'type' => ['coding' => [['system' => 'https://nrces.in/ndhm/fhir/r4/CodeSystem/ndhm-identifier-type-code', 'code' => 'ABHA-ADDRESS', 'display' => 'ABHA Address']]],
|
||||
'system' => 'https://abdm.gov.in',
|
||||
'value' => $abhaAddress
|
||||
];
|
||||
}
|
||||
$resourceEntries[] = ['fullUrl' => $patientRef, 'resource' => $patientResource];
|
||||
|
||||
// 4. MedicationDispense Resources
|
||||
$medicationRefs = [];
|
||||
foreach ($items as $idx => $it) {
|
||||
$medUuid = $this->generateUuid();
|
||||
$medRef = 'urn:uuid:' . $medUuid;
|
||||
$medicationRefs[] = ['reference' => $medRef];
|
||||
|
||||
$snomedCode = trim((string)($it['snomed_ct_code'] ?? ''));
|
||||
$snomedDisplay = trim((string)($it['snomed_display'] ?? ($it['item_name'] ?? 'Medicine')));
|
||||
|
||||
$coding = [];
|
||||
if ($snomedCode !== '') {
|
||||
$coding[] = [
|
||||
'system' => 'http://snomed.info/sct',
|
||||
'code' => $snomedCode,
|
||||
'display' => $snomedDisplay
|
||||
];
|
||||
}
|
||||
|
||||
$medResource = [
|
||||
'resourceType' => 'MedicationDispense',
|
||||
'id' => $medUuid,
|
||||
'meta' => ['profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/MedicationDispense']],
|
||||
'status' => 'completed',
|
||||
'medicationCodeableConcept' => [
|
||||
'coding' => $coding,
|
||||
'text' => (string)($it['item_name'] ?? 'Medicine')
|
||||
],
|
||||
'subject' => ['reference' => $patientRef, 'display' => (string)(($sale['patient_name'] ?? '') ?: 'Patient')],
|
||||
'performer' => [[
|
||||
'actor' => ['reference' => $practitionerRef, 'display' => $practName]
|
||||
]],
|
||||
'location' => ['reference' => $organizationRef, 'display' => (string)(($store['store_name'] ?? '') ?: 'Pharmacy')],
|
||||
'quantity' => [
|
||||
'value' => (int)($it['qty'] ?? 1),
|
||||
'unit' => (string)($it['unit_pack'] ?? 'Units'),
|
||||
'system' => 'http://unitsofmeasure.org',
|
||||
'code' => '1'
|
||||
],
|
||||
'daysSupply' => [
|
||||
'value' => 5,
|
||||
'unit' => 'days',
|
||||
'system' => 'http://unitsofmeasure.org',
|
||||
'code' => 'd'
|
||||
],
|
||||
'whenPrepared' => $issuedAt,
|
||||
'whenHandedOver' => $issuedAt,
|
||||
'dosageInstruction' => [[
|
||||
'text' => 'As directed by physician'
|
||||
]]
|
||||
];
|
||||
|
||||
$resourceEntries[] = ['fullUrl' => $medRef, 'resource' => $medResource];
|
||||
}
|
||||
|
||||
// 5. Composition (Record Head)
|
||||
$compositionResource = [
|
||||
'resourceType' => 'Composition',
|
||||
'id' => $compositionUuid,
|
||||
'meta' => [
|
||||
'profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/MedicationDispenseDocument'],
|
||||
'versionId' => '1',
|
||||
'lastUpdated' => $issuedAt
|
||||
],
|
||||
'language' => 'en-IN',
|
||||
'identifier' => [
|
||||
'system' => 'https://ndhm.in/phr',
|
||||
'value' => (string)(($sale['abdm_care_context_ref'] ?? '') ?: ('PHARM-' . (($sale['invoice_no'] ?? '') ?: $compositionUuid)))
|
||||
],
|
||||
'status' => 'final',
|
||||
'type' => [
|
||||
'coding' => [[
|
||||
'system' => 'http://loinc.org',
|
||||
'code' => '60590-7',
|
||||
'display' => 'Medication dispensed.extended Document'
|
||||
]],
|
||||
'text' => 'Pharmacy Medication Dispense Record'
|
||||
],
|
||||
'subject' => ['reference' => $patientRef, 'display' => (string)(($sale['patient_name'] ?? '') ?: 'Patient')],
|
||||
'date' => $issuedAt,
|
||||
'author' => [['reference' => $practitionerRef, 'display' => $practName]],
|
||||
'title' => 'Pharmacy Medication Dispensation Receipt',
|
||||
'custodian' => ['reference' => $organizationRef, 'display' => (string)(($store['store_name'] ?? '') ?: 'Hospital Pharmacy')],
|
||||
'section' => [[
|
||||
'title' => 'Medications Dispensed',
|
||||
'code' => [
|
||||
'coding' => [[
|
||||
'system' => 'http://loinc.org',
|
||||
'code' => '10160-0',
|
||||
'display' => 'History of Medication use'
|
||||
]]
|
||||
],
|
||||
'entry' => $medicationRefs
|
||||
]]
|
||||
];
|
||||
|
||||
array_unshift($resourceEntries, [
|
||||
'fullUrl' => 'urn:uuid:' . $compositionUuid,
|
||||
'resource' => $compositionResource
|
||||
]);
|
||||
|
||||
return [
|
||||
'resourceType' => 'Bundle',
|
||||
'id' => $bundleUuid,
|
||||
'meta' => [
|
||||
'versionId' => '1',
|
||||
'lastUpdated' => $issuedAt,
|
||||
'profile' => ['https://nrces.in/ndhm/fhir/r4/StructureDefinition/DocumentBundle']
|
||||
],
|
||||
'identifier' => [
|
||||
'system' => 'https://ndhm.in/phr',
|
||||
'value' => $bundleUuid
|
||||
],
|
||||
'type' => 'document',
|
||||
'timestamp' => $issuedAt,
|
||||
'entry' => $resourceEntries
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,13 @@
|
|||
<span>Nursing Station Master</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 col-md-2 col-lg-2">
|
||||
<a class="admin-tile" href="javascript:openAdminSubPage('<?= base_url('setting/admin/medical-store') ?>','Medical Stores & POS Setup');">
|
||||
<i class="bi bi-capsule" style="color:#0891b2"></i>
|
||||
<span>Medical Stores & Counters</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="col-6 col-md-2 col-lg-2">
|
||||
<a class="admin-tile" href="javascript:openAdminSubPage('<?= base_url('setting/admin/user-management') ?>','User Management');">
|
||||
<i class="bi bi-people"></i>
|
||||
|
|
|
|||
686
app/Views/Setting/MedicalStore/medical_store_index.php
Normal file
686
app/Views/Setting/MedicalStore/medical_store_index.php
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
<div class="container-fluid p-0">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div>
|
||||
<h5 class="text-primary mb-0"><i class="bi bi-capsule me-1"></i> Medical Stores & Pharmacy Counters Master</h5>
|
||||
<small class="text-muted">Manage hospital building stores, Indian Drug Licenses (20B/21B), GSTIN, direct URLs, and machine terminal security</small>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" class="btn btn-outline-success btn-sm" id="btn_open_marg_import">
|
||||
<i class="bi bi-file-earmark-arrow-up me-1"></i> Marg ERP / Excel Import
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="btn_add_store">
|
||||
<i class="bi bi-plus-lg me-1"></i> Add Medical Store
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Card -->
|
||||
<div class="card shadow-sm border-0 mb-3">
|
||||
<div class="card-body py-2 px-3">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-md-9">
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text bg-light border-end-0"><i class="bi bi-search text-muted"></i></span>
|
||||
<input type="text" class="form-control border-start-0" id="store_search_input" placeholder="Search by store name, code, slug, building, DL 20B, GSTIN..." value="<?= esc($searchQuery ?? '') ?>">
|
||||
<button class="btn btn-primary" type="button" id="btn_store_search">Search</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" id="btn_refresh_store_list">
|
||||
<i class="bi bi-arrow-clockwise me-1"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stores Table -->
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0" id="stores_table">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width: 40px;" class="ps-3">#</th>
|
||||
<th>Store Name & Building</th>
|
||||
<th>Direct Counter Link (URL)</th>
|
||||
<th>Drug Licenses (20B / 21B)</th>
|
||||
<th>GSTIN & State</th>
|
||||
<th>Pharmacist</th>
|
||||
<th>Terminal Security</th>
|
||||
<th style="width: 130px;" class="text-end pe-3">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($stores)): ?>
|
||||
<tr>
|
||||
<td colspan="8" class="text-center py-4 text-muted">
|
||||
<i class="bi bi-hospital fs-3 d-block mb-1"></i>
|
||||
No medical stores found. Click <strong>"Add Medical Store"</strong> to create a new pharmacy counter.
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($stores as $idx => $st): ?>
|
||||
<?php
|
||||
$directUrl = base_url('MedicalStore/' . ($st['store_slug'] ?: $st['store_code']));
|
||||
?>
|
||||
<tr>
|
||||
<td class="ps-3 fw-bold text-secondary"><?= $idx + 1 ?></td>
|
||||
<td>
|
||||
<div class="fw-bold text-dark fs-6"><?= esc($st['store_name']) ?></div>
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-geo-alt me-1"></i><?= esc($st['building_name'] ?: 'Main Block') ?> • <?= esc($st['floor_no'] ?: 'Ground Floor') ?>
|
||||
<?php if ($st['is_main_store']): ?>
|
||||
<span class="badge bg-primary-subtle text-primary border border-primary px-1.5 py-0.5 ms-1">CENTRAL STORE</span>
|
||||
<?php endif; ?>
|
||||
</small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center gap-1">
|
||||
<code class="text-primary fw-bold" style="font-size: 11px;">MedicalStore/<?= esc($st['store_slug']) ?></code>
|
||||
<button type="button" class="btn btn-sm btn-light py-0 px-1 border" title="Copy Direct URL Link" onclick="copyText('<?= esc($directUrl) ?>')">
|
||||
<i class="bi bi-copy text-muted" style="font-size: 11px;"></i>
|
||||
</button>
|
||||
<a href="<?= esc($directUrl) ?>" target="_blank" class="btn btn-sm btn-outline-primary py-0 px-1" title="Open Counter POS">
|
||||
<i class="bi bi-box-arrow-up-right" style="font-size: 11px;"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small"><strong>20B:</strong> <?= esc($st['drug_license_no_20b'] ?: 'N/A') ?></div>
|
||||
<div class="small"><strong>21B:</strong> <?= esc($st['drug_license_no_21b'] ?: 'N/A') ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<div><code class="text-success fw-bold"><?= esc($st['gstin'] ?: 'N/A') ?></code></div>
|
||||
<small class="text-muted d-block">State: <?= esc($st['state_code']) ?> (<?= esc($st['state_name']) ?>)</small>
|
||||
<?php if (!empty($st['abdm_hfr_id'])): ?>
|
||||
<span class="badge bg-primary-subtle text-primary border border-primary-subtle mt-0.5" style="font-size: 10px;" title="ABDM Health Facility Registry">
|
||||
<i class="bi bi-shield-check me-0.5"></i> HFR: <?= esc($st['abdm_hfr_id']) ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small fw-semibold"><?= esc($st['registered_pharmacist_name'] ?: 'Not Assigned') ?></div>
|
||||
<small class="text-muted"><?= esc($st['pharmacist_reg_no'] ?: '') ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-outline-info py-0.5 px-2" onclick="openTerminalSecurityModal(<?= htmlspecialchars(json_encode($st), ENT_QUOTES, 'UTF-8') ?>)">
|
||||
<i class="bi bi-shield-lock-fill me-1"></i> Key & OTP
|
||||
<span class="badge bg-secondary ms-1"><?= (int)$st['authorized_devices_count'] ?> PCs</span>
|
||||
</button>
|
||||
</td>
|
||||
<td class="text-end pe-3">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm py-0.5 px-2" onclick="editStoreModal(<?= htmlspecialchars(json_encode($st), ENT_QUOTES, 'UTF-8') ?>)">
|
||||
<i class="bi bi-pencil-square"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm py-0.5 px-2 ms-1" onclick="deleteStore(<?= (int)$st['store_id'] ?>, '<?= esc($st['store_name']) ?>')">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Authorized Terminals / Machines Section -->
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-header bg-white py-2.5 px-3 d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0 fw-bold text-dark"><i class="bi bi-display me-1 text-primary"></i> Authorized Computer Terminals & Machines</h6>
|
||||
<small class="text-muted">Protected counter computers verified via HMS Admin Security Key or OTP</small>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0" style="font-size: 12px;">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="ps-3">Machine / Computer Name</th>
|
||||
<th>Medical Store</th>
|
||||
<th>IP Address</th>
|
||||
<th>Verified Method</th>
|
||||
<th>Authorized Date</th>
|
||||
<th>Status</th>
|
||||
<th class="text-end pe-3">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($devices)): ?>
|
||||
<tr>
|
||||
<td colSpan="7" class="text-center py-3 text-muted">
|
||||
No machine terminals registered yet. Open a store link on a counter PC and verify using the Security Key or OTP.
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($devices as $d): ?>
|
||||
<tr>
|
||||
<td class="ps-3 fw-bold">
|
||||
<i class="bi bi-pc-display me-1 text-primary"></i> <?= esc($d['machine_name']) ?>
|
||||
</td>
|
||||
<td><?= esc($d['store_name']) ?></td>
|
||||
<td><code><?= esc($d['ip_address'] ?: 'Localhost') ?></code></td>
|
||||
<td><span class="badge bg-light text-dark border"><?= esc($d['verified_by_method']) ?></span></td>
|
||||
<td><?= esc(date('d-m-Y h:i A', strtotime($d['authorized_at']))) ?></td>
|
||||
<td>
|
||||
<?php if ($d['status'] === 'authorized'): ?>
|
||||
<span class="badge bg-success">Active Authorized</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">Access Revoked</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="text-end pe-3">
|
||||
<?php if ($d['status'] === 'authorized'): ?>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm py-0 px-2" onclick="revokeTerminal(<?= (int)$d['device_id'] ?>)">
|
||||
<i class="bi bi-slash-circle me-1"></i> Revoke
|
||||
</button>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">Revoked</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal 1: Add / Edit Medical Store -->
|
||||
<div class="modal fade" id="storeModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-primary text-white py-2.5">
|
||||
<h6 class="modal-title fw-bold" id="storeModalTitle"><i class="bi bi-capsule me-1"></i> Add Medical Store Counter</h6>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form id="storeForm">
|
||||
<input type="hidden" name="store_id" id="form_store_id" value="0">
|
||||
<div class="modal-body p-3">
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Store Code <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" name="store_code" id="form_store_code" placeholder="e.g. ST-OPD-1" required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Unique URL Link Slug <span class="text-danger">*</span></label>
|
||||
<div class="input-group input-group-sm">
|
||||
<span class="input-group-text bg-light" style="font-size: 11px;">/MedicalStore/</span>
|
||||
<input type="text" class="form-control form-control-sm" name="store_slug" id="form_store_slug" placeholder="storeA" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Is Central Warehouse?</label>
|
||||
<select class="form-select form-select-sm" name="is_main_store" id="form_is_main_store">
|
||||
<option value="0">Sub-Counter / Building Store</option>
|
||||
<option value="1">Central Main Pharmacy</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label small fw-bold mb-1">Medical Store Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" name="store_name" id="form_store_name" placeholder="e.g. Apollo City Medicos - OPD Counter" required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Building Name</label>
|
||||
<input type="text" class="form-control form-control-sm" name="building_name" id="form_building_name" placeholder="e.g. OPD Block B">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Floor</label>
|
||||
<input type="text" class="form-control form-control-sm" name="floor_no" id="form_floor_no" placeholder="e.g. 1st Floor">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Counter / Room No</label>
|
||||
<input type="text" class="form-control form-control-sm" name="room_no" id="form_room_no" placeholder="e.g. Counter 2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 class="fw-bold text-primary mt-3 mb-2" style="font-size: 13px;"><i class="bi bi-shield-check me-1"></i> Indian Statutory Drug Licenses & GST</h6>
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Drug License Form 20-B (Allopathic)</label>
|
||||
<input type="text" class="form-control form-control-sm" name="drug_license_no_20b" id="form_dl_20b" placeholder="DL-20B-DEL-XXXXX">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Drug License Form 21-B (Schedule C/C1)</label>
|
||||
<input type="text" class="form-control form-control-sm" name="drug_license_no_21b" id="form_dl_21b" placeholder="DL-21B-DEL-XXXXX">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Drug License Form 20-F (Schedule X)</label>
|
||||
<input type="text" class="form-control form-control-sm" name="drug_license_no_20f_x" id="form_dl_20f" placeholder="DL-20F-DEL-XXXXX">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">GSTIN (15-digit)</label>
|
||||
<input type="text" class="form-control form-control-sm text-uppercase" name="gstin" id="form_gstin" placeholder="07AAAAA0000A1Z5">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">PAN Number</label>
|
||||
<input type="text" class="form-control form-control-sm text-uppercase" name="pan_no" id="form_pan" placeholder="AAAAA0000A">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">FSSAI License No</label>
|
||||
<input type="text" class="form-control form-control-sm" name="fssai_no" id="form_fssai" placeholder="100XXXXXXXXXX">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small fw-bold mb-1">State Code (GST)</label>
|
||||
<input type="text" class="form-control form-control-sm" name="state_code" id="form_state_code" placeholder="07" value="07">
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<label class="form-label small fw-bold mb-1">State Name</label>
|
||||
<input type="text" class="form-control form-control-sm" name="state_name" id="form_state_name" placeholder="Delhi" value="Delhi">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 class="fw-bold text-primary mt-3 mb-2" style="font-size: 13px;"><i class="bi bi-shield-check me-1"></i> ABDM (Ayushman Bharat Digital Mission) Registration</h6>
|
||||
<div class="row g-2">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">ABDM HFR Facility ID</label>
|
||||
<input type="text" class="form-control form-control-sm" name="abdm_hfr_id" id="form_abdm_hfr_id" placeholder="e.g. IN0710001234">
|
||||
<div class="form-text" style="font-size: 10px;">Health Facility Registry ID</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">ABDM HIP ID</label>
|
||||
<input type="text" class="form-control form-control-sm" name="abdm_hip_id" id="form_abdm_hip_id" placeholder="e.g. HIP-CITYHOSP-01">
|
||||
<div class="form-text" style="font-size: 10px;">Health Information Provider ID</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Pharmacist ABDM HPR ID</label>
|
||||
<input type="text" class="form-control form-control-sm" name="pharmacist_hpr_id" id="form_pharmacist_hpr_id" placeholder="e.g. 91-XXXX-XXXX-XXXX">
|
||||
<div class="form-text" style="font-size: 10px;">Healthcare Professional Registry ID</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 class="fw-bold text-primary mt-3 mb-2" style="font-size: 13px;"><i class="bi bi-person-badge me-1"></i> Pharmacist & POS Bill Configuration</h6>
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold mb-1">Registered Pharmacist Name</label>
|
||||
<input type="text" class="form-control form-control-sm" name="registered_pharmacist_name" id="form_pharmacist_name" placeholder="Pharmacist Full Name">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold mb-1">State Pharmacy Council Reg No</label>
|
||||
<input type="text" class="form-control form-control-sm" name="pharmacist_reg_no" id="form_pharmacist_reg_no" placeholder="e.g. DPC-Reg-45892">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Bill Series Prefix</label>
|
||||
<input type="text" class="form-control form-control-sm" name="invoice_prefix" id="form_invoice_prefix" placeholder="OPD1/26-27/">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Next Sequence No</label>
|
||||
<input type="number" class="form-control form-control-sm" name="next_invoice_no" id="form_next_invoice_no" value="1001">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Store UPI VPA (for QR Code)</label>
|
||||
<input type="text" class="form-control form-control-sm" name="upi_id" id="form_upi_id" placeholder="hospital@upi">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label small fw-bold mb-1">Terms & Conditions (Printed on Invoice)</label>
|
||||
<textarea class="form-control form-control-sm" name="terms_conditions" id="form_terms" rows="2" placeholder="Goods once sold returnable within 7 days with bill. Store below 25°C."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 class="fw-bold text-primary mt-3 mb-2" style="font-size: 13px;"><i class="bi bi-geo-alt me-1"></i> Store Contact & Physical Address</h6>
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold mb-1">Contact Phone / Mobile</label>
|
||||
<input type="text" class="form-control form-control-sm" name="contact_phone" id="form_contact_phone" placeholder="e.g. +91 98765 43210">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small fw-bold mb-1">Contact Email</label>
|
||||
<input type="email" class="form-control form-control-sm" name="contact_email" id="form_contact_email" placeholder="pharmacy@hospital.com">
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<label class="form-label small fw-bold mb-1">Store / Counter Physical Address</label>
|
||||
<textarea class="form-control form-control-sm" name="address" id="form_address" rows="2" placeholder="Full address of the hospital pharmacy counter..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 class="fw-bold text-primary mt-3 mb-2" style="font-size: 13px;"><i class="bi bi-bank me-1"></i> Bank Account Details (for Statement Reconciliation & Invoices)</h6>
|
||||
<div class="row g-2">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Bank Name</label>
|
||||
<input type="text" class="form-control form-control-sm" name="bank_name" id="form_bank_name" placeholder="e.g. State Bank of India">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Bank Account Number</label>
|
||||
<input type="text" class="form-control form-control-sm" name="bank_account_no" id="form_bank_account_no" placeholder="e.g. 10293847561">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label small fw-bold mb-1">Bank IFSC Code</label>
|
||||
<input type="text" class="form-control form-control-sm text-uppercase" name="bank_ifsc" id="form_bank_ifsc" placeholder="e.g. SBIN0001234">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer py-2 px-3 bg-light">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm" id="btn_save_store">
|
||||
<i class="bi bi-check-circle me-1"></i> Save Medical Store
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal 2: Terminal Verification & Computer Security Keys -->
|
||||
<div class="modal fade" id="terminalSecurityModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-dark text-white py-2.5">
|
||||
<h6 class="modal-title fw-bold"><i class="bi bi-shield-lock me-1 text-warning"></i> Computer Machine Verification</h6>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-3">
|
||||
<div class="alert alert-info py-2 mb-3" style="font-size: 12px;">
|
||||
<i class="bi bi-info-circle me-1"></i> When opening the store link on a counter PC for the first time, staff must enter either the permanent <strong>Security Key</strong> or an <strong>Activation OTP</strong>.
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold text-muted mb-1">Permanent Machine Security Key</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control fw-bold text-primary font-monospace" id="modal_sec_key" readonly>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="copyText(document.getElementById('modal_sec_key').value)">
|
||||
<i class="bi bi-copy"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-warning" type="button" id="btn_regen_key" title="Regenerate Security Key">
|
||||
<i class="bi bi-arrow-repeat"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 p-3 bg-light rounded-3 border">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label class="form-label small fw-bold mb-0">6-Digit Counter Activation OTP</label>
|
||||
<button type="button" class="btn btn-primary btn-sm py-0.5 px-2" id="btn_generate_otp">
|
||||
<i class="bi bi-key-fill me-1"></i> Generate New OTP
|
||||
</button>
|
||||
</div>
|
||||
<div id="otp_display_box" style="display: none;">
|
||||
<div class="display-6 fw-bold text-success text-center letter-spacing-2" id="otp_code_val" style="letter-spacing: 6px;">
|
||||
------
|
||||
</div>
|
||||
<small class="text-muted d-block text-center mt-1" id="otp_expiry_val"></small>
|
||||
</div>
|
||||
<small class="text-muted d-block" id="otp_idle_text">
|
||||
Click "Generate New OTP" to generate an emergency 60-minute activation PIN for this store.
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer py-2 bg-light">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal 3: Marg ERP / Excel Inventory Import -->
|
||||
<div class="modal fade" id="margImportModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-0 shadow">
|
||||
<div class="modal-header bg-success text-white py-2.5">
|
||||
<h6 class="modal-title fw-bold"><i class="bi bi-file-earmark-arrow-up me-1"></i> Marg ERP / Excel Inventory Import</h6>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form id="margImportForm" enctype="multipart/form-data">
|
||||
<div class="modal-body p-3">
|
||||
<p class="small text-muted mb-3">
|
||||
Quickly migrate stock from <strong>Marg Pharmacy Software</strong> or Microsoft Excel into the store's shared master catalog and batch stock.
|
||||
</p>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold mb-1">Target Medical Store Counter <span class="text-danger">*</span></label>
|
||||
<select class="form-select form-select-sm" name="store_id" id="marg_store_id" required>
|
||||
<?php foreach ($stores as $st): ?>
|
||||
<option value="<?= (int)$st['store_id'] ?>"><?= esc($st['store_name']) ?> (<?= esc($st['building_name'] ?: 'Building') ?>)</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold mb-1">Upload CSV / Excel Export <span class="text-danger">*</span></label>
|
||||
<input type="file" class="form-control form-control-sm" name="import_file" id="marg_file" accept=".csv, .txt" required>
|
||||
<small class="text-muted" style="font-size: 11px;">
|
||||
Supported columns: Item Name, Generic, Batch No, Expiry (MM/YY), MRP, PTR/Cost, HSN, GST%, Opening Qty.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-light border py-2 mb-0" style="font-size: 11px;">
|
||||
<i class="bi bi-download text-primary me-1"></i>
|
||||
<a href="javascript:downloadSampleMargCsv()" class="text-decoration-none fw-bold">Download Sample Marg CSV Template</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer py-2 bg-light">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-success btn-sm" id="btn_submit_marg">
|
||||
<i class="bi bi-upload me-1"></i> Start Import
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var activeStoreObj = null;
|
||||
|
||||
function copyText(text) {
|
||||
navigator.clipboard.writeText(text).then(function() {
|
||||
alert('Copied to clipboard: ' + text);
|
||||
});
|
||||
}
|
||||
|
||||
function openTerminalSecurityModal(store) {
|
||||
activeStoreObj = store;
|
||||
document.getElementById('modal_sec_key').value = store.security_key || '';
|
||||
document.getElementById('otp_display_box').style.display = 'none';
|
||||
document.getElementById('otp_idle_text').style.display = 'block';
|
||||
|
||||
var modal = new bootstrap.Modal(document.getElementById('terminalSecurityModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
function editStoreModal(store) {
|
||||
document.getElementById('storeModalTitle').innerHTML = '<i class="bi bi-pencil-square me-1"></i> Edit Medical Store: ' + store.store_name;
|
||||
document.getElementById('form_store_id').value = store.store_id;
|
||||
document.getElementById('form_store_code').value = store.store_code || '';
|
||||
document.getElementById('form_store_slug').value = store.store_slug || '';
|
||||
document.getElementById('form_store_name').value = store.store_name || '';
|
||||
document.getElementById('form_building_name').value = store.building_name || '';
|
||||
document.getElementById('form_floor_no').value = store.floor_no || '';
|
||||
document.getElementById('form_room_no').value = store.room_no || '';
|
||||
document.getElementById('form_is_main_store').value = store.is_main_store || 0;
|
||||
document.getElementById('form_dl_20b').value = store.drug_license_no_20b || '';
|
||||
document.getElementById('form_dl_21b').value = store.drug_license_no_21b || '';
|
||||
document.getElementById('form_dl_20f').value = store.drug_license_no_20f_x || '';
|
||||
document.getElementById('form_gstin').value = store.gstin || '';
|
||||
document.getElementById('form_pan').value = store.pan_no || '';
|
||||
document.getElementById('form_fssai').value = store.fssai_no || '';
|
||||
document.getElementById('form_state_code').value = store.state_code || '07';
|
||||
document.getElementById('form_state_name').value = store.state_name || 'Delhi';
|
||||
document.getElementById('form_pharmacist_name').value = store.registered_pharmacist_name || '';
|
||||
document.getElementById('form_pharmacist_reg_no').value = store.pharmacist_reg_no || '';
|
||||
document.getElementById('form_invoice_prefix').value = store.invoice_prefix || 'INV/';
|
||||
document.getElementById('form_next_invoice_no').value = store.next_invoice_no || 1001;
|
||||
document.getElementById('form_abdm_hfr_id').value = store.abdm_hfr_id || '';
|
||||
document.getElementById('form_abdm_hip_id').value = store.abdm_hip_id || '';
|
||||
document.getElementById('form_pharmacist_hpr_id').value = store.pharmacist_hpr_id || '';
|
||||
document.getElementById('form_upi_id').value = store.upi_id || '';
|
||||
document.getElementById('form_terms').value = store.terms_conditions || '';
|
||||
document.getElementById('form_contact_phone').value = store.contact_phone || '';
|
||||
document.getElementById('form_contact_email').value = store.contact_email || '';
|
||||
document.getElementById('form_address').value = store.address || '';
|
||||
document.getElementById('form_bank_name').value = store.bank_name || '';
|
||||
document.getElementById('form_bank_account_no').value = store.bank_account_no || '';
|
||||
document.getElementById('form_bank_ifsc').value = store.bank_ifsc || '';
|
||||
|
||||
var modal = new bootstrap.Modal(document.getElementById('storeModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
document.getElementById('btn_add_store').addEventListener('click', function() {
|
||||
document.getElementById('storeForm').reset();
|
||||
document.getElementById('storeModalTitle').innerHTML = '<i class="bi bi-capsule me-1"></i> Add New Medical Store Counter';
|
||||
document.getElementById('form_store_id').value = '0';
|
||||
document.getElementById('form_store_code').value = 'ST-' + Math.floor(100 + Math.random() * 900);
|
||||
document.getElementById('form_store_slug').value = 'counter' + Math.floor(1 + Math.random() * 9);
|
||||
var modal = new bootstrap.Modal(document.getElementById('storeModal'));
|
||||
modal.show();
|
||||
});
|
||||
|
||||
document.getElementById('btn_open_marg_import').addEventListener('click', function() {
|
||||
var modal = new bootstrap.Modal(document.getElementById('margImportModal'));
|
||||
modal.show();
|
||||
});
|
||||
|
||||
// Save Store Form
|
||||
$('#storeForm').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
var formData = $(this).serialize();
|
||||
$.ajax({
|
||||
url: '<?= base_url('setting/admin/medical-store/save') ?>',
|
||||
method: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.ok) {
|
||||
alert(res.message);
|
||||
location.reload();
|
||||
} else {
|
||||
alert(res.error || 'Failed to save store');
|
||||
}
|
||||
},
|
||||
error: function(err) {
|
||||
alert('Request error: ' + err.statusText);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Generate OTP
|
||||
$('#btn_generate_otp').on('click', function() {
|
||||
if (!activeStoreObj) return;
|
||||
$.ajax({
|
||||
url: '<?= base_url('setting/admin/medical-store/generate-otp') ?>',
|
||||
method: 'POST',
|
||||
data: { store_id: activeStoreObj.store_id },
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.ok) {
|
||||
document.getElementById('otp_code_val').innerText = res.otp;
|
||||
document.getElementById('otp_expiry_val').innerText = 'Valid until ' + res.expiry;
|
||||
document.getElementById('otp_display_box').style.display = 'block';
|
||||
document.getElementById('otp_idle_text').style.display = 'none';
|
||||
} else {
|
||||
alert(res.error || 'Failed to generate OTP');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Regenerate Security Key
|
||||
$('#btn_regen_key').on('click', function() {
|
||||
if (!activeStoreObj || !confirm('Are you sure you want to regenerate the Security Key?')) return;
|
||||
$.ajax({
|
||||
url: '<?= base_url('setting/admin/medical-store/regenerate-key') ?>',
|
||||
method: 'POST',
|
||||
data: { store_id: activeStoreObj.store_id },
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.ok) {
|
||||
document.getElementById('modal_sec_key').value = res.security_key;
|
||||
alert('Security key updated! Please share this with counter staff.');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Revoke Terminal Access
|
||||
function revokeTerminal(deviceId) {
|
||||
if (!confirm('Are you sure you want to revoke counter access for this computer?')) return;
|
||||
$.ajax({
|
||||
url: '<?= base_url('setting/admin/medical-store/revoke-device') ?>',
|
||||
method: 'POST',
|
||||
data: { device_id: deviceId },
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.ok) {
|
||||
alert(res.message);
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteStore(storeId, storeName) {
|
||||
if (!confirm('Are you sure you want to deactivate store: ' + storeName + '?')) return;
|
||||
$.ajax({
|
||||
url: '<?= base_url('setting/admin/medical-store/delete') ?>',
|
||||
method: 'POST',
|
||||
data: { store_id: storeId },
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.ok) {
|
||||
alert(res.message);
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Marg CSV Import Submit
|
||||
$('#margImportForm').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
var formData = new FormData(this);
|
||||
var btn = $('#btn_submit_marg');
|
||||
btn.prop('disabled', true).text('Importing records...');
|
||||
|
||||
$.ajax({
|
||||
url: '<?= base_url('setting/admin/medical-store/import-marg') ?>',
|
||||
method: 'POST',
|
||||
data: formData,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
btn.prop('disabled', false).html('<i class="bi bi-upload me-1"></i> Start Import');
|
||||
if (res.ok) {
|
||||
alert(res.message);
|
||||
location.reload();
|
||||
} else {
|
||||
alert(res.error || 'Import failed');
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
btn.prop('disabled', false).html('<i class="bi bi-upload me-1"></i> Start Import');
|
||||
alert('Import error occurred');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function downloadSampleMargCsv() {
|
||||
var csvContent = "Item Name,Generic Name,Category,Packing,Batch No,Expiry Date,MRP,PTR,HSN Code,GST Rate,Opening Qty,Barcode\n" +
|
||||
"Augmentin 625 Duo Tablet,Amoxycillin + Clavulanic Acid,Tablet,10 Tab,AUG-991,10/27,204.50,155.00,3004,12,100,890103000001\n" +
|
||||
"Pan 40 Tablet,Pantoprazole 40mg,Tablet,15 Tab,PAN-442,04/27,162.00,115.00,3004,12,150,890103000002\n" +
|
||||
"Dolo 650 Tablet,Paracetamol 650mg,Tablet,15 Tab,DOL-112,08/27,34.00,22.50,3004,12,200,890103000003\n" +
|
||||
"Azithral 500 Tablet,Azithromycin 500mg,Tablet,5 Tab,AZI-771,12/26,125.00,89.00,3004,12,80,890103000004\n";
|
||||
|
||||
var blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
var link = document.createElement("a");
|
||||
var url = URL.createObjectURL(blob);
|
||||
link.setAttribute("href", url);
|
||||
link.setAttribute("download", "Marg_Pharmacy_Sample_Import.csv");
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
// Search and Refresh
|
||||
$('#btn_store_search').on('click', function() {
|
||||
var q = $('#store_search_input').val();
|
||||
window.location.href = '<?= base_url('setting/admin/medical-store') ?>?q=' + encodeURIComponent(q);
|
||||
});
|
||||
|
||||
$('#btn_refresh_store_list').on('click', function() {
|
||||
window.location.href = '<?= base_url('setting/admin/medical-store') ?>';
|
||||
});
|
||||
</script>
|
||||
4111
public/App/MedicalStore/index.html
Normal file
4111
public/App/MedicalStore/index.html
Normal file
File diff suppressed because it is too large
Load Diff
17
public/App/MedicalStore/manifest.json
Normal file
17
public/App/MedicalStore/manifest.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"short_name": "Medical Store",
|
||||
"name": "HMS Medical Store & Multi-Building Pharmacy POS",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/assets/img/logo.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
],
|
||||
"start_url": "/app/medical-store",
|
||||
"background_color": "#0f172a",
|
||||
"theme_color": "#0891b2",
|
||||
"display": "standalone",
|
||||
"orientation": "any"
|
||||
}
|
||||
21
public/App/MedicalStore/sw.js
Normal file
21
public/App/MedicalStore/sw.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const CACHE_NAME = 'medstore-pwa-v1';
|
||||
const ASSETS_TO_CACHE = [
|
||||
'/app/medical-store',
|
||||
'https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css',
|
||||
'https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css'
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME).then((cache) => {
|
||||
return cache.addAll(ASSETS_TO_CACHE);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
if (event.request.method !== 'GET') return;
|
||||
event.respondWith(
|
||||
fetch(event.request).catch(() => caches.match(event.request))
|
||||
);
|
||||
});
|
||||
|
|
@ -176,24 +176,24 @@
|
|||
</div>
|
||||
</a>
|
||||
|
||||
<!-- Pharmacy App (Coming Soon) -->
|
||||
<div class="app-option-card disabled">
|
||||
<!-- Medical Store & Pharmacy App (Active PWA) -->
|
||||
<a href="/app/medical-store" class="app-option-card">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="app-icon-circle bg-secondary-subtle text-secondary">
|
||||
<div class="app-icon-circle bg-info-subtle text-info">
|
||||
<i class="bi bi-capsule"></i>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h6 class="fw-bold mb-0 text-secondary">Pharmacy App</h6>
|
||||
<span class="badge bg-secondary" style="font-size: 10px;">Coming Soon</span>
|
||||
<h6 class="fw-bold mb-0 text-dark">Medical Store & Pharmacy POS</h6>
|
||||
<span class="badge bg-info text-dark" style="font-size: 10px;">Active PWA</span>
|
||||
</div>
|
||||
<small class="text-muted d-block mt-1" style="font-size: 12px;">
|
||||
Counter Sales, Medicine Dispense & Stock Check
|
||||
Multi-Building Counters, DL 20B/21B, GST, UHID/IPD/OPD & Ledgers
|
||||
</small>
|
||||
</div>
|
||||
<i class="bi bi-lock-fill text-muted"></i>
|
||||
<i class="bi bi-chevron-right text-muted"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Install Banner -->
|
||||
|
|
|
|||
23
scratch/add_discount_columns.php
Normal file
23
scratch/add_discount_columns.php
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
$db = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
if ($db->connect_error) {
|
||||
die("Connection failed: " . $db->connect_error . "\n");
|
||||
}
|
||||
|
||||
$res = $db->query("SHOW COLUMNS FROM mst_sales LIKE 'bill_discount_type'");
|
||||
if ($res->num_rows == 0) {
|
||||
$db->query("ALTER TABLE mst_sales ADD COLUMN bill_discount_type varchar(10) DEFAULT 'pct' AFTER discount_amount");
|
||||
$db->query("ALTER TABLE mst_sales ADD COLUMN bill_discount_val decimal(10,2) DEFAULT 0.00 AFTER bill_discount_type");
|
||||
echo "Columns bill_discount_type and bill_discount_val added to mst_sales.\n";
|
||||
} else {
|
||||
echo "Columns already exist in mst_sales.\n";
|
||||
}
|
||||
|
||||
$resItem = $db->query("SHOW COLUMNS FROM mst_sales_items LIKE 'discount_type'");
|
||||
if ($resItem->num_rows == 0) {
|
||||
$db->query("ALTER TABLE mst_sales_items ADD COLUMN discount_type varchar(10) DEFAULT 'pct' AFTER unit_mrp");
|
||||
$db->query("ALTER TABLE mst_sales_items ADD COLUMN discount_val decimal(10,2) DEFAULT 0.00 AFTER discount_type");
|
||||
echo "Columns discount_type and discount_val added to mst_sales_items.\n";
|
||||
} else {
|
||||
echo "Columns already exist in mst_sales_items.\n";
|
||||
}
|
||||
43
scratch/add_split_payment_columns.php
Normal file
43
scratch/add_split_payment_columns.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
$db = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
if ($db->connect_error) {
|
||||
die("Connection failed: " . $db->connect_error . "\n");
|
||||
}
|
||||
|
||||
// Check and add columns to mst_sales
|
||||
$salesCols = [
|
||||
'bank_name' => "ALTER TABLE mst_sales ADD COLUMN bank_name varchar(100) DEFAULT '' AFTER payment_reference",
|
||||
'upi_ref_no' => "ALTER TABLE mst_sales ADD COLUMN upi_ref_no varchar(100) DEFAULT '' AFTER bank_name",
|
||||
'card_ref_no' => "ALTER TABLE mst_sales ADD COLUMN card_ref_no varchar(100) DEFAULT '' AFTER upi_ref_no",
|
||||
'is_bank_reconciled' => "ALTER TABLE mst_sales ADD COLUMN is_bank_reconciled tinyint(1) DEFAULT 0 AFTER card_ref_no",
|
||||
'reconciled_at' => "ALTER TABLE mst_sales ADD COLUMN reconciled_at datetime NULL AFTER is_bank_reconciled",
|
||||
'reconciled_by' => "ALTER TABLE mst_sales ADD COLUMN reconciled_by varchar(100) DEFAULT '' AFTER reconciled_at",
|
||||
'reconciled_notes' => "ALTER TABLE mst_sales ADD COLUMN reconciled_notes text NULL AFTER reconciled_by",
|
||||
];
|
||||
|
||||
foreach ($salesCols as $col => $sql) {
|
||||
$res = $db->query("SHOW COLUMNS FROM mst_sales LIKE '$col'");
|
||||
if ($res->num_rows == 0) {
|
||||
$db->query($sql);
|
||||
echo "Added column $col to mst_sales.\n";
|
||||
} else {
|
||||
echo "Column $col already exists in mst_sales.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Check and add columns to mst_ledger_entries
|
||||
$ledgerCols = [
|
||||
'reconciled_flag' => "ALTER TABLE mst_ledger_entries ADD COLUMN reconciled_flag tinyint(1) DEFAULT 0 AFTER narration",
|
||||
'reconciled_at' => "ALTER TABLE mst_ledger_entries ADD COLUMN reconciled_at datetime NULL AFTER reconciled_flag",
|
||||
'reconciled_ref' => "ALTER TABLE mst_ledger_entries ADD COLUMN reconciled_ref varchar(100) DEFAULT '' AFTER reconciled_at",
|
||||
];
|
||||
|
||||
foreach ($ledgerCols as $col => $sql) {
|
||||
$res = $db->query("SHOW COLUMNS FROM mst_ledger_entries LIKE '$col'");
|
||||
if ($res->num_rows == 0) {
|
||||
$db->query($sql);
|
||||
echo "Added column $col to mst_ledger_entries.\n";
|
||||
} else {
|
||||
echo "Column $col already exists in mst_ledger_entries.\n";
|
||||
}
|
||||
}
|
||||
51
scratch/analyze_diffs.php
Normal file
51
scratch/analyze_diffs.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
$our_json = json_decode(file_get_contents('d:/Workplace/HMS_CI4_OLD/writable/ipd9_bundle.json'), true);
|
||||
$f1 = json_decode(file_get_contents('d:/Workplace/HMS_CI4_OLD/scratch/fhir_1.json'), true);
|
||||
|
||||
echo "=== FHIR_1 vs our_FHIR Analysis ===\n";
|
||||
|
||||
echo "\n--- FHIR_1 Sections in Composition ---\n";
|
||||
foreach ($f1['entry'][0]['resource']['section'] as $s) {
|
||||
echo "Title: " . $s['title'] . " | Code: " . $s['code']['coding'][0]['code'] . " | Entries: " . count($s['entry']) . "\n";
|
||||
}
|
||||
|
||||
echo "\n--- our_FHIR Sections in Composition ---\n";
|
||||
foreach ($our_json['entry'][0]['resource']['section'] as $s) {
|
||||
echo "Title: " . $s['title'] . " | Code: " . $s['code']['coding'][0]['code'] . " | Entries: " . count($s['entry']) . "\n";
|
||||
}
|
||||
|
||||
// Let's check differences in:
|
||||
// 1. Encounter resource
|
||||
echo "\n--- FHIR_1 Encounter ---\n";
|
||||
print_r($f1['entry'][4]['resource']);
|
||||
|
||||
echo "\n--- our_FHIR Encounter ---\n";
|
||||
foreach ($our_json['entry'] as $e) {
|
||||
if ($e['resource']['resourceType'] === 'Encounter') {
|
||||
print_r($e['resource']);
|
||||
}
|
||||
}
|
||||
|
||||
// Let's check differences in:
|
||||
// 2. Patient resource
|
||||
echo "\n--- FHIR_1 Patient identifiers ---\n";
|
||||
print_r($f1['entry'][1]['resource']['identifier']);
|
||||
|
||||
echo "\n--- our_FHIR Patient identifiers ---\n";
|
||||
print_r($our_json['entry'][1]['resource']['identifier']);
|
||||
|
||||
// Let's check differences in:
|
||||
// 3. Organization resource
|
||||
echo "\n--- FHIR_1 Organization identifiers ---\n";
|
||||
print_r($f1['entry'][3]['resource']['identifier']);
|
||||
|
||||
echo "\n--- our_FHIR Organization identifiers ---\n";
|
||||
print_r($our_json['entry'][3]['resource']['identifier']);
|
||||
|
||||
// Let's check differences in:
|
||||
// 4. Practitioner resource
|
||||
echo "\n--- FHIR_1 Practitioner identifiers ---\n";
|
||||
print_r($f1['entry'][2]['resource']['identifier']);
|
||||
|
||||
echo "\n--- our_FHIR Practitioner identifiers ---\n";
|
||||
print_r($our_json['entry'][2]['resource']['identifier']);
|
||||
4
scratch/babel.min.js
vendored
Normal file
4
scratch/babel.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
912
scratch/bundle.js
Normal file
912
scratch/bundle.js
Normal file
File diff suppressed because one or more lines are too long
1483
scratch/bundle_with_pdf.json
Normal file
1483
scratch/bundle_with_pdf.json
Normal file
File diff suppressed because one or more lines are too long
1426
scratch/bundle_without_pdf.json
Normal file
1426
scratch/bundle_without_pdf.json
Normal file
File diff suppressed because it is too large
Load Diff
23
scratch/check_all_bundles.php
Normal file
23
scratch/check_all_bundles.php
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
$dir = 'ABDM_FHIR/examples.json/';
|
||||
$files = glob($dir . 'Bundle-*.json');
|
||||
foreach ($files as $file) {
|
||||
$b = json_decode(file_get_contents($file), true);
|
||||
if (!isset($b['entry'][0]['resource']['resourceType'])) continue;
|
||||
$comp = $b['entry'][0]['resource'];
|
||||
echo basename($file) . ":\n";
|
||||
echo " title: " . ($comp['title'] ?? 'NONE') . "\n";
|
||||
echo " type: " . ($comp['type']['text'] ?? $comp['type']['coding'][0]['display'] ?? 'NONE') . "\n";
|
||||
if (isset($comp['category'])) {
|
||||
echo " category: " . json_encode($comp['category']) . "\n";
|
||||
}
|
||||
if (isset($comp['encounter'])) {
|
||||
echo " encounter: " . json_encode($comp['encounter']) . "\n";
|
||||
}
|
||||
if (isset($comp['custodian'])) {
|
||||
echo " custodian: " . json_encode($comp['custodian']) . "\n";
|
||||
}
|
||||
if (isset($comp['author'])) {
|
||||
echo " author: " . json_encode($comp['author']) . "\n";
|
||||
}
|
||||
}
|
||||
26
scratch/check_all_dbs.php
Normal file
26
scratch/check_all_dbs.php
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
$conn = new mysqli('localhost', 'root', '');
|
||||
$res = $conn->query("SHOW DATABASES");
|
||||
echo "DATABASES ON LOCALHOST:\n";
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
$dbName = $row['Database'];
|
||||
echo "- " . $dbName;
|
||||
|
||||
// Check if dbName has ipd_master
|
||||
$dbConn = @new mysqli('localhost', 'root', '', $dbName);
|
||||
if (!$dbConn->connect_error) {
|
||||
$check = $dbConn->query("SHOW TABLES LIKE 'ipd_master'");
|
||||
if ($check && $check->num_rows > 0) {
|
||||
$cnt = $dbConn->query("SELECT count(*) as c FROM ipd_master")->fetch_assoc()['c'];
|
||||
echo " (has ipd_master with $cnt rows)";
|
||||
$rec009 = $dbConn->query("SELECT id, ipd_code, p_id, r_doc_id, r_doc_name FROM ipd_master WHERE ipd_code LIKE '%0009%' OR ipd_code LIKE '%009%'");
|
||||
if ($rec009 && $rec009->num_rows > 0) {
|
||||
echo " *** FOUND 0009! ***\n";
|
||||
while ($r = $rec009->fetch_assoc()) {
|
||||
print_r($r);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
17
scratch/check_all_orgs.php
Normal file
17
scratch/check_all_orgs.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
$files = glob(__DIR__ . '/../ABDM_FHIR/examples.json/Bundle-*.json');
|
||||
foreach ($files as $f) {
|
||||
$json = json_decode(file_get_contents($f), true);
|
||||
if (!isset($json['entry'])) continue;
|
||||
foreach ($json['entry'] as $e) {
|
||||
$res = $e['resource'] ?? [];
|
||||
if (($res['resourceType'] ?? '') === 'Organization') {
|
||||
echo basename($f) . ":\n";
|
||||
echo " name: " . ($res['name'] ?? '') . "\n";
|
||||
echo " telecom: " . json_encode($res['telecom'] ?? '') . "\n";
|
||||
echo " address: " . json_encode($res['address'] ?? '') . "\n";
|
||||
echo " type: " . json_encode($res['type'] ?? '') . "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
scratch/check_all_tables_ipd9.php
Normal file
18
scratch/check_all_tables_ipd9.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$dbname = 'hms_data_ci4';
|
||||
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$tables = ['ipd_discharge_prescrption_prescribed', 'ipd_discharge_drug', 'ipd_discharge', 'ipd_discharge_instructions'];
|
||||
foreach ($tables as $t) {
|
||||
if ($pdo->query("SHOW TABLES LIKE '$t'")->fetch()) {
|
||||
$stmt = $pdo->query("SELECT * FROM $t WHERE ipd_id = 9");
|
||||
echo "=== Table $t ===\n";
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
}
|
||||
}
|
||||
8
scratch/check_api_doctors.php
Normal file
8
scratch/check_api_doctors.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
$conn = new mysqli('localhost', 'root', '', 'hms_ci4_2026');
|
||||
|
||||
$res = $conn->query("SELECT id, p_title, p_fname, p_mname, p_lname, email1, mphone1 FROM doctor_master");
|
||||
echo "DOCTORS IN doctor_master:\n";
|
||||
while ($d = $res->fetch_assoc()) {
|
||||
print_r($d);
|
||||
}
|
||||
7
scratch/check_careplan_spec.php
Normal file
7
scratch/check_careplan_spec.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$def = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-CarePlan.json'), true);
|
||||
foreach ($def['snapshot']['element'] as $el) {
|
||||
if (strpos($el['id'], 'CarePlan.activity') === 0 || strpos($el['id'], 'CarePlan.category') === 0) {
|
||||
echo $el['id'] . " [min: " . $el['min'] . ", max: " . $el['max'] . "]\n";
|
||||
}
|
||||
}
|
||||
14
scratch/check_ci4_db.php
Normal file
14
scratch/check_ci4_db.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
require __DIR__ . '/../vendor/codeigniter4/framework/system/Test/bootstrap.php';
|
||||
|
||||
$gateway = new \App\Controllers\AbdmGateway();
|
||||
$req = \Config\Services::request();
|
||||
$resp = \Config\Services::response();
|
||||
$logger = \Config\Services::logger();
|
||||
$gateway->initController($req, $resp, $logger);
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
echo "DB: " . $db->getDatabase() . "\n";
|
||||
|
||||
$row = $db->table('patient_master')->where('id', 11)->get(1)->getRowArray();
|
||||
echo "Patient 11: " . json_encode($row) . "\n";
|
||||
13
scratch/check_comp_cat.php
Normal file
13
scratch/check_comp_cat.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/package/package/StructureDefinition-ImmunizationRecord.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (strpos($el['id'], 'Composition.category') === 0 || strpos($el['id'], 'Composition.encounter') === 0) {
|
||||
echo $el['id'] . ":\n";
|
||||
if (isset($el['binding'])) {
|
||||
echo " Binding: " . json_encode($el['binding']) . "\n";
|
||||
}
|
||||
if (isset($el['type'])) {
|
||||
echo " Type: " . json_encode($el['type']) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
13
scratch/check_comp_category_sd.php
Normal file
13
scratch/check_comp_category_sd.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents(__DIR__ . '/../ABDM_FHIR/examples.json/StructureDefinition-ImmunizationRecord.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (strpos($el['id'], 'Composition.category') === 0) {
|
||||
echo $el['id'] . "\n";
|
||||
if (isset($el['binding'])) {
|
||||
echo " binding: " . json_encode($el['binding']) . "\n";
|
||||
}
|
||||
if (isset($el['definition'])) {
|
||||
echo " def: " . $el['definition'] . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
7
scratch/check_comp_enc.php
Normal file
7
scratch/check_comp_enc.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$lines = file(__DIR__ . '/../app/Libraries/FhirR4Builder.php');
|
||||
foreach ($lines as $i => $l) {
|
||||
if (strpos($l, "'encounter'") !== false && strpos($l, '=>') !== false) {
|
||||
echo ($i + 1) . ': ' . trim($l) . PHP_EOL;
|
||||
}
|
||||
}
|
||||
7
scratch/check_comp_slices.php
Normal file
7
scratch/check_comp_slices.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$def = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-DischargeSummaryRecord.json'), true);
|
||||
foreach ($def['snapshot']['element'] as $el) {
|
||||
if (strpos($el['id'], 'Composition.section:') === 0) {
|
||||
echo $el['id'] . " (min=" . $el['min'] . ", max=" . $el['max'] . ")\n";
|
||||
}
|
||||
}
|
||||
10
scratch/check_cond_cat_binding.php
Normal file
10
scratch/check_cond_cat_binding.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
$def = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-Condition.json'), true);
|
||||
foreach ($def['snapshot']['element'] as $el) {
|
||||
if (strpos($el['id'], 'Condition.category') === 0) {
|
||||
echo $el['id'] . "\n";
|
||||
if (isset($el['binding'])) {
|
||||
echo " Binding: " . json_encode($el['binding']) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
7
scratch/check_cond_dates.php
Normal file
7
scratch/check_cond_dates.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-Condition.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (str_starts_with($el['id'], 'Condition.recordedDate') || str_starts_with($el['id'], 'Condition.onset')) {
|
||||
echo "{$el['id']} -> type: " . json_encode($el['type']) . ", min: {$el['min']}, max: {$el['max']}\n";
|
||||
}
|
||||
}
|
||||
7
scratch/check_cond_req.php
Normal file
7
scratch/check_cond_req.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$def = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-Condition.json'), true);
|
||||
foreach ($def['snapshot']['element'] as $el) {
|
||||
if ($el['min'] > 0) {
|
||||
echo $el['id'] . " min=" . $el['min'] . "\n";
|
||||
}
|
||||
}
|
||||
7
scratch/check_cp_req.php
Normal file
7
scratch/check_cp_req.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$def = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-CarePlan.json'), true);
|
||||
foreach ($def['snapshot']['element'] as $el) {
|
||||
if ($el['min'] > 0) {
|
||||
echo $el['id'] . " min=" . $el['min'] . "\n";
|
||||
}
|
||||
}
|
||||
21
scratch/check_db_health_records.php
Normal file
21
scratch/check_db_health_records.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
$db = \Config\Database::connect();
|
||||
if ($db->tableExists('health_records')) {
|
||||
$rows = $db->table('health_records')
|
||||
->where('entity_type', 'ipd')
|
||||
->orderBy('id', 'DESC')
|
||||
->limit(5)
|
||||
->get()
|
||||
->getResultArray();
|
||||
echo "Found " . count($rows) . " health_records for IPD:\n";
|
||||
foreach ($rows as $r) {
|
||||
echo "ID: " . $r['id'] . " | Entity ID: " . $r['entity_id'] . " | Care Context: " . ($r['care_context_reference'] ?? '') . " | Status: " . ($r['push_status'] ?? '') . " | Updated: " . ($r['updated_at'] ?? '') . "\n";
|
||||
$data = $r['record_data'] ?? '';
|
||||
if ($data !== '') {
|
||||
$bundle = json_decode($data, true);
|
||||
echo " Bundle ID in DB: " . ($bundle['id'] ?? 'unknown') . " | Entry count: " . count($bundle['entry'] ?? []) . "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "health_records table does not exist.\n";
|
||||
}
|
||||
9
scratch/check_db_hospital.php
Normal file
9
scratch/check_db_hospital.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
$mysqli = new mysqli('localhost', 'root', '', 'hms_data_ci4', 3306);
|
||||
if ($mysqli->connect_error) {
|
||||
die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
|
||||
}
|
||||
$res = $mysqli->query("SELECT s_name, s_value FROM hospital_setting");
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
echo $row['s_name'] . ' = ' . $row['s_value'] . PHP_EOL;
|
||||
}
|
||||
12
scratch/check_dc_entries.php
Normal file
12
scratch/check_dc_entries.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
$data = json_decode(file_get_contents('ABDM_FHIR/examples.json/Bundle-DischargeSummary-example-04.json'), true);
|
||||
foreach ($data['entry'] as $i => $e) {
|
||||
$r = $e['resource'];
|
||||
echo "Entry $i: " . $r['resourceType'] . "\n";
|
||||
if ($r['resourceType'] === 'Composition') {
|
||||
echo " title: " . ($r['title'] ?? '') . "\n";
|
||||
echo " custodian: " . json_encode($r['custodian'] ?? '') . "\n";
|
||||
echo " author: " . json_encode($r['author'] ?? '') . "\n";
|
||||
echo " encounter: " . json_encode($r['encounter'] ?? '') . "\n";
|
||||
}
|
||||
}
|
||||
11
scratch/check_diag_use.php
Normal file
11
scratch/check_diag_use.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
$dir = 'd:/Workplace/HMS_CI4_OLD/ABDM_FHIR/definitions.json/';
|
||||
$files = glob($dir . '*diagnosis-use*.json');
|
||||
foreach ($files as $f) {
|
||||
echo "Found: " . basename($f) . "\n";
|
||||
$data = json_decode(file_get_contents($f), true);
|
||||
if (isset($data['compose']['include'])) {
|
||||
echo json_encode($data['compose']['include'], JSON_PRETTY_PRINT) . "\n";
|
||||
}
|
||||
}
|
||||
21
scratch/check_discharge_pdf.php
Normal file
21
scratch/check_discharge_pdf.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
// Bootstrap CodeIgniter
|
||||
$_SERVER['CI_ENVIRONMENT'] = 'development';
|
||||
$app = require __DIR__ . '/../app/Config/Boot/production.php';
|
||||
|
||||
// Let's test generating the discharge summary PDF for IPD 9
|
||||
$controller = new \App\Controllers\Ipd_discharge();
|
||||
$request = \Config\Services::request();
|
||||
$response = \Config\Services::response();
|
||||
$logger = \Config\Services::logger();
|
||||
$controller->initController($request, $response, $logger);
|
||||
|
||||
$pdfPath = WRITEPATH . 'uploads/abdm/ipd/9/discharge-summary.pdf';
|
||||
echo "Checking PDF at: $pdfPath\n";
|
||||
if (file_exists($pdfPath)) {
|
||||
echo "Existing PDF size: " . filesize($pdfPath) . " bytes\n";
|
||||
} else {
|
||||
echo "PDF does not exist yet on disk.\n";
|
||||
}
|
||||
11
scratch/check_discount_schema.php
Normal file
11
scratch/check_discount_schema.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
$db = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
if ($db->connect_error) {
|
||||
die("Connection failed: " . $db->connect_error . "\n");
|
||||
}
|
||||
|
||||
echo "=== mst_ledger_entries ===\n";
|
||||
$res = $db->query("DESCRIBE mst_ledger_entries");
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
echo " {$row['Field']} - {$row['Type']}\n";
|
||||
}
|
||||
7
scratch/check_docref_desc.php
Normal file
7
scratch/check_docref_desc.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-DocumentReference.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if ($el['id'] == 'DocumentReference.description') {
|
||||
echo "DocumentReference.description: min={$el['min']}, max={$el['max']}\n";
|
||||
}
|
||||
}
|
||||
7
scratch/check_docref_req.php
Normal file
7
scratch/check_docref_req.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$def = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-DocumentReference.json'), true);
|
||||
foreach ($def['snapshot']['element'] as $el) {
|
||||
if ($el['min'] > 0) {
|
||||
echo $el['id'] . " min=" . $el['min'] . "\n";
|
||||
}
|
||||
}
|
||||
6
scratch/check_doctor_master.php
Normal file
6
scratch/check_doctor_master.php
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
$mysqli = new mysqli('localhost', 'root', '', 'hms_data_ci4', 3306);
|
||||
$res = $mysqli->query("SELECT * FROM doctor_master LIMIT 5");
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
print_r($row);
|
||||
}
|
||||
13
scratch/check_enc_bindings.php
Normal file
13
scratch/check_enc_bindings.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents(__DIR__ . '/../ABDM_FHIR/examples.json/StructureDefinition-Encounter.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (strpos($el['id'], 'Encounter.serviceType') === 0 || strpos($el['id'], 'Encounter.type') === 0) {
|
||||
echo $el['id'] . "\n";
|
||||
if (isset($el['binding'])) {
|
||||
echo " binding: " . json_encode($el['binding']) . "\n";
|
||||
}
|
||||
if (isset($el['definition'])) {
|
||||
echo " def: " . $el['definition'] . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
18
scratch/check_enc_elements.php
Normal file
18
scratch/check_enc_elements.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-Encounter.json'), true);
|
||||
|
||||
echo "=== ENCOUNTER ELEMENTS IN NRCES ===\n";
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (str_starts_with($el['id'], 'Encounter.hospitalization') || str_starts_with($el['id'], 'Encounter.diagnosis') || str_starts_with($el['id'], 'Encounter.reason')) {
|
||||
echo "{$el['id']}\n";
|
||||
if (isset($el['binding'])) {
|
||||
echo " binding: " . json_encode($el['binding']) . "\n";
|
||||
}
|
||||
if (isset($el['type'])) {
|
||||
foreach ($el['type'] as $t) {
|
||||
echo " type: " . $t['code'] . (isset($t['targetProfile']) ? (' -> ' . implode(',', $t['targetProfile'])) : '') . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
9
scratch/check_enc_sd.php
Normal file
9
scratch/check_enc_sd.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents(__DIR__ . '/../ABDM_FHIR/examples.json/StructureDefinition-Encounter.json'), true);
|
||||
echo "=== Encounter elements ===\n";
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (substr_count($el['id'], '.') === 1) {
|
||||
$ms = !empty($el['mustSupport']) ? ' [MustSupport]' : '';
|
||||
echo $el['id'] . $ms . "\n";
|
||||
}
|
||||
}
|
||||
7
scratch/check_encounter_req.php
Normal file
7
scratch/check_encounter_req.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$def = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-Encounter.json'), true);
|
||||
foreach ($def['snapshot']['element'] as $el) {
|
||||
if ($el['min'] > 0) {
|
||||
echo $el['id'] . " min=" . $el['min'] . "\n";
|
||||
}
|
||||
}
|
||||
10
scratch/check_example_encounters.php
Normal file
10
scratch/check_example_encounters.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
foreach (['Bundle-OPConsultNote-example-05.json', 'Bundle-DischargeSummary-example-04.json'] as $file) {
|
||||
$json = json_decode(file_get_contents(__DIR__ . '/../ABDM_FHIR/examples.json/' . $file), true);
|
||||
echo "=== $file Encounter ===\n";
|
||||
foreach ($json['entry'] as $e) {
|
||||
if ($e['resource']['resourceType'] === 'Encounter') {
|
||||
echo json_encode($e['resource'], JSON_PRETTY_PRINT) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
19
scratch/check_file_upload_table.php
Normal file
19
scratch/check_file_upload_table.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
$mysqli = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
if ($mysqli->connect_error) {
|
||||
die("Connection failed: " . $mysqli->connect_error);
|
||||
}
|
||||
|
||||
$res = $mysqli->query("SHOW COLUMNS FROM file_upload_data");
|
||||
$cols = [];
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
$cols[] = $row['Field'] . ' (' . $row['Type'] . ')';
|
||||
}
|
||||
echo "FILE_UPLOAD_DATA COLUMNS:\n";
|
||||
print_r($cols);
|
||||
|
||||
$res = $mysqli->query("SELECT * FROM file_upload_data ORDER BY id DESC LIMIT 5");
|
||||
echo "\nLAST 5 ROWS IN FILE_UPLOAD_DATA:\n";
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
print_r($row);
|
||||
}
|
||||
27
scratch/check_full_563.php
Normal file
27
scratch/check_full_563.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
$lines = file('C:/Users/d_s_b/.gemini/antigravity-ide/brain/5d74b30a-f6db-45f5-988c-4e3f71d58774/.system_generated/logs/transcript_full.jsonl');
|
||||
$d = json_decode($lines[563], true);
|
||||
$content = $d['content'];
|
||||
$start = strpos($content, '{');
|
||||
$end = strrpos($content, '}');
|
||||
if ($start !== false && $end !== false) {
|
||||
$jsonStr = substr($content, $start, $end - $start + 1);
|
||||
$bundle = json_decode($jsonStr, true);
|
||||
if ($bundle && isset($bundle['entry'])) {
|
||||
foreach ($bundle['entry'] as $idx => $e) {
|
||||
$r = $e['resource'];
|
||||
echo "$idx: " . $r['resourceType'] . " (id: " . ($r['id'] ?? '') . ")\n";
|
||||
if ($r['resourceType'] === 'Organization') {
|
||||
echo "Organization:\n" . json_encode($r, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
|
||||
}
|
||||
if ($r['resourceType'] === 'Encounter') {
|
||||
echo "Encounter:\n" . json_encode($r, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
|
||||
}
|
||||
if ($r['resourceType'] === 'Immunization') {
|
||||
echo "Immunization:\n" . json_encode($r, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "JSON decode error: " . json_last_error_msg() . "\n";
|
||||
}
|
||||
}
|
||||
7
scratch/check_h_settings.php
Normal file
7
scratch/check_h_settings.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
require 'd:/Workplace/HMS_CI4_OLD/vendor/codeigniter4/framework/system/Test/bootstrap.php';
|
||||
$db = \Config\Database::connect('default');
|
||||
$rows = $db->table('hospital_setting')->select('s_name, s_value')->like('s_name', 'H_')->orLike('s_name', 'ABDM')->get()->getResultArray();
|
||||
foreach ($rows as $r) {
|
||||
echo $r['s_name'] . ' = ' . $r['s_value'] . PHP_EOL;
|
||||
}
|
||||
40
scratch/check_health_doc_db.php
Normal file
40
scratch/check_health_doc_db.php
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
$mysqli = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
|
||||
if ($mysqli->connect_error) {
|
||||
die("Connect Error: " . $mysqli->connect_error);
|
||||
}
|
||||
|
||||
echo "=== patient_doc with ID 5 ===\n";
|
||||
$res = $mysqli->query("SELECT * FROM patient_doc WHERE id = 5");
|
||||
if ($row = $res->fetch_assoc()) {
|
||||
print_r($row);
|
||||
} else {
|
||||
echo "No row with id=5 in patient_doc\n";
|
||||
}
|
||||
|
||||
echo "\n=== recent patient_doc rows ===\n";
|
||||
$res = $mysqli->query("SELECT id, p_id, dr_id, doc_format_id, created_at FROM patient_doc ORDER BY id DESC LIMIT 5");
|
||||
while ($r = $res->fetch_assoc()) {
|
||||
print_r($r);
|
||||
}
|
||||
|
||||
echo "\n=== file_upload_data with ID 5 ===\n";
|
||||
$res = $mysqli->query("SELECT * FROM file_upload_data WHERE id = 5");
|
||||
if ($row = $res->fetch_assoc()) {
|
||||
print_r($row);
|
||||
} else {
|
||||
echo "No row with id=5 in file_upload_data\n";
|
||||
}
|
||||
|
||||
echo "\n=== recent file_upload_data rows ===\n";
|
||||
$res = $mysqli->query("SELECT id, pid, insert_date FROM file_upload_data ORDER BY id DESC LIMIT 5");
|
||||
while ($r = $res->fetch_assoc()) {
|
||||
print_r($r);
|
||||
}
|
||||
|
||||
echo "\n=== abdm_work_tasks with ID 585 ===\n";
|
||||
$res = $mysqli->query("SELECT * FROM abdm_work_tasks WHERE id = 585");
|
||||
if ($row = $res->fetch_assoc()) {
|
||||
print_r($row);
|
||||
}
|
||||
16
scratch/check_health_records.php
Normal file
16
scratch/check_health_records.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
define('FCPATH', __DIR__ . '/../public/');
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
$bootstrap = require __DIR__ . '/../app/Config/Boot/development.php';
|
||||
$app = \Config\Services::codeigniter();
|
||||
$app->initialize();
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$rows = $db->table('health_records')->orderBy('id', 'DESC')->limit(10)->get()->getResultArray();
|
||||
echo "=== Last 10 Health Records in DB ===\n";
|
||||
foreach ($rows as $r) {
|
||||
echo "ID: {$r['id']} | Entity: {$r['entity_type']} #{$r['entity_id']} | HI Type: {$r['hi_type']} | Status: {$r['push_status']} | Queue: {$r['queue_id']} | Date: {$r['created_at']}\n";
|
||||
if (!empty($r['error_message'])) {
|
||||
echo " Error: {$r['error_message']}\n";
|
||||
}
|
||||
}
|
||||
11
scratch/check_hms_data_ci4.php
Normal file
11
scratch/check_hms_data_ci4.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
|
||||
$pdo1 = new PDO("mysql:host=$host;dbname=hms_ci4_2026;charset=utf8mb4", $user, $pass);
|
||||
echo "Count in hms_ci4_2026 opd_med_master: " . $pdo1->query("SELECT COUNT(*) FROM opd_med_master")->fetchColumn() . "\n";
|
||||
|
||||
$stmt = $pdo1->query("SELECT id, item_name, genericname, salt_name FROM opd_med_master WHERE item_name LIKE '%PANTOP%' LIMIT 5");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
6
scratch/check_hospital_keys.php
Normal file
6
scratch/check_hospital_keys.php
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
$mysqli = new mysqli('localhost', 'root', '', 'hms_data_ci4', 3306);
|
||||
$res = $mysqli->query("SELECT s_name, s_value FROM hospital_setting WHERE s_name LIKE '%H_%' OR s_name LIKE '%ABDM%' OR s_name LIKE '%addr%' OR s_name LIKE '%phone%'");
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
echo $row['s_name'] . ' = ' . $row['s_value'] . PHP_EOL;
|
||||
}
|
||||
8
scratch/check_imm_loc.php
Normal file
8
scratch/check_imm_loc.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/package/package/StructureDefinition-Immunization.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (strpos($el['id'], 'Immunization.location') === 0) {
|
||||
echo $el['id'] . ":\n";
|
||||
echo " Type: " . json_encode($el['type']) . "\n";
|
||||
}
|
||||
}
|
||||
8
scratch/check_imm_ms.php
Normal file
8
scratch/check_imm_ms.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents(__DIR__ . '/../ABDM_FHIR/examples.json/StructureDefinition-Immunization.json'), true);
|
||||
echo "=== Immunization MustSupport elements ===\n";
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (!empty($el['mustSupport'])) {
|
||||
echo $el['id'] . " (min: " . $el['min'] . ")\n";
|
||||
}
|
||||
}
|
||||
21
scratch/check_init_bundle.php
Normal file
21
scratch/check_init_bundle.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
$lines = file('C:/Users/d_s_b/.gemini/antigravity-ide/brain/5d74b30a-f6db-45f5-988c-4e3f71d58774/.system_generated/logs/transcript.jsonl');
|
||||
$d = json_decode($lines[0], true);
|
||||
if (preg_match('/\{[\s\S]*"resourceType"\s*:\s*"Bundle"[\s\S]*\}/', $d['content'], $m)) {
|
||||
$bundle = json_decode($m[0], true);
|
||||
if ($bundle && isset($bundle['entry'])) {
|
||||
foreach ($bundle['entry'] as $idx => $e) {
|
||||
$r = $e['resource'];
|
||||
echo "$idx: " . $r['resourceType'] . " id=" . ($r['id'] ?? '') . "\n";
|
||||
if ($r['resourceType'] === 'Immunization') {
|
||||
echo "Immunization keys: " . implode(', ', array_keys($r)) . "\n";
|
||||
if (isset($r['location'])) {
|
||||
echo "Location: " . json_encode($r['location']) . "\n";
|
||||
}
|
||||
if (isset($r['encounter'])) {
|
||||
echo "Encounter: " . json_encode($r['encounter']) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
scratch/check_init_imm.php
Normal file
14
scratch/check_init_imm.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
$lines = file('C:/Users/d_s_b/.gemini/antigravity-ide/brain/5d74b30a-f6db-45f5-988c-4e3f71d58774/.system_generated/logs/transcript.jsonl');
|
||||
$d = json_decode($lines[0], true);
|
||||
preg_match('/"resourceType": "Immunization".*?\}/s', $d['content'], $m);
|
||||
if ($m) {
|
||||
echo $m[0] . "\n";
|
||||
} else {
|
||||
echo "Not found in regex, showing lines with location or Immunization:\n";
|
||||
foreach (explode("\n", $d['content']) as $l) {
|
||||
if (stripos($l, 'location') !== false || stripos($l, 'resourceType') !== false) {
|
||||
echo $l . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
15
scratch/check_invoice_attachment.php
Normal file
15
scratch/check_invoice_attachment.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-Invoice.json'), true);
|
||||
|
||||
echo "Checking Attachment in Invoice SD:\n";
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (isset($el['type'])) {
|
||||
foreach ($el['type'] as $t) {
|
||||
if (in_array($t['code'], ['Attachment', 'Binary', 'base64Binary'])) {
|
||||
echo "{$el['id']} has type {$t['code']}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "Done checking Attachment in Invoice.\n";
|
||||
16
scratch/check_invoice_elements.php
Normal file
16
scratch/check_invoice_elements.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-Invoice.json'), true);
|
||||
|
||||
echo "Elements in StructureDefinition-Invoice:\n";
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
$types = [];
|
||||
if (isset($el['type'])) {
|
||||
foreach ($el['type'] as $t) {
|
||||
$code = $t['code'] ?? '';
|
||||
$tp = isset($t['targetProfile']) ? (' -> ' . implode(',', $t['targetProfile'])) : '';
|
||||
$types[] = $code . $tp;
|
||||
}
|
||||
}
|
||||
echo "{$el['id']} [" . implode('|', $types) . "] min:{$el['min']} max:{$el['max']}\n";
|
||||
}
|
||||
15
scratch/check_invoice_files.php
Normal file
15
scratch/check_invoice_files.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
$dir = 'd:/Workplace/HMS_CI4_OLD/ABDM_FHIR/definitions.json/';
|
||||
$files = glob($dir . '*Invoice*.json');
|
||||
echo "Definitions with Invoice:\n";
|
||||
foreach ($files as $f) {
|
||||
echo " - " . basename($f) . "\n";
|
||||
}
|
||||
|
||||
$exDir = 'd:/Workplace/HMS_CI4_OLD/ABDM_FHIR/examples.json/';
|
||||
$exFiles = glob($exDir . '*Invoice*.json');
|
||||
echo "Examples with Invoice:\n";
|
||||
foreach ($exFiles as $f) {
|
||||
echo " - " . basename($f) . "\n";
|
||||
}
|
||||
20
scratch/check_invoice_record_diff.php
Normal file
20
scratch/check_invoice_record_diff.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-InvoiceRecord.json'), true);
|
||||
|
||||
echo "Checking section slices in StructureDefinition-InvoiceRecord:\n";
|
||||
$differential = $sd['differential']['element'];
|
||||
foreach ($differential as $el) {
|
||||
if (str_starts_with($el['id'], 'Composition.section')) {
|
||||
echo "{$el['id']}\n";
|
||||
if (isset($el['sliceName'])) {
|
||||
echo " sliceName: {$el['sliceName']}\n";
|
||||
}
|
||||
if (isset($el['code'])) {
|
||||
echo " code: " . json_encode($el['code']) . "\n";
|
||||
}
|
||||
if (isset($el['type'])) {
|
||||
echo " type: " . json_encode($el['type']) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
20
scratch/check_invoice_record_sd.php
Normal file
20
scratch/check_invoice_record_sd.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-InvoiceRecord.json'), true);
|
||||
|
||||
echo "Snapshot Elements in StructureDefinition-InvoiceRecord:\n";
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (str_starts_with($el['id'], 'Composition.section')) {
|
||||
echo "{$el['id']}\n";
|
||||
if (isset($el['sliceName'])) {
|
||||
echo " sliceName: {$el['sliceName']}\n";
|
||||
}
|
||||
if (isset($el['type'])) {
|
||||
foreach ($el['type'] as $t) {
|
||||
if (isset($t['targetProfile'])) {
|
||||
echo " targetProfile: " . json_encode($t['targetProfile']) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
scratch/check_invoice_slicing.php
Normal file
10
scratch/check_invoice_slicing.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-InvoiceRecord.json'), true);
|
||||
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (isset($el['slicing'])) {
|
||||
echo "{$el['id']} has slicing:\n";
|
||||
echo json_encode($el['slicing'], JSON_PRETTY_PRINT) . "\n";
|
||||
}
|
||||
}
|
||||
13
scratch/check_ipd9.php
Normal file
13
scratch/check_ipd9.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
define('FCPATH', __DIR__ . '/../public/');
|
||||
chdir(__DIR__ . '/../');
|
||||
require 'vendor/autoload.php';
|
||||
require 'app/Config/Paths.php';
|
||||
$paths = new Config\Paths();
|
||||
require 'system/bootstrap.php';
|
||||
$app = Config\Services::codeigniter();
|
||||
$app->initialize();
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
$ipd = $db->table('ipd_master')->where('id', 9)->get()->getRowArray();
|
||||
echo "IPD 9: " . json_encode($ipd, JSON_PRETTY_PRINT) . "\n";
|
||||
20
scratch/check_ipd_009.php
Normal file
20
scratch/check_ipd_009.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
$conn = new mysqli('localhost', 'root', '', 'hms_ci4_2026');
|
||||
|
||||
echo "=== DOCTOR MASTER RECORDS ===\n";
|
||||
$docRes = $conn->query("SELECT * FROM doctor_master");
|
||||
while ($d = $docRes->fetch_assoc()) {
|
||||
echo "ID: " . $d['id'] . " | Title: " . ($d['p_title'] ?? '') . " | Name: " . ($d['p_fname'] ?? '') . " " . ($d['p_lname'] ?? '') . "\n";
|
||||
}
|
||||
|
||||
echo "\n=== IPD MASTER RECORDS ===\n";
|
||||
$ipdRes = $conn->query("SELECT id, ipd_code, p_id, r_doc_id, r_doc_name, ipd_status, register_date FROM ipd_master ORDER BY id DESC LIMIT 10");
|
||||
while ($i = $ipdRes->fetch_assoc()) {
|
||||
print_r($i);
|
||||
}
|
||||
|
||||
echo "\n=== IPD MASTER DOC LIST ===\n";
|
||||
$docListRes = $conn->query("SELECT * FROM ipd_master_doc_list ORDER BY id DESC LIMIT 20");
|
||||
while ($dl = $docListRes->fetch_assoc()) {
|
||||
print_r($dl);
|
||||
}
|
||||
38
scratch/check_ipd_6_meds.php
Normal file
38
scratch/check_ipd_6_meds.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$dbname = 'hms_ci4_2026';
|
||||
|
||||
|
||||
|
||||
try {
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
} catch (Exception $e) {
|
||||
die("Connection failed: " . $e->getMessage() . "\n");
|
||||
}
|
||||
|
||||
$ipdId = 6;
|
||||
echo "=== CHECKING MEDICATION TABLES FOR IPD ID $ipdId in DB [$dbname] ===\n";
|
||||
|
||||
$tables = [
|
||||
'ipd_discharge_prescrption_prescribed',
|
||||
'ipd_discharge_prescription_prescribed',
|
||||
'ipd_discharge_drug',
|
||||
'ipd_discharge_medication',
|
||||
];
|
||||
|
||||
foreach ($tables as $t) {
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT * FROM `$t` LIMIT 10");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
echo "Table $t: " . count($rows) . " rows found\n";
|
||||
foreach ($rows as $r) {
|
||||
print_r($r);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo "Table $t: " . $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
18
scratch/check_ipd_9_content.php
Normal file
18
scratch/check_ipd_9_content.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$dbname = 'hms_ci4_2026';
|
||||
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$stmt = $pdo->query("SELECT id, ipd_code, p_id FROM ipd_master ORDER BY id DESC LIMIT 15");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
$stmt = $pdo->query("SELECT DISTINCT ipd_id FROM ipd_discharge_prescrption_prescribed");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
$stmt = $pdo->query("SELECT * FROM ipd_discharge_prescrption_prescribed LIMIT 10");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
18
scratch/check_ipd_9_meds.php
Normal file
18
scratch/check_ipd_9_meds.php
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$dbname = 'hms_ci4_2026';
|
||||
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$stmt = $pdo->query("SELECT * FROM ipd_discharge WHERE ipd_id = 9 OR id = 9");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
$stmt = $pdo->query("SELECT * FROM ipd_discharge_1_b WHERE ipd_id = 9");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
$stmt = $pdo->query("SELECT * FROM ipd_discharge_1_b_final WHERE ipd_id = 9");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
15
scratch/check_ipd_9_summary.php
Normal file
15
scratch/check_ipd_9_summary.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$dbname = 'hms_data_ci4';
|
||||
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$stmt = $pdo->query("SELECT * FROM ipd_discharge_instructions WHERE ipd_id = 9");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
$stmt = $pdo->query("SELECT * FROM ipd_discharge WHERE ipd_id = 9");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
34
scratch/check_ipd_data.php
Normal file
34
scratch/check_ipd_data.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
$conn = new mysqli('localhost', 'root', '', 'hms_ci4_2026');
|
||||
|
||||
$sql = "SELECT i.id, i.ipd_code, p.p_code, p.p_fname, p.p_rname,
|
||||
concat('Bed No :', b.bed_number, '[', w.ward_name, ']') as Bed_Desc,
|
||||
date_format(i.register_date,'%d-%m-%Y') as str_register_date,
|
||||
if(i.ipd_status = 0,(to_days(sysdate()) - to_days(i.register_date)),(to_days(i.discharge_date) - to_days(i.register_date))) as no_days,
|
||||
ipd_doc_list.doc_name as doc_name,
|
||||
ipd_doc_list.doc_list as doc_list,
|
||||
i.r_doc_id,
|
||||
i.r_doc_name
|
||||
FROM ipd_master i
|
||||
JOIN patient_master p ON i.p_id = p.id
|
||||
LEFT JOIN (
|
||||
select max(id) as id, ipd_id from bed_assignment_history group by ipd_id
|
||||
) bah_latest ON bah_latest.ipd_id = i.id
|
||||
LEFT JOIN bed_assignment_history bah ON bah.id = bah_latest.id
|
||||
LEFT JOIN bed_master b ON b.id = bah.bed_id
|
||||
LEFT JOIN ward_master w ON w.id = bah.ward_id
|
||||
LEFT JOIN (
|
||||
select i.ipd_id,
|
||||
group_concat(distinct concat_ws(' ', 'Dr.', d.p_fname, d.p_mname, d.p_lname)) as doc_name,
|
||||
group_concat(distinct d.id) as doc_list
|
||||
from ipd_master_doc_list i
|
||||
join doctor_master d on i.doc_id = d.id
|
||||
group by i.ipd_id
|
||||
) ipd_doc_list ON i.id = ipd_doc_list.ipd_id
|
||||
WHERE i.ipd_status = 0";
|
||||
|
||||
$res = $conn->query($sql);
|
||||
echo "HMS CURRENT ADMISSIONS QUERY RESULTS (" . $res->num_rows . " rows):\n\n";
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
print_r($row);
|
||||
}
|
||||
19
scratch/check_ipd_db.php
Normal file
19
scratch/check_ipd_db.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
require_once 'vendor/codeigniter4/framework/system/Test/bootstrap.php';
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
echo "=== IPD_DETAILS COLUMNS ===\n";
|
||||
$cols = $db->getFieldNames('ipd_details');
|
||||
echo implode(', ', $cols) . "\n\n";
|
||||
|
||||
if ($db->tableExists('ipd_discharge')) {
|
||||
echo "=== IPD_DISCHARGE COLUMNS ===\n";
|
||||
$dcols = $db->getFieldNames('ipd_discharge');
|
||||
echo implode(', ', $dcols) . "\n\n";
|
||||
$drow = $db->table('ipd_discharge')->where('ipd_id', 9)->get()->getRowArray();
|
||||
echo "IPD 9 discharge row: " . json_encode($drow, JSON_PRETTY_PRINT) . "\n\n";
|
||||
}
|
||||
|
||||
$irow = $db->table('ipd_details')->where('id', 9)->get()->getRowArray();
|
||||
echo "IPD 9 details row: " . json_encode($irow, JSON_PRETTY_PRINT) . "\n";
|
||||
8
scratch/check_ipd_nursing_entries.php
Normal file
8
scratch/check_ipd_nursing_entries.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
$conn = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
|
||||
$res = $conn->query("SHOW COLUMNS FROM ipd_nursing_entries");
|
||||
echo "COLUMNS IN ipd_nursing_entries:\n";
|
||||
while ($r = $res->fetch_assoc()) {
|
||||
echo "- " . $r['Field'] . " (" . $r['Type'] . ")\n";
|
||||
}
|
||||
7
scratch/check_ipd_tables.php
Normal file
7
scratch/check_ipd_tables.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$db = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
$res = $db->query("SHOW TABLES LIKE '%ipd%'");
|
||||
while ($r = $res->fetch_array()) {
|
||||
echo $r[0] . "\n";
|
||||
}
|
||||
$db->close();
|
||||
7
scratch/check_items_units.php
Normal file
7
scratch/check_items_units.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$db = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
$res = $db->query("SELECT item_id, item_name, unit_pack, units_per_pack, category FROM mst_items LIMIT 25");
|
||||
while($r = $res->fetch_assoc()) {
|
||||
echo "ID {$r['item_id']}: {$r['item_name']} | Pack: '{$r['unit_pack']}' | UnitsPerPack: {$r['units_per_pack']} | Cat: {$r['category']}\n";
|
||||
}
|
||||
$db->close();
|
||||
7
scratch/check_lab_enc.php
Normal file
7
scratch/check_lab_enc.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$d = json_decode(file_get_contents('writable/tmp/abdm_lab_bundle_real_sample.json'), true);
|
||||
foreach ($d['entry'] as $e) {
|
||||
if ($e['resource']['resourceType'] === 'Encounter') {
|
||||
print_r($e['resource']);
|
||||
}
|
||||
}
|
||||
12
scratch/check_lab_entries.php
Normal file
12
scratch/check_lab_entries.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
$data = json_decode(file_get_contents('ABDM_FHIR/examples.json/Bundle-DiagnosticReport-Lab-example-03.json'), true);
|
||||
foreach ($data['entry'] as $i => $e) {
|
||||
$r = $e['resource'];
|
||||
echo "Entry $i: " . $r['resourceType'] . "\n";
|
||||
if ($r['resourceType'] === 'Composition') {
|
||||
echo " title: " . ($r['title'] ?? '') . "\n";
|
||||
echo " custodian: " . json_encode($r['custodian'] ?? '') . "\n";
|
||||
echo " author: " . json_encode($r['author'] ?? '') . "\n";
|
||||
echo " encounter: " . json_encode($r['encounter'] ?? '') . "\n";
|
||||
}
|
||||
}
|
||||
7
scratch/check_lab_real.php
Normal file
7
scratch/check_lab_real.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$d = json_decode(file_get_contents('writable/tmp/abdm_lab_bundle_real_sample.json'), true);
|
||||
echo "Composition:\n";
|
||||
print_r($d['entry'][0]['resource']);
|
||||
foreach ($d['entry'] as $i => $e) {
|
||||
echo "$i: " . $e['resource']['resourceType'] . "\n";
|
||||
}
|
||||
14
scratch/check_master_dosage_when.php
Normal file
14
scratch/check_master_dosage_when.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$dbname = 'hms_data_ci4';
|
||||
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$stmt = $pdo->query("SELECT id, item_name, dosage, dosage_when, dosage_freq, remark FROM opd_med_master LIMIT 10");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
print_r($rows);
|
||||
20
scratch/check_med_masters.php
Normal file
20
scratch/check_med_masters.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$dbname = 'hms_ci4_2026';
|
||||
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$tables = ['opd_med_master', 'med_product_master', 'med_genric_name', 'inv_med_item'];
|
||||
foreach ($tables as $t) {
|
||||
try {
|
||||
echo "=== Table $t ===\n";
|
||||
$stmt = $pdo->query("SELECT * FROM `$t` LIMIT 5");
|
||||
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
11
scratch/check_med_tables.php
Normal file
11
scratch/check_med_tables.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
$db = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
$res = $db->query("SHOW TABLES LIKE '%med%'");
|
||||
while ($r = $res->fetch_array()) {
|
||||
echo $r[0] . "\n";
|
||||
}
|
||||
$res = $db->query("SHOW TABLES LIKE '%pharm%'");
|
||||
while ($r = $res->fetch_array()) {
|
||||
echo $r[0] . "\n";
|
||||
}
|
||||
$db->close();
|
||||
6
scratch/check_media_0.php
Normal file
6
scratch/check_media_0.php
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
$lines = file('C:/Users/d_s_b/.gemini/antigravity-ide/brain/5d74b30a-f6db-45f5-988c-4e3f71d58774/.system_generated/logs/transcript.jsonl');
|
||||
$line0 = json_decode($lines[0], true);
|
||||
echo "Media paths in line 0:\n";
|
||||
print_r($line0['media_paths'] ?? []);
|
||||
print_r($line0['tool_calls'] ?? []);
|
||||
10
scratch/check_mr_binding.php
Normal file
10
scratch/check_mr_binding.php
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-MedicationRequest.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (str_starts_with($el['id'], 'MedicationRequest.category') || str_starts_with($el['id'], 'MedicationRequest.reason')) {
|
||||
echo "{$el['id']}\n";
|
||||
if (isset($el['binding'])) {
|
||||
echo " binding: " . json_encode($el['binding']) . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
7
scratch/check_mr_req.php
Normal file
7
scratch/check_mr_req.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$def = json_decode(file_get_contents('ABDM_FHIR/definitions.json/StructureDefinition-MedicationRequest.json'), true);
|
||||
foreach ($def['snapshot']['element'] as $el) {
|
||||
if ($el['min'] > 0) {
|
||||
echo $el['id'] . " min=" . $el['min'] . "\n";
|
||||
}
|
||||
}
|
||||
7
scratch/check_mst_stores_columns.php
Normal file
7
scratch/check_mst_stores_columns.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$db = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
$res = $db->query('SHOW FULL COLUMNS FROM mst_stores');
|
||||
while($row = $res->fetch_assoc()) {
|
||||
echo $row['Field'] . " | " . $row['Type'] . "\n";
|
||||
}
|
||||
$db->close();
|
||||
17
scratch/check_mysql_ipd.php
Normal file
17
scratch/check_mysql_ipd.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
$mysqli = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
|
||||
$res = $mysqli->query("SELECT * FROM ipd_master WHERE id = 9");
|
||||
echo "=== ipd_master row 9 ===\n";
|
||||
print_r($res->fetch_assoc());
|
||||
|
||||
$res = $mysqli->query("SELECT * FROM ipd_discharge WHERE ipd_id = 9");
|
||||
echo "=== ipd_discharge row for ipd 9 ===\n";
|
||||
print_r($res->fetch_assoc());
|
||||
|
||||
$res = $mysqli->query("SELECT * FROM ipd_discharg_status");
|
||||
echo "=== ipd_discharg_status rows ===\n";
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
print_r($row);
|
||||
}
|
||||
8
scratch/check_nursing_table.php
Normal file
8
scratch/check_nursing_table.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
$conn = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
|
||||
$res = $conn->query("SHOW COLUMNS FROM nursing_treatment_entries");
|
||||
echo "COLUMNS IN nursing_treatment_entries:\n";
|
||||
while ($r = $res->fetch_assoc()) {
|
||||
echo "- " . $r['Field'] . " (" . $r['Type'] . ")\n";
|
||||
}
|
||||
8
scratch/check_opd_dates.php
Normal file
8
scratch/check_opd_dates.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
$conn = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
|
||||
$res = $conn->query("SELECT opd_id, opd_code, p_id, doc_id, apointment_date, opd_status FROM opd_master ORDER BY opd_id DESC LIMIT 20");
|
||||
echo "OPD MASTER DATES IN hms_data_ci4:\n";
|
||||
while ($r = $res->fetch_assoc()) {
|
||||
print_r($r);
|
||||
}
|
||||
14
scratch/check_opd_dose_when.php
Normal file
14
scratch/check_opd_dose_when.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
$host = '127.0.0.1';
|
||||
$user = 'root';
|
||||
$pass = '';
|
||||
$dbname = 'hms_data_ci4';
|
||||
|
||||
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $user, $pass);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$stmt = $pdo->query("SELECT * FROM opd_dose_when");
|
||||
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
print_r($rows);
|
||||
14
scratch/check_opd_prescription_cols.php
Normal file
14
scratch/check_opd_prescription_cols.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
$conn = new mysqli('localhost', 'root', '', 'hms_ci4_2026');
|
||||
$tables = ['opd_prescrption_prescribed', 'opd_prescription_prescribed', 'opd_prescription_item'];
|
||||
|
||||
foreach ($tables as $t) {
|
||||
$res = $conn->query("SHOW TABLES LIKE '$t'");
|
||||
if ($res && $res->num_rows > 0) {
|
||||
echo "TABLE $t EXISTS:\n";
|
||||
$c = $conn->query("SHOW COLUMNS FROM $t");
|
||||
while ($r = $c->fetch_assoc()) {
|
||||
echo " - " . $r['Field'] . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
20
scratch/check_opd_table.php
Normal file
20
scratch/check_opd_table.php
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
$mysqli = new mysqli('localhost', 'root', '', 'hms_data_ci4');
|
||||
if ($mysqli->connect_error) {
|
||||
die("Connection failed: " . $mysqli->connect_error);
|
||||
}
|
||||
|
||||
$res = $mysqli->query("SELECT opd_id, opd_code, p_id, doc_id, apointment_date, opd_book_date, opd_status FROM opd_master ORDER BY opd_id DESC LIMIT 10");
|
||||
echo "\nLAST 10 OPD MASTER ROWS:\n";
|
||||
while ($row = $res->fetch_assoc()) {
|
||||
print_r($row);
|
||||
}
|
||||
|
||||
$today = date('Y-m-d');
|
||||
echo "\nTODAY DATE IS: " . $today . "\n";
|
||||
|
||||
foreach (['apointment_date', 'opd_book_date'] as $c) {
|
||||
$res = $mysqli->query("SELECT count(*) as count FROM opd_master WHERE DATE({$c}) = '{$today}'");
|
||||
$row = $res->fetch_assoc();
|
||||
echo "Count for DATE({$c}) = '{$today}': " . $row['count'] . "\n";
|
||||
}
|
||||
9
scratch/check_org_elements.php
Normal file
9
scratch/check_org_elements.php
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/package/package/StructureDefinition-Organization.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
$id = $el['id'];
|
||||
$min = $el['min'] ?? 0;
|
||||
$max = $el['max'] ?? '*';
|
||||
$type = isset($el['type']) ? implode(',', array_column($el['type'], 'code')) : '';
|
||||
echo sprintf("%-40s | %s..%s | %s\n", $id, $min, $max, $type);
|
||||
}
|
||||
7
scratch/check_org_must_support.php
Normal file
7
scratch/check_org_must_support.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/package/package/StructureDefinition-Organization.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if (str_starts_with($el['id'], 'Organization.address') || str_starts_with($el['id'], 'Organization.telecom')) {
|
||||
echo $el['id'] . ' | min:' . $el['min'] . ' | max:' . $el['max'] . ' | mustSupport:' . (!empty($el['mustSupport']) ? 'YES' : 'NO') . PHP_EOL;
|
||||
}
|
||||
}
|
||||
7
scratch/check_org_type_binding.php
Normal file
7
scratch/check_org_type_binding.php
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
$sd = json_decode(file_get_contents('ABDM_FHIR/package/package/StructureDefinition-Organization.json'), true);
|
||||
foreach ($sd['snapshot']['element'] as $el) {
|
||||
if ($el['id'] === 'Organization.type') {
|
||||
echo json_encode($el['binding'] ?? [], JSON_PRETTY_PRINT) . "\n";
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user