diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml new file mode 100644 index 00000000..f0ed48e4 --- /dev/null +++ b/.github/workflows/commit-lint.yml @@ -0,0 +1,34 @@ +name: Commit Compliance + +on: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + commitlint: + runs-on: ubuntu-latest + + steps: + - name: Checkout code with submodule + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + submodules: true + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Install dependencies + run: | + npm ci --legacy-peer-deps + npm i --legacy-peer-deps + + - name: Run commitlint on PR + run: | + npx commitlint --from ${{ github.event.pull_request.base.sha }} \ + --to ${{ github.event.pull_request.head.sha }} \ + --verbose diff --git a/.gitignore b/.gitignore index 769653c4..5a1e6d24 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ mvnw mvnw.cmd .mvn /logs/ +src/main/environment/common_local.properties +node_modules diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 00000000..34eed8b2 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1 @@ +npx --no -- commitlint --edit $1 \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..d0a77842 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npx lint-staged \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index f99697fa..417c00e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,8 @@ FROM eclipse-temurin:17-jre WORKDIR /app +ENV TZ=Asia/Kolkata + # Copy the built WAR file from the build stage COPY --from=build /app/target/*.war app.war diff --git a/README.md b/README.md index 560f69a7..5c992214 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,49 @@ This repository comprises of all APIs related to FLW Mobile App. Flw-API is a microservice which is used for the creation and management of beneficiaries related data +## Setting Up Commit Hooks + +This project uses Git hooks to enforce consistent code quality and commit message standards. Even though this is a Java project, the hooks are powered by Node.js. Follow these steps to set up the hooks locally: + +### Prerequisites +- Node.js (v14 or later) +- npm (comes with Node.js) + +### Setup Steps + +1. **Install Node.js and npm** + - Download and install from [nodejs.org](https://nodejs.org/) + - Verify installation with: + ``` + node --version + npm --version + ``` +2. **Install dependencies** + - From the project root directory, run: + ``` + npm ci + ``` + - This will install all required dependencies including Husky and commitlint +3. **Verify hooks installation** + - The hooks should be automatically installed by Husky + - You can verify by checking if the `.husky` directory contains executable hooks +### Commit Message Convention +This project follows a specific commit message format: +- Format: `type(scope): subject` +- Example: `feat(login): add remember me functionality` +Types include: +- `feat`: A new feature +- `fix`: A bug fix +- `docs`: Documentation changes +- `style`: Code style changes (formatting, etc.) +- `refactor`: Code changes that neither fix bugs nor add features +- `perf`: Performance improvements +- `test`: Adding or fixing tests +- `build`: Changes to build process or tools +- `ci`: Changes to CI configuration +- `chore`: Other changes (e.g., maintenance tasks, dependencies) +Your commit messages will be automatically validated when you commit, ensuring project consistency. + ## Filing Issues If you encounter any issues, bugs, or have feature requests, please file them in the [main AMRIT repository](https://github.com/PSMRI/AMRIT/issues). Centralizing all feedback helps us streamline improvements and address concerns efficiently. diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 00000000..e65d7e68 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,36 @@ +module.exports = { + extends: ['@commitlint/config-conventional'], + rules: { + 'body-leading-blank': [1, 'always'], + 'body-max-line-length': [2, 'always', 100], + 'footer-leading-blank': [1, 'always'], + 'footer-max-line-length': [2, 'always', 100], + 'header-max-length': [2, 'always', 100], + 'subject-case': [ + 2, + 'never', + ['sentence-case', 'start-case', 'pascal-case', 'upper-case'], + ], + 'subject-empty': [2, 'never'], + 'subject-full-stop': [2, 'never', '.'], + 'type-case': [2, 'always', 'lower-case'], + 'type-empty': [2, 'never'], + 'type-enum': [ + 2, + 'always', + [ + 'build', + 'chore', + 'ci', + 'docs', + 'feat', + 'fix', + 'perf', + 'refactor', + 'revert', + 'style', + 'test', + ], + ], + } +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..d11ee7ec --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3433 @@ +{ + "name": "flw-api", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "flw-api", + "version": "1.0.0", + "devDependencies": { + "@commitlint/cli": "^19.8.0", + "@commitlint/config-conventional": "^19.8.0", + "commitizen": "^4.3.1", + "cz-conventional-changelog": "^3.3.0", + "husky": "^9.1.7", + "lint-staged": "^15.5.1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@commitlint/cli": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.8.1.tgz", + "integrity": "sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/format": "^19.8.1", + "@commitlint/lint": "^19.8.1", + "@commitlint/load": "^19.8.1", + "@commitlint/read": "^19.8.1", + "@commitlint/types": "^19.8.1", + "tinyexec": "^1.0.0", + "yargs": "^17.0.0" + }, + "bin": { + "commitlint": "cli.js" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-19.8.1.tgz", + "integrity": "sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "conventional-changelog-conventionalcommits": "^7.0.2" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-19.8.1.tgz", + "integrity": "sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/ensure": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-19.8.1.tgz", + "integrity": "sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "lodash.camelcase": "^4.3.0", + "lodash.kebabcase": "^4.1.1", + "lodash.snakecase": "^4.1.1", + "lodash.startcase": "^4.4.0", + "lodash.upperfirst": "^4.3.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-19.8.1.tgz", + "integrity": "sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-19.8.1.tgz", + "integrity": "sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-19.8.1.tgz", + "integrity": "sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/lint": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-19.8.1.tgz", + "integrity": "sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^19.8.1", + "@commitlint/parse": "^19.8.1", + "@commitlint/rules": "^19.8.1", + "@commitlint/types": "^19.8.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-19.8.1.tgz", + "integrity": "sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^19.8.1", + "@commitlint/execute-rule": "^19.8.1", + "@commitlint/resolve-extends": "^19.8.1", + "@commitlint/types": "^19.8.1", + "chalk": "^5.3.0", + "cosmiconfig": "^9.0.0", + "cosmiconfig-typescript-loader": "^6.1.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "lodash.uniq": "^4.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/message": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-19.8.1.tgz", + "integrity": "sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/parse": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-19.8.1.tgz", + "integrity": "sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^19.8.1", + "conventional-changelog-angular": "^7.0.0", + "conventional-commits-parser": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/read": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-19.8.1.tgz", + "integrity": "sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/top-level": "^19.8.1", + "@commitlint/types": "^19.8.1", + "git-raw-commits": "^4.0.0", + "minimist": "^1.2.8", + "tinyexec": "^1.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/resolve-extends": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-19.8.1.tgz", + "integrity": "sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^19.8.1", + "@commitlint/types": "^19.8.1", + "global-directory": "^4.0.1", + "import-meta-resolve": "^4.0.0", + "lodash.mergewith": "^4.6.2", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/rules": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-19.8.1.tgz", + "integrity": "sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/ensure": "^19.8.1", + "@commitlint/message": "^19.8.1", + "@commitlint/to-lines": "^19.8.1", + "@commitlint/types": "^19.8.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/to-lines": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-19.8.1.tgz", + "integrity": "sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/top-level": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-19.8.1.tgz", + "integrity": "sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^7.0.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/types": { + "version": "19.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-19.8.1.tgz", + "integrity": "sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/conventional-commits-parser": "^5.0.0", + "chalk": "^5.3.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@types/conventional-commits-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz", + "integrity": "sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "24.5.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz", + "integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.12.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/commitizen": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.1.tgz", + "integrity": "sha512-gwAPAVTy/j5YcOOebcCRIijn+mSjWJC+IYKivTu6aG8Ei/scoXgfsMRnuAk6b0GRste2J4NGxVdMN3ZpfNaVaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cachedir": "2.3.0", + "cz-conventional-changelog": "3.3.0", + "dedent": "0.7.0", + "detect-indent": "6.1.0", + "find-node-modules": "^2.1.2", + "find-root": "1.1.0", + "fs-extra": "9.1.0", + "glob": "7.2.3", + "inquirer": "8.2.5", + "is-utf8": "^0.2.1", + "lodash": "4.17.21", + "minimist": "1.2.7", + "strip-bom": "4.0.0", + "strip-json-comments": "3.1.1" + }, + "bin": { + "commitizen": "bin/commitizen", + "cz": "bin/git-cz", + "git-cz": "bin/git-cz" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/commitizen/node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/conventional-changelog-angular": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz", + "integrity": "sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz", + "integrity": "sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/conventional-commit-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-3.0.0.tgz", + "integrity": "sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==", + "dev": true, + "license": "ISC" + }, + "node_modules/conventional-commits-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz", + "integrity": "sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-text-path": "^2.0.0", + "JSONStream": "^1.3.5", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "conventional-commits-parser": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig-typescript-loader": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz", + "integrity": "sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jiti": "^2.4.1" + }, + "engines": { + "node": ">=v18" + }, + "peerDependencies": { + "@types/node": "*", + "cosmiconfig": ">=9", + "typescript": ">=5" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cz-conventional-changelog": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", + "integrity": "sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "commitizen": "^4.0.3", + "conventional-commit-types": "^3.0.0", + "lodash.map": "^4.5.1", + "longest": "^2.0.1", + "word-wrap": "^1.0.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@commitlint/load": ">6.1.1" + } + }, + "node_modules/cz-conventional-changelog/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cz-conventional-changelog/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dargs": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-8.1.0.tgz", + "integrity": "sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true, + "license": "MIT" + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-node-modules": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/find-node-modules/-/find-node-modules-2.1.3.tgz", + "integrity": "sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "findup-sync": "^4.0.0", + "merge": "^2.1.1" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true, + "license": "MIT" + }, + "node_modules/find-up": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz", + "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.2.0", + "path-exists": "^5.0.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-raw-commits": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", + "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dargs": "^8.0.0", + "meow": "^12.0.1", + "split2": "^4.0.0" + }, + "bin": { + "git-raw-commits": "cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", + "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-text-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", + "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "text-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.0.tgz", + "integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.mergewith": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", + "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-escapes": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz", + "integrity": "sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.5.0.tgz", + "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/longest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-2.0.1.tgz", + "integrity": "sha512-Ajzxb8CM6WAnFjgiloPsI3bF+WCxcvhdIG3KNA2KN962+tdBsHcuQ4k4qX/EcS/2CRkcc0iAkR956Nib6aXU/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", + "integrity": "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/text-extensions": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", + "integrity": "sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz", + "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..bf8bff9d --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "flw-api", + "version": "1.0.0", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "prepare": "husky", + "commit": "cz" + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } + }, + "lint-staged": { + "src/**/*.{ts,js}": [ + "eslint --fix" + ], + "*.xml": [ + "xmllint --noout {{files}}" + ] + }, + "devDependencies": { + "@commitlint/cli": "^19.8.0", + "@commitlint/config-conventional": "^19.8.0", + "commitizen": "^4.3.1", + "cz-conventional-changelog": "^3.3.0", + "husky": "^9.1.7", + "lint-staged": "^15.5.1" + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 512a160b..576c0cdf 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iemr.common.flw flw-api - 3.10.0 + 3.8.2 war FLW-API @@ -337,6 +337,32 @@ + + io.github.git-commit-id + git-commit-id-maven-plugin + 9.0.2 + + + get-the-git-infos + + revision + + initialize + + + + true + ${project.build.outputDirectory}/git.properties + + ^git.branch$ + ^git.commit.id.abbrev$ + ^git.build.version$ + ^git.build.time$ + + false + false + + org.apache.maven.plugins maven-antrun-plugin @@ -420,4 +446,4 @@ - \ No newline at end of file + diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 347e06a3..8d24ebe9 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -16,8 +16,7 @@ secondary.datasource.password=@env.DATABASE_IDENTITY_PASSWORD@ secondary.datasource.url=@env.DATABASE_IDENTITY_URL@ secondary.datasource.driver-class-name=com.mysql.jdbc.Driver -springdoc.api-docs.enabled=@env.SWAGGER_UI_ENABLED@ -springdoc.swagger-ui.enabled=@env.SWAGGER_UI_ENABLED@ + #ELK logging file name logging.path=logs/ @@ -28,6 +27,9 @@ jwt.secret=@env.JWT_SECRET_KEY@ # Redis Config spring.redis.host=@env.REDIS_HOST@ +# Stop TB: when true, saves fail with an error if camp (vanID) is not configured +stoptb.enforce.vanid=@env.STOPTB_ENFORCE_VANID@ + cors.allowed-origins=@env.CORS_ALLOWED_ORIGINS@ #### SMS Configuration @@ -37,4 +39,17 @@ sms-username=@env.SMS_USERNAME@ sms-password=@env.SMS_PASSWORD@ send-message-url=@env.SMS_MESSAGE_URL@ -crash.logs.base.path=@env.CRASH_LOGS_PATH@ +#crash.logs.base.path=@env.CRASH_LOGS_PATH@ + +# ABHA Token Config +abha.client.id=@env.ABHA_CLIENT_ID@ +abha.client.secret=@env.ABHA_CLIENT_SECRET@ +abha.token.url=@env.ABHA_TOKEN_URL@ +abha.xcmid=@env.ABHA_XCM_ID@ + +# GovThealth API Config +govthealth.user.details.url=@env.GOVTHEALTH_USER_DETAILS_URL@ +govthealth.user.id=@env.GOVTHEALTH_USER_ID@ +govthealth.password=@env.GOVTHEALTH_PASSWORD@ + + diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index 958a9a19..c021fc52 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -1,5 +1,5 @@ -fhir-url = ${FHIR_URL} -tm-url = ${TM_URL} +fhir-url = ${FHIR_API} +tm-url = ${TM_API} ##--------------------------------------------## Primary db------------------------------------------------------------------- @@ -15,8 +15,8 @@ secondary.datasource.password=${DATABASE_IDENTITY_PASSWORD} secondary.datasource.url=${DATABASE_IDENTITY_URL} secondary.datasource.driver-class-name=com.mysql.jdbc.Driver -springdoc.api-docs.enabled=true -springdoc.swagger-ui.enabled=true + + #ELK logging file name logging.path=logs/ @@ -27,6 +27,9 @@ jwt.secret=${JWT_SECRET_KEY} # Redis Config spring.redis.host=${REDIS_HOST} +# Stop TB: when true, saves fail with an error if camp (vanID) is not configured +stoptb.enforce.vanid=${STOPTB_ENFORCE_VANID} + #### SMS Configuration send-sms=${SEND_SMS} source-address=${SMS_CONSENT_SOURCE_ADDRESS} @@ -35,4 +38,18 @@ sms-password=${SMS_PASSWORD} send-message-url=${SMS_MESSAGE_URL} -crash.logs.base.path=${CRASH_LOGS_PATH} +#crash.logs.base.path=${CRASH_LOGS_PATH} + +# ABHA Token Config +abha.client.id=${ABHA_CLIENT_ID} +abha.client.secret=${ABHA_CLIENT_SECRET} +abha.token.url=${ABHA_TOKEN_URL} +abha.xcmid=${ABHA_XCM_ID} + +# GovThealth API Config +govthealth.user.details.url=${GOVTHEALTH_USER_DETAILS_URL} +govthealth.user.id=${GOVTHEALTH_USER_ID} +govthealth.password=${GOVTHEALTH_PASSWORD} + + + diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 51873ab6..7e8d43b0 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -24,11 +24,17 @@ springdoc.swagger-ui.enabled=true logging.path=logs/ logging.file.name=logs/flw-api.log -jwt.secret=my-32-character-ultra-secure-and-ultra-long-secret + +jwt.secret=eefa40497bb9b2a8491b85069aff62e7596521c6816e471c464181b52eac7670ff91394a + # Redis Config spring.redis.host=localhost +# Stop TB: when true, saves fail with an error if camp (vanID) is not configured +# instead of silently storing vanID=NULL (which then never gets synced to central) +stoptb.enforce.vanid=false + cors.allowed-origins=http://localhost:* source-address= @@ -38,6 +44,12 @@ send-message-url= crash.logs.base.path= +# ABHA Token Config +abha.client.id= +abha.client.secret= +abha.token.url= +abha.xcmid= + diff --git a/src/main/environment/common_local.properties b/src/main/environment/common_local.properties.bkp similarity index 91% rename from src/main/environment/common_local.properties rename to src/main/environment/common_local.properties.bkp index 6e5bdd00..b6463a03 100644 --- a/src/main/environment/common_local.properties +++ b/src/main/environment/common_local.properties.bkp @@ -43,3 +43,7 @@ get-HRP-Status=ANC/getHRPStatus #Get Beneficiary ABHA getHealthID=healthID/getBenhealthID + +# TM API URL +tm-url=https://amritdemo.piramalswasthya.org/tm-api +jwt.secret=eefa40497bb9b2a8491b85069aff62e7596521c6816e471c464181b52eac7670ff91394a diff --git a/src/main/java/com/iemr/flw/controller/AbhaBeneficiaryController.java b/src/main/java/com/iemr/flw/controller/AbhaBeneficiaryController.java new file mode 100644 index 00000000..8025de55 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/AbhaBeneficiaryController.java @@ -0,0 +1,54 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.domain.iemr.AdolescentHealth; +import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; +import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.AbhaRequestDTO; +import com.iemr.flw.service.AbhaBeneficiaryService; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/UserRegistration") +public class AbhaBeneficiaryController { + @Autowired + private AbhaBeneficiaryService abhaBeneficiaryService; + + private final org.slf4j.Logger logger = LoggerFactory.getLogger(AbhaBeneficiaryController.class); + + + + @RequestMapping(value = "/GetUserDetailsByAyushmanCardNo",method = RequestMethod.POST) + public ResponseEntity> getAllAdolescentHealth(@RequestBody AbhaRequestDTO request ) { + Map response = new HashMap<>(); + try { + if(request.getCardNo()!=null){ + Object abhaBeneficiaryDTOList = abhaBeneficiaryService.getBeneficiaryByAbha(request); + + if (abhaBeneficiaryDTOList != null ) { + response.put("statusCode",200); + response.put("data", abhaBeneficiaryDTOList); + } else { + response.put("statusCode", 5000); + response.put("error", "Invalid/NULL request obj"); + } + } + + } catch (Exception e) { + logger.error("Error in get data : " + e); + response.put("statusCode",5000); + response.put("error","Error in get data : " + e); + + } + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/iemr/flw/controller/AbhaTokenController.java b/src/main/java/com/iemr/flw/controller/AbhaTokenController.java new file mode 100644 index 00000000..5197ddf2 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/AbhaTokenController.java @@ -0,0 +1,40 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.service.AbhaTokenService; +import com.iemr.flw.utils.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping(value = "/abha", headers = "Authorization") +public class AbhaTokenController { + + private final Logger logger = LoggerFactory.getLogger(AbhaTokenController.class); + + @Autowired + private AbhaTokenService abhaTokenService; + + @Operation(summary = "Get ABHA access token") + @PostMapping("/token") + public ResponseEntity getAbhaToken( + @RequestHeader(value = "Authorization") String authorization) { + try { + Map tokenResponse = abhaTokenService.getAbhaToken(); + return new ResponseEntity<>( + new ApiResponse(true, null, tokenResponse), HttpStatus.OK); + } catch (Exception e) { + logger.error("Error fetching ABHA token: " + e.getMessage()); + return new ResponseEntity<>( + new ApiResponse(false, "Error fetching ABHA token: " + e.getMessage(), null), + HttpStatus.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/src/main/java/com/iemr/flw/controller/AshaProfileController.java b/src/main/java/com/iemr/flw/controller/AshaProfileController.java index 1bda4499..2d02ce23 100644 --- a/src/main/java/com/iemr/flw/controller/AshaProfileController.java +++ b/src/main/java/com/iemr/flw/controller/AshaProfileController.java @@ -1,35 +1,21 @@ package com.iemr.flw.controller; import com.iemr.flw.domain.iemr.AshaWorker; -import com.iemr.flw.domain.iemr.M_User; -import com.iemr.flw.dto.iemr.UserServiceRoleDTO; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.AshaProfileService; import com.iemr.flw.service.EmployeeMasterInter; -import com.iemr.flw.service.UserService; import io.lettuce.core.dynamic.annotation.Param; import com.iemr.flw.utils.JwtUtil; -import io.swagger.v3.oas.annotations.Operation; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -import com.iemr.flw.utils.JwtAuthenticationUtil; -import com.iemr.flw.utils.JwtUtil; -import com.iemr.flw.utils.exception.IEMRException; -import io.jsonwebtoken.Claims; -import io.swagger.v3.oas.annotations.Operation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; -import java.util.Objects; @RestController @RequestMapping(value = "/asha", produces = "application/json") @@ -76,18 +62,18 @@ public ResponseEntity> getProfile(HttpServletRequest request try { String jwtFromHeader = request.getHeader("JwtToken"); - // Validate JWT header presence -// if (jwtFromHeader == null || jwtFromHeader.trim().isEmpty()) { -// response.put("statusCode", 401); -// response.put("status", "Unauthorized"); -// response.put("errorMessage", "JWT token is missing"); -// return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); -// } +// Validate JWT header presence + if (jwtFromHeader == null || jwtFromHeader.trim().isEmpty()) { + response.put("statusCode", 401); + response.put("status", "Unauthorized"); + response.put("errorMessage", "JWT token is missing"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); + } // Extract and validate user ID from JWT - // int userId = jwtUtil.extractUserId(jwtFromHeader); // Make sure this returns 0 or throws for invalid token + int userId = jwtUtil.extractUserId(jwtFromHeader); // Make sure this returns 0 or throws for invalid token - if (employeeId == 0) { + if (userId == 0) { response.put("statusCode", 401); response.put("status", "Unauthorized"); response.put("errorMessage", "Invalid JWT token"); @@ -95,7 +81,7 @@ public ResponseEntity> getProfile(HttpServletRequest request } // Business logic - AshaWorker ashaWorker = ashaProfileService.getProfileData(employeeId); + AshaWorker ashaWorker = ashaProfileService.getProfileData(userId); logger.info("Asha Profile"+ashaWorker); response.put("statusCode", 200); diff --git a/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java new file mode 100644 index 00000000..3f840f61 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/AshaSupervisorIncentiveApproval.java @@ -0,0 +1,123 @@ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.iemr.AshaByFacilityRequestDTO; +import com.iemr.flw.dto.iemr.UpdateApprovalRequestDTO; +import com.iemr.flw.service.SupervisorDashboardService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.response.OutputResponse; +import io.swagger.v3.oas.annotations.Operation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +@RestController +@RequestMapping("/ashaSupervisor") +public class AshaSupervisorIncentiveApproval { + + @Autowired + private SupervisorDashboardService supervisorDashboardService; + + @Autowired + private JwtUtil jwtUtil; + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + + @PostMapping("/getAshaListByFacility") + public ResponseEntity getAshaListByFacility( + @RequestBody AshaByFacilityRequestDTO request, + @RequestHeader(value = "JwtToken") String token) { + + try { + + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("UNAUTHORIZED"); + } + + Map result = supervisorDashboardService.getAshasAtFacility( + jwtUtil.extractUserId(token), + request.getFacilityId(), + request.getMonth(), + request.getYear(), + request.getApprovalStatus() + ); + + logger.info("result {}", result); + + return ResponseEntity.status(HttpStatus.OK).body(result); + + } catch (Exception e) { + + logger.error("Error in getAshaListByFacility", e); + + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Server error: " + e.getMessage()); + } + } + + + + + @Operation(summary = "Get comprehensive ASHA Supervisor dashboard with facilities, ASHAs, villages and incentive data") + @PostMapping("/dashboard") + public String getSupervisorDashboard(@RequestBody AshaByFacilityRequestDTO request,@RequestHeader(value = "JwtToken") String token ) { + OutputResponse response = new OutputResponse(); + + try { + if(token!=null){ + String result = supervisorDashboardService.getSupervisorDashboard(jwtUtil.extractUserId(token),request.getMonth(),request.getYear()); + response.setResponse(result); + } + + } catch (Exception e) { + logger.error("getSupervisorDashboard failed: " + e.getMessage(), e); + response.setError(e); + } + return response.toString(); + } + + @PostMapping("/updateApprovalStatus") + public ResponseEntity updateApprovalStatus( + @RequestBody UpdateApprovalRequestDTO request, + @RequestHeader(value = "JwtToken") String token) { + + try { + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("UNAUTHORIZED"); + } + + int updatedRows = supervisorDashboardService.updateApprovalStatus( + request.getAshaId(), + request.getMonth(), + request.getYear(), + request.getApprovalStatus(), + request.getIncentiveIds(), + request.getReason(), + request.getOtherReason(), + token + ); + + Map response = new HashMap<>(); + response.put("statusCode", 200); + response.put("updatedRecords", updatedRows); + + return ResponseEntity.ok(response); + + } catch (Exception e) { + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Server error: " + e.getMessage()); + } + } + + +} diff --git a/src/main/java/com/iemr/flw/controller/BeneficiaryController.java b/src/main/java/com/iemr/flw/controller/BeneficiaryController.java index dd083840..d439fbf5 100644 --- a/src/main/java/com/iemr/flw/controller/BeneficiaryController.java +++ b/src/main/java/com/iemr/flw/controller/BeneficiaryController.java @@ -40,10 +40,13 @@ public class BeneficiaryController { @Autowired private MdaFormSubmissionService mdaFormSubmissionService; + @Autowired + private JwtUtil jwtUtil; + @RequestMapping(value = "/getBeneficiaryData", method = RequestMethod.POST) @Operation(summary = "get beneficiary data for given user ") public String getBeneficiaryDataByAsha(@RequestBody GetBenRequestHandler requestDTO, - @RequestHeader(value = "Authorization") String authorization) { + @RequestHeader(value = "Authorization") String authorization) { OutputResponse response = new OutputResponse(); try { @@ -65,8 +68,9 @@ public String getBeneficiaryDataByAsha(@RequestBody GetBenRequestHandler request return response.toString(); } + @RequestMapping(value = {"/eye_surgery/saveAll"}, method = RequestMethod.POST) - public ResponseEntity saveEyeSurgery(@RequestBody List eyeCheckupRequestDTOS) { + public ResponseEntity saveEyeSurgery(@RequestBody List eyeCheckupRequestDTOS, @RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("Eye Checkup Save Request: {}", eyeCheckupRequestDTOS); @@ -77,7 +81,7 @@ public ResponseEntity saveEyeSurgery(@RequestBody List return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); } - String responseObject = beneficiaryService.saveEyeCheckupVsit(eyeCheckupRequestDTOS); + String responseObject = beneficiaryService.saveEyeCheckupVsit(eyeCheckupRequestDTOS, token); if (responseObject != null) { response.put("statusCode", HttpStatus.OK.value()); @@ -91,47 +95,102 @@ public ResponseEntity saveEyeSurgery(@RequestBody List } catch (Exception e) { logger.error("Error saving eye checkup visit:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + return ResponseEntity.ok(response); } } - @RequestMapping(value = {"/eye_surgery/getAll"}, method = RequestMethod.POST) - public ResponseEntity getAllEyeSurgery(@RequestBody GetBenRequestHandler request) { + public ResponseEntity getAllEyeSurgery(@RequestBody GetBenRequestHandler request, @RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("Eye Checkup Get Request: {}", request); try { - List responseObject = beneficiaryService.getEyeCheckUpVisit(request); + List responseObject = beneficiaryService.getEyeCheckUpVisit(request, token); if (responseObject != null && !responseObject.isEmpty()) { response.put("statusCode", HttpStatus.OK.value()); response.put("data", responseObject); return ResponseEntity.ok(response); } else { - response.put("statusCode", HttpStatus.NOT_FOUND.value()); + response.put("statusCode", 5000); response.put("message", "No records found"); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + return ResponseEntity.ok(response); } } catch (Exception e) { logger.error("Error fetching eye checkup visit:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + return ResponseEntity.ok(response); } } - @RequestMapping(value = "/ifa/saveAll",method = RequestMethod.POST) - public ResponseEntity saveFormData(@RequestBody List requests) { - String message = ifaFormSubmissionService.saveFormData(requests); - return ResponseEntity.ok(Map.of("success", true, "message", message)); + @RequestMapping(value = "/ifa/saveAll", method = RequestMethod.POST) + public ResponseEntity saveIfaFormData( + @RequestBody List requests, + @RequestHeader(value = "JwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + logger.info("IFA Save Request: {}", requests); + + try { + + if (requests == null || requests.isEmpty()) { + + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Request body cannot be empty"); + + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(response); + } + if (token != null) { + String message = + ifaFormSubmissionService.saveFormData(requests, jwtUtil.extractUserId(token)); + + if (message != null) { + + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", message); + + return ResponseEntity.ok(response); + + } else { + + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save records"); + + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) + .body(response); + } + } else { + response.put("statusCode", HttpStatus.UNAUTHORIZED.value()); + response.put("message", "UNAUTHORIZED"); + + return ResponseEntity + .status(HttpStatus.UNAUTHORIZED) + .body(response); + } + + + } catch (Exception e) { + + logger.error("Error saving IFA records:", e); + + response.put("statusCode", 5000); + response.put("errorMessage", e.getMessage()); + + return ResponseEntity.ok(response); + + } } - @RequestMapping(value = "ifa/getAll",method = RequestMethod.POST) + @RequestMapping(value = "ifa/getAll", method = RequestMethod.POST) public ResponseEntity getFormData(@RequestBody GetBenRequestHandler getBenRequestHandler) { var data = ifaFormSubmissionService.getFormData(getBenRequestHandler); return ResponseEntity.ok(Map.of("success", true, "message", "Data fetched successfully", "data", data)); @@ -139,15 +198,15 @@ public ResponseEntity getFormData(@RequestBody GetBenRequestHandler getBenReq @RequestMapping(value = "/mda/saveAll", method = RequestMethod.POST) public ResponseEntity saveFormData(@RequestBody List requests, - @RequestHeader(value = "Authorization") String authorization) { + @RequestHeader(value = "Authorization") String authorization) { String message = mdaFormSubmissionService.saveFormData(requests); return ResponseEntity.ok(Map.of("success", true, "message", message)); } @RequestMapping(value = "/mda/getAll", method = RequestMethod.POST) public ResponseEntity getFormDataByCreatedBy(@RequestBody Map request, - @RequestHeader(value = "Authorization") String authorization) { - String userName = request.get("userName") ; + @RequestHeader(value = "Authorization") String authorization) { + String userName = request.get("userName"); var data = mdaFormSubmissionService.getFormDataByUserName(userName); return ResponseEntity.ok(Map.of("success", true, "message", "Data fetched successfully", "data", data)); } diff --git a/src/main/java/com/iemr/flw/controller/CampaignController.java b/src/main/java/com/iemr/flw/controller/CampaignController.java new file mode 100644 index 00000000..f5f13d69 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/CampaignController.java @@ -0,0 +1,360 @@ +package com.iemr.flw.controller; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.iemr.flw.domain.iemr.CampaignOrs; +import com.iemr.flw.domain.iemr.FilariasisCampaign; +import com.iemr.flw.domain.iemr.PulsePolioCampaign; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.service.CampaignService; +import com.iemr.flw.utils.exception.IEMRException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.sql.Timestamp; +import java.util.*; + +@RestController +@RequestMapping(value = "/campaign") +public class CampaignController { + private final Logger logger = LoggerFactory.getLogger(CampaignController.class); + + @Autowired + private CampaignService campaignService; + + @PostMapping("/ors/distribution/saveAll") + public ResponseEntity> saveOrsDistribution( + @RequestPart("formDataJson") String fields, + @RequestHeader("jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + + // Validate input + if (fields == null || fields.trim().isEmpty()) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Form data is required"); + return ResponseEntity.badRequest().body(response); + } + + // Parse JSON to DTO + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + OrsCampaignDTO requestDTO = objectMapper.readValue(fields, OrsCampaignDTO.class); + + // Validate fields + if (requestDTO.getFields() == null) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Campaign fields are required"); + return ResponseEntity.badRequest().body(response); + } + + logger.info("Parsed DTO - Start Date: {}, End Date: {}, Families: {}, Photos: {}", + requestDTO.getFields().getStartDate(), + requestDTO.getFields().getEndDate(), + requestDTO.getFields().getNumberOfFamilies(), + requestDTO.getFields().getCampaignPhotos() + ); + + // Create DTO + OrsCampaignDTO campaignDTO = new OrsCampaignDTO(); + campaignDTO.setFields(requestDTO.getFields()); + + List orsCampaignDTOList = Collections.singletonList(campaignDTO); + + // Save to database + List result = campaignService.saveOrsCampaign(orsCampaignDTOList, token); + + if (result != null && !result.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "Campaign saved successfully"); + response.put("data", result); + return ResponseEntity.status(HttpStatus.OK).body(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save campaign"); + return ResponseEntity.badRequest().body(response); + } + + } catch (JsonProcessingException e) { + logger.error("JSON parsing error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Invalid JSON format"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (IEMRException e) { + logger.error("Business logic error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (Exception e) { + logger.error("Error saving ORS distribution: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "Internal server error occurred"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @RequestMapping(value = "ors/distribution/getAll", method = RequestMethod.POST) + public ResponseEntity> getAllOrsDistribution(@RequestHeader(value = "jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + List result = campaignService.getOrsCampaign(token); + + + if (result != null) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("data", result); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "No records found"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + + } catch (Exception e) { + logger.error("Error save ors distribution :", e.getMessage()); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @PostMapping("/polio/campaign/saveAll") + public ResponseEntity> savePolioCampaign( + @RequestPart("formDataJson") String fields, + @RequestHeader("jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + logger.info("Received polio campaign data"); + + // Validate input + if (fields == null || fields.trim().isEmpty()) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Form data is required"); + return ResponseEntity.badRequest().body(response); + } + + // Parse JSON to DTO + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + PolioCampaignDTO requestDTO = objectMapper.readValue(fields, PolioCampaignDTO.class); + + // Validate fields + if (requestDTO.getFields() == null) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Campaign fields are required"); + return ResponseEntity.badRequest().body(response); + } + + logger.info("Parsed DTO - Start Date: {}, End Date: {}, Families: {}, Individuals: {}, Photos: {}", + requestDTO.getFields().getStartDate(), + requestDTO.getFields().getEndDate(), + requestDTO.getFields().getNumberOfChildren(), + + requestDTO.getFields().getCampaignPhotos() + ); + + // Create DTO + PolioCampaignDTO campaignDTO = new PolioCampaignDTO(); + campaignDTO.setFields(requestDTO.getFields()); + + List polioCampaignDTOList = Collections.singletonList(campaignDTO); + + // Save to database + List result = campaignService.savePolioCampaign(polioCampaignDTOList, token); + + if (result != null && !result.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "polio campaign saved successfully"); + response.put("data", result); + return ResponseEntity.status(HttpStatus.OK).body(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save Polio campaign"); + return ResponseEntity.badRequest().body(response); + } + + } catch (JsonProcessingException e) { + logger.error("JSON parsing error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Invalid JSON format"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (IEMRException e) { + logger.error("Business logic error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (Exception e) { + logger.error("Error saving filariasis campaign: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "Internal server error occurred"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @RequestMapping(value = "polio/campaign/getAll", method = RequestMethod.POST) + public ResponseEntity> getAllPolioCampaign(@RequestHeader(value = "jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + List result = campaignService.getPolioCampaign(token); + + + if (result != null) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("data", result); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "No records found"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + + } catch (Exception e) { + logger.error("Error save ors distribution :", e.getMessage()); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @PostMapping("/filariasis/campaign/saveAll") + public ResponseEntity> saveFilariasisCampaign( + @RequestPart("formDataJson") String fields, + @RequestHeader("jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + logger.info("Received polio campaign data"); + + // Validate input + if (fields == null || fields.trim().isEmpty()) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Form data is required"); + return ResponseEntity.badRequest().body(response); + } + + // Parse JSON to DTO + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + FilariasisCampaignDTO requestDTO = objectMapper.readValue(fields, FilariasisCampaignDTO.class); + + // Validate fields + if (requestDTO.getFields() == null) { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Campaign fields are required"); + return ResponseEntity.badRequest().body(response); + } + + logger.info("Parsed DTO - Start Date: {}, End Date: {}, Families: {}, Individuals: {}, Photos: {}", + requestDTO.getFields().getStartDate(), + requestDTO.getFields().getEndDate(), + requestDTO.getFields().getNumberOfIndividuals(), + requestDTO.getFields().getNumberOfIndividuals(), + + requestDTO.getFields().getMdaPhotos() + ); + + // Create DTO + FilariasisCampaignDTO campaignDTO = new FilariasisCampaignDTO(); + campaignDTO.setFields(requestDTO.getFields()); + + List filariasisCampaignDTOS = Collections.singletonList(campaignDTO); + + + // Save to database + List result = campaignService.saveFilariasisCampaign(filariasisCampaignDTOS, token); + + if (result != null && !result.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "filariasis campaign saved successfully"); + response.put("data", result); + return ResponseEntity.status(HttpStatus.OK).body(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save filariasis campaign"); + return ResponseEntity.badRequest().body(response); + } + + } catch (JsonProcessingException e) { + logger.error("JSON parsing error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Invalid JSON format"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (IEMRException e) { + logger.error("Business logic error: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", e.getMessage()); + return ResponseEntity.badRequest().body(response); + + } catch (Exception e) { + logger.error("Error saving filariasis campaign: {}", e.getMessage(), e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "Internal server error occurred"); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + + @RequestMapping(value = "filariasis/campaign/getAll", method = RequestMethod.POST) + public ResponseEntity> getAllFilariasisCampaign(@RequestHeader(value = "jwtToken") String token) { + + Map response = new LinkedHashMap<>(); + + try { + List result = campaignService.getAllFilariasisCampaign(token); + + + if (result != null) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("data", result); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("message", "No records found"); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + + } catch (Exception e) { + logger.error("Error save ors distribution :", e.getMessage()); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } +} diff --git a/src/main/java/com/iemr/flw/controller/ChildCareController.java b/src/main/java/com/iemr/flw/controller/ChildCareController.java index d5e4335f..bbc9cba2 100644 --- a/src/main/java/com/iemr/flw/controller/ChildCareController.java +++ b/src/main/java/com/iemr/flw/controller/ChildCareController.java @@ -7,14 +7,19 @@ import com.iemr.flw.domain.iemr.HbncVisit; import com.iemr.flw.domain.iemr.IfaDistribution; import com.iemr.flw.domain.iemr.SamVisitResponseDTO; +import com.iemr.flw.domain.iemr.UserServiceRole; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.ChildCareService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; import com.iemr.flw.utils.response.OutputResponse; import io.swagger.v3.oas.annotations.Operation; import jakarta.mail.Multipart; +import org.checkerframework.checker.units.qual.A; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -37,10 +42,18 @@ public class ChildCareController { @Autowired private ChildCareService childCareService; + @Autowired + private UserService userService; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; @Operation(summary = "save HBYC details") @RequestMapping(value = {"/hbycVisit/saveAll"}, method = {RequestMethod.POST}) public String saveHbycRecords(@RequestBody List hbycDTOs, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "JwtToken") String token) { ObjectMapper mapper = new ObjectMapper(); mapper.enable(SerializationFeature.INDENT_OUTPUT); // Pretty print @@ -92,25 +105,27 @@ public String getHbycRecords(@RequestBody GetBenRequestHandler requestDTO) { @PostMapping("/hbncVisit/saveAll") public String saveHBNCVisit(@RequestBody List hbncRequestDTOs, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "jwtToken") String jwtToken) { OutputResponse response = new OutputResponse(); try { if (!hbncRequestDTOs.isEmpty()) { logger.info("Saving HBNC details at: " + new Timestamp(System.currentTimeMillis())); + if(jwtToken!=null){ + String result = childCareService.saveHBNCDetails(hbncRequestDTOs,jwtUtil.extractUserId(jwtToken)); // <-- actual save - String result = childCareService.saveHBNCDetails(hbncRequestDTOs); // <-- actual save + if (result != null) + response.setResponse(result); + else + response.setError(500, "Failed to save HBNC visit data."); + } - if (result != null) - response.setResponse(result); - else - response.setError(500, "Failed to save HBNC visit data."); } else { response.setError(400, "Empty request list."); } } catch (Exception e) { logger.error("Error saving HBNC visit: ", e); - response.setError(500, "Server error: " + e.getMessage()); + response.setError(5000, "Server error: " + e.getMessage()); } return response.toString(); } @@ -146,7 +161,7 @@ public ResponseEntity>> getHBNCVisit } catch (Exception e) { logger.error("Exception in fetching HBNC visits", e); - response.setStatusCode(500); + response.setStatusCode(5000); response.setStatus("Failed"); response.setErrorMessage("Internal Server Error: " + e.getMessage()); response.setData(null); @@ -228,7 +243,7 @@ public String getChildVaccinationDetails(@RequestParam(value = "category") Strin return response.toString(); } @RequestMapping(value = {"/sam/saveAll"}, method = RequestMethod.POST) - public ResponseEntity saveSevereAcuteMalnutrition(@RequestBody List samRequest) { + public ResponseEntity saveSevereAcuteMalnutrition(@RequestBody List samRequest,@RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("SAM Request: {}", samRequest); @@ -240,21 +255,30 @@ public ResponseEntity saveSevereAcuteMalnutrition(@RequestBody List s } - String responseObject = childCareService.saveSamDetails(samRequest); - - if (responseObject != null) { - response.put("statusCode", HttpStatus.OK.value()); - response.put("message", responseObject); - return ResponseEntity.ok(response); - } else { - response.put("statusCode", HttpStatus.BAD_REQUEST.value()); - response.put("message", "Failed to save SAM details"); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + if(token!=null){ + Integer userId = jwtUtil.extractUserId(token); + String userName = userService.getUserDetail(userId).getUserName(); + String responseObject = childCareService.saveSamDetails(samRequest,userId,userName); + + if (responseObject != null) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", responseObject); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save SAM details"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + }else { + response.put("statusCode", HttpStatus.UNAUTHORIZED.value()); + response.put("message", "Invalid token"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); } + } catch (Exception e) { logger.error("Error saving SAM details:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode",5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } @@ -272,14 +296,14 @@ public ResponseEntity getAllSevereAcuteMalnutrition(@RequestBody GetBenReques response.put("data", responseObject); return ResponseEntity.ok(response); } else { - response.put("statusCode", HttpStatus.NOT_FOUND.value()); + response.put("statusCode", HttpStatus.OK.value()); response.put("message", "No SAM records found"); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + return ResponseEntity.status(HttpStatus.NO_CONTENT).body(response); } } catch (Exception e) { logger.error("Error fetching SAM records:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } @@ -287,7 +311,7 @@ public ResponseEntity getAllSevereAcuteMalnutrition(@RequestBody GetBenReques @RequestMapping(value = {"/ors/saveAll"}, method = RequestMethod.POST) - public ResponseEntity saveOrsDistribution(@RequestBody List orsDistributionDTOS) { + public ResponseEntity saveOrsDistribution(@RequestBody List orsDistributionDTOS,@RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("ORS Request: {}", orsDistributionDTOS); @@ -297,22 +321,29 @@ public ResponseEntity saveOrsDistribution(@RequestBody List getAllOrDistribution(@RequestBody GetBenRequestHandler response.put("data", responseObject); return ResponseEntity.ok(response); } else { - response.put("statusCode", HttpStatus.NOT_FOUND.value()); + response.put("statusCode", 5000); response.put("message", "No ORS records found"); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } } catch (Exception e) { logger.error("Error fetching ORS records:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } @@ -346,7 +377,7 @@ public ResponseEntity getAllOrDistribution(@RequestBody GetBenRequestHandler @RequestMapping(value = {"/ifa/saveAll"}, method = RequestMethod.POST) - public ResponseEntity saveIfDistribution(@RequestBody List ifaDistributionDTOS) { + public ResponseEntity saveIfDistribution(@RequestBody List ifaDistributionDTOS,@RequestHeader(value = "JwtToken") String token) { Map response = new LinkedHashMap<>(); logger.info("IFA Request: {}", ifaDistributionDTOS); @@ -356,22 +387,29 @@ public ResponseEntity saveIfDistribution(@RequestBody List responseObject = childCareService.saveAllIfa(ifaDistributionDTOS,userId); + + if (responseObject != null && !responseObject.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "IFA saved successfully"); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "Failed to save IFA details"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + }else { + response.put("statusCode", HttpStatus.UNAUTHORIZED.value()); + response.put("message", "Invalid token"); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response); + } - List responseObject = childCareService.saveAllIfa(ifaDistributionDTOS); - - if (responseObject != null && !responseObject.isEmpty()) { - response.put("statusCode", HttpStatus.OK.value()); - response.put("message", "IFA saved successfully"); - return ResponseEntity.ok(response); - } else { - response.put("statusCode", HttpStatus.BAD_REQUEST.value()); - response.put("message", "Failed to save IFA details"); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); - } } catch (Exception e) { logger.error("Error saving IFA:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } @@ -397,7 +435,7 @@ public ResponseEntity getIfaDistribution(@RequestBody GetBenRequestHandler re } catch (Exception e) { logger.error("Error fetching IFA records:", e); - response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("statusCode", 5000); response.put("errorMessage", e.getMessage()); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } diff --git a/src/main/java/com/iemr/flw/controller/DeathReportsController.java b/src/main/java/com/iemr/flw/controller/DeathReportsController.java index f5317a8b..e8b50de9 100644 --- a/src/main/java/com/iemr/flw/controller/DeathReportsController.java +++ b/src/main/java/com/iemr/flw/controller/DeathReportsController.java @@ -84,8 +84,8 @@ public String getCdrRecords(@RequestBody GetBenRequestHandler requestDTO, logger.info("fetching All CDR Details for user: " + requestDTO.getAshaId()); if (requestDTO != null) { List result = deathReportsService.getCdrRecords(requestDTO); - Gson gson = new GsonBuilder() - .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format + Gson gson = new GsonBuilder()// Set the desired date format + .setDateFormat("MMM dd, yyyy h:mm:ss a") .create(); String s = gson.toJson(result); if (s != null) @@ -111,8 +111,8 @@ public String getMdsrRecords(@RequestBody GetBenRequestHandler requestDTO, logger.info("fetching All MDSR Details for user: " + requestDTO.getAshaId()); if (requestDTO != null) { List result = deathReportsService.getMdsrRecords(requestDTO); - Gson gson = new GsonBuilder() - .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format + Gson gson = new GsonBuilder()// Set the desired date format + .setDateFormat("MMM dd, yyyy h:mm:ss a") .create(); String s = gson.toJson(result); if (s != null) diff --git a/src/main/java/com/iemr/flw/controller/DiseaseControlController.java b/src/main/java/com/iemr/flw/controller/DiseaseControlController.java index 2f5d4264..764ebeaf 100644 --- a/src/main/java/com/iemr/flw/controller/DiseaseControlController.java +++ b/src/main/java/com/iemr/flw/controller/DiseaseControlController.java @@ -34,11 +34,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.LinkedHashMap; @@ -67,12 +63,12 @@ public ResponseEntity> saveMalaria(@RequestBody MalariaDTO m response.put("data", diseaseControlService.saveMalaria(malariaDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -90,12 +86,12 @@ public ResponseEntity> saveKalaAzar(@RequestBody KalaAzarDTO response.put("data", diseaseControlService.saveKalaAzar(kalaAzarDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -112,12 +108,12 @@ public ResponseEntity> saveAESJE(@RequestBody AesJeDTO aesJe response.put("data", diseaseControlService.saveAES(aesJeDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -134,12 +130,12 @@ public ResponseEntity> saveFilaria(@RequestBody FilariaDTO f response.put("data", diseaseControlService.saveFilaria(filariaDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -155,12 +151,12 @@ public ResponseEntity> saveLeprosy(@RequestBody LeprosyDTO l response.put("data", diseaseControlService.saveLeprosy(leprosyDTO)); }else { response.put("message", "Invalid request"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -179,11 +175,11 @@ public ResponseEntity> saveLeprosyFollowUP(@RequestBody List response.put("message", "All follow-ups saved successfully"); } else { response.put("message", "Invalid request - no follow-up data"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); @@ -207,15 +203,17 @@ public ResponseEntity> getAllLeprosy( response.put("data", result); // ← Put list directly, no gson.toJson() } else { response.put("message", "No record found"); - response.put("statusCode", 404); + response.put("statusCode", 5000); } } else { response.put("message", "Invalid request - userName required"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { + logger.info("Fail leprosy: "+e.getMessage()); + logger.info("Fail leprosy full error: "+e); response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); // ← Spring serializes the whole map } @@ -237,15 +235,17 @@ public ResponseEntity> getAllLeprosyFollowUp( response.put("data", result); // ← Put list directly, no gson.toJson() } else { response.put("message", "No record found"); - response.put("statusCode", 404); + response.put("statusCode", 5000); } } else { response.put("message", "Invalid request - userName required"); - response.put("statusCode", 400); + response.put("statusCode", 5000); } } catch (Exception e) { + logger.info("Fail leprosy followUp: "+e.getMessage()); + logger.info("Fail leprosy full error: "+e); response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); // ← Spring serializes the whole map } @@ -260,8 +260,10 @@ public ResponseEntity> getAllData( response.put("data", diseaseControlService.getAllScreeningData(getDiseaseRequestHandler)); } catch (Exception e) { + logger.info("getAllDisease "+e.getMessage()); + logger.info("Fail getAllDisease full error: "+e); response.put("status", "Error" + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); } @@ -314,5 +316,63 @@ public ResponseEntity> getAllMobilizationMosquitoNet(@Reques return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); } } + @RequestMapping(value = "cdtfVisit/saveAll", method = RequestMethod.POST) + public ResponseEntity> saveVisit( + @RequestBody List requestList,@RequestHeader(value = "JwtToken") String token) { + + Map response = new LinkedHashMap<>(); + logger.info("Chronic Disease Visit Save Request: {}", requestList); + + try { + List savedList = + diseaseControlService.saveChronicDiseaseVisit(requestList,token); + + if (savedList != null && !savedList.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("message", "Data saved successfully"); + response.put("data", savedList); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.BAD_REQUEST.value()); + response.put("message", "No data saved"); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } + + } catch (Exception e) { + logger.error("Error saving Chronic Disease Visit :", e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + + @RequestMapping(value = "cdtfVisit/getAll", method = RequestMethod.POST) + public ResponseEntity> getVisitDetails( + @RequestBody GetBenRequestHandler getBenRequestHandler) { + + Map response = new LinkedHashMap<>(); + + try { + List result = + diseaseControlService.getCdtfVisits(getBenRequestHandler); + + if (result != null && !result.isEmpty()) { + response.put("statusCode", HttpStatus.OK.value()); + response.put("data", result); + return ResponseEntity.ok(response); + } else { + response.put("statusCode", HttpStatus.NOT_FOUND.value()); + response.put("message", "No records found"); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); + } + + } catch (Exception e) { + logger.error("Error fetching Chronic Disease Visit :", e); + response.put("statusCode", HttpStatus.INTERNAL_SERVER_ERROR.value()); + response.put("errorMessage", e.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/controller/DynamicFormController.java b/src/main/java/com/iemr/flw/controller/DynamicFormController.java new file mode 100644 index 00000000..59295cbf --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/DynamicFormController.java @@ -0,0 +1,100 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.iemr.DynamicFormDTO; +import com.iemr.flw.service.DynamicFormDefinitionService; +import com.iemr.flw.utils.ApiResponse; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * REST controller for dynamic form definition management. + * All write operations use POST; all read operations use GET. + * Exceptions propagate to GlobalExceptionHandler — no local try-catch. + * + * @author Piramal Swasthya + */ +@Slf4j +@RequiredArgsConstructor +@RestController +@RequestMapping(value = "/dynamicForm", headers = "Authorization") +public class DynamicFormController { + + private final DynamicFormDefinitionService formService; + + @Operation(summary = "Create a full dynamic form definition with sections, questions, options and validations") + @RequestMapping(value = "/createForm", method = RequestMethod.POST) + public ResponseEntity createForm(@RequestBody @Valid DynamicFormDTO dto) { + return ResponseEntity.ok(new ApiResponse(true, null, formService.createForm(dto))); + } + + @Operation(summary = "Replace form structure and bump version (unchanged sections reused)") + @RequestMapping(value = "/updateForm", method = RequestMethod.POST) + public ResponseEntity updateForm( + @RequestParam Long formId, + @RequestBody @Valid DynamicFormDTO dto) { + return ResponseEntity.ok(new ApiResponse(true, null, formService.updateForm(formId, dto))); + } + + @Operation(summary = "Get form definition — latest version or specific version if ?version= provided") + @RequestMapping(value = "/getDefinition", method = RequestMethod.GET) + public ResponseEntity getFormDefinition( + @RequestParam Long formId, + @RequestParam(required = false) Integer version) { + Object result = version != null + ? formService.getFormDefinitionByVersion(formId, version) + : formService.getFormDefinition(formId); + return ResponseEntity.ok(new ApiResponse(true, null, result)); + } + + @Operation(summary = "Get metadata list of all active forms") + @RequestMapping(value = "/getAllForms", method = RequestMethod.GET) + public ResponseEntity getAllForms() { + return ResponseEntity.ok(new ApiResponse(true, null, formService.getAllForms())); + } + + @Operation(summary = "Activate a form (isActive = true)") + @RequestMapping(value = "/activateForm", method = RequestMethod.POST) + public ResponseEntity activateForm( + @RequestParam Long formId) { + formService.activateForm(formId); + return ResponseEntity.ok(new ApiResponse(true, "Form activated", null)); + } + + @Operation(summary = "Deactivate a form (isActive = false)") + @RequestMapping(value = "/deactivateForm", method = RequestMethod.POST) + public ResponseEntity deactivateForm( + @RequestParam Long formId) { + formService.deactivateForm(formId); + return ResponseEntity.ok(new ApiResponse(true, "Form deactivated", null)); + } + +} diff --git a/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java new file mode 100644 index 00000000..49d8e547 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/DynamicFormResponseController.java @@ -0,0 +1,110 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.controller; + +import com.iemr.flw.dto.iemr.FormResponseDTO; +import com.iemr.flw.dto.iemr.FormResponseRequest; +import com.iemr.flw.masterEnum.FormType; +import com.iemr.flw.service.DynamicFormResponseService; +import com.iemr.flw.utils.ApiResponse; +import com.iemr.flw.utils.exception.IEMRException; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * REST controller for saving and retrieving dynamic form responses (beneficiary answers). + * All exceptions propagate to GlobalExceptionHandler — no local try-catch. + * + * @author Piramal Swasthya + */ +@RequiredArgsConstructor +@RestController +@RequestMapping(value = "/dynamicForm/response", headers = "Authorization") +public class DynamicFormResponseController { + + private final DynamicFormResponseService responseService; + + @Operation(summary = "Submit PRE_SUBMIT section answers, status → SUBMITTED. " + + "Pass responseId in body to re-submit an existing SUBMITTED response.") + @RequestMapping(value = "/submit", method = RequestMethod.POST) + public ResponseEntity submitForm( + @Valid @RequestBody FormResponseRequest request) { + FormResponseDTO dto = responseService.submitForm(request); + return ResponseEntity.ok(new ApiResponse(true, "Form submitted successfully", dto)); + } + + @Operation(summary = "Save POST_SUBMIT section answers, status → COMPLETE") + @RequestMapping(value = "/complete", method = RequestMethod.POST) + public ResponseEntity completeForm( + @Valid @RequestBody FormResponseRequest request, + @RequestHeader("JwtToken") String jwtToken) throws IEMRException { + FormResponseDTO dto = responseService.completeForm(request, jwtToken); + return ResponseEntity.ok(new ApiResponse(true, "Form completed successfully", dto)); + } + + @Operation(summary = "Submit multiple form responses in one bulk transaction. " + + "All-or-nothing: any failure rolls back all. responseId is populated for every saved item.") + @RequestMapping(value = "/submitBulk", method = RequestMethod.POST) + public ResponseEntity submitBulk( + @Valid @RequestBody List requests, + @RequestHeader("JwtToken") String jwtToken) { + List saved = responseService.submitBulk(requests, jwtToken); + return ResponseEntity.ok( + new ApiResponse(true, "Bulk submit complete: " + saved.size() + " saved", saved)); + } + + @Operation(summary = "Get all form responses for a beneficiary filtered by form UUID") + @RequestMapping(value = "/getByBeneficiary", method = RequestMethod.GET) + public ResponseEntity getByBeneficiary( + @RequestParam Long beneficiaryId, + @RequestParam String formUuid) { + List dtos = + responseService.getResponsesByBeneficiary(beneficiaryId, formUuid); + return ResponseEntity.ok(new ApiResponse(true, "Responses fetched successfully", dtos)); + } + + @Operation(summary = "Get a single form response with all nested answers") + @RequestMapping(value = "/getById", method = RequestMethod.GET) + public ResponseEntity getById(@RequestParam Long responseId) { + FormResponseDTO dto = responseService.getResponseById(responseId); + return ResponseEntity.ok(new ApiResponse(true, "Response fetched successfully", dto)); + } + @Operation(summary = "Get beneficiary IDs that have a COMPLETE form response for the given form type, optionally filtered by village and/or provider service map") + @RequestMapping(value = "/getCompletedBeneficiaries", method = RequestMethod.GET) + public ResponseEntity getCompletedBeneficiaries( + @RequestParam FormType formType, + @RequestParam(required = false) Integer villageId, + @RequestParam(required = false) Integer providerServiceMapId) { + List beneficiaryIds = responseService.getCompletedBeneficiaries(formType, villageId, providerServiceMapId); + return ResponseEntity.ok(new ApiResponse(true, "Completed beneficiaries fetched successfully", beneficiaryIds)); + } +} diff --git a/src/main/java/com/iemr/flw/controller/GeneralOPDController.java b/src/main/java/com/iemr/flw/controller/GeneralOPDController.java index 5e7823df..c683a9be 100644 --- a/src/main/java/com/iemr/flw/controller/GeneralOPDController.java +++ b/src/main/java/com/iemr/flw/controller/GeneralOPDController.java @@ -77,7 +77,7 @@ public ResponseEntity> getBeneficiaryDataByAsha(@RequestBody } catch (Exception e) { logger.error("Error in get data : " + e); - response.put("status", 500); + response.put("statusCode", 5000); response.put("message", "Error in get data : " + e); } return ResponseEntity.ok(response); diff --git a/src/main/java/com/iemr/flw/controller/GlobalExceptionHandler.java b/src/main/java/com/iemr/flw/controller/GlobalExceptionHandler.java new file mode 100644 index 00000000..8470b97f --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/GlobalExceptionHandler.java @@ -0,0 +1,154 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.controller; + +import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; +import com.iemr.flw.utils.ApiResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingRequestHeaderException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +/** + * Converts all Spring MVC and application exceptions into a consistent ApiResponse envelope. + * + * @author Piramal Swasthya + */ +@RestControllerAdvice +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + + private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + /** @Valid / @Validated failures — collect every field error into one readable message. */ + @Override + protected ResponseEntity handleMethodArgumentNotValid( + MethodArgumentNotValidException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + + String message = ex.getBindingResult().getFieldErrors().stream() + .map(fe -> fe.getField() + ": " + fe.getDefaultMessage()) + .collect(Collectors.joining(", ")); + + log.warn("Validation failed: {}", message); + return ResponseEntity.badRequest() + .body(new ApiResponse(false, "Validation failed — " + message, null)); + } + + /** Malformed JSON body, including unrecognized field names. */ + @Override + protected ResponseEntity handleHttpMessageNotReadable( + HttpMessageNotReadableException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + + String message = "Malformed JSON request body"; + if (ex.getCause() instanceof UnrecognizedPropertyException upe) { + message = "Unrecognized field '" + upe.getPropertyName() + + "' — use camelCase field names (e.g. sectionUuid, questionUuid)"; + } + log.warn("Unreadable request body: {}", ex.getMessage()); + return ResponseEntity.badRequest().body(new ApiResponse(false, message, null)); + } + + /** Invalid argument (e.g. null UUID field when wrong field name was sent). */ + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity handleIllegalArgument(IllegalArgumentException ex) { + log.warn("Illegal argument: {}", ex.getMessage()); + return ResponseEntity.badRequest() + .body(new ApiResponse(false, ex.getMessage(), null)); + } + + /** Required @RequestParam missing from the request. */ + @Override + protected ResponseEntity handleMissingServletRequestParameter( + MissingServletRequestParameterException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + + log.warn("Missing request parameter: {}", ex.getParameterName()); + return ResponseEntity.badRequest() + .body(new ApiResponse(false, + "Missing required parameter: '" + ex.getParameterName() + "'", null)); + } + + /** Required @RequestHeader missing from the request. */ + @ExceptionHandler(MissingRequestHeaderException.class) + public ResponseEntity handleMissingHeader(MissingRequestHeaderException ex) { + log.warn("Missing required header: {}", ex.getHeaderName()); + return ResponseEntity.badRequest() + .body(new ApiResponse(false, + "Missing required header: '" + ex.getHeaderName() + "'", null)); + } + + /** Wrong type for a @RequestParam or @PathVariable (e.g. "abc" passed for a Long). */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + public ResponseEntity handleTypeMismatch(MethodArgumentTypeMismatchException ex) { + String expected = ex.getRequiredType() != null ? ex.getRequiredType().getSimpleName() : "unknown"; + String message = "Invalid value '" + ex.getValue() + + "' for parameter '" + ex.getName() + + "' — expected type: " + expected; + log.warn("Type mismatch: {}", message); + return ResponseEntity.badRequest().body(new ApiResponse(false, message, null)); + } + + /** Entity not found (thrown by service layer orElseThrow). */ + @ExceptionHandler(NoSuchElementException.class) + public ResponseEntity handleNotFound(NoSuchElementException ex) { + log.warn("Resource not found: {}", ex.getMessage()); + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(new ApiResponse(false, ex.getMessage(), null)); + } + + /** Invalid lifecycle transition (e.g. completing a non-SUBMITTED response). */ + @ExceptionHandler(IllegalStateException.class) + public ResponseEntity handleIllegalState(IllegalStateException ex) { + log.warn("Illegal state: {}", ex.getMessage()); + return ResponseEntity.status(HttpStatus.CONFLICT) + .body(new ApiResponse(false, ex.getMessage(), null)); + } + + /** Catch-all for anything not handled above. */ + @ExceptionHandler(Exception.class) + public ResponseEntity handleGeneric(Exception ex) { + log.error("Unhandled exception: {}", ex.getMessage(), ex); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(new ApiResponse(false, ex.getMessage(), null)); + } +} diff --git a/src/main/java/com/iemr/flw/controller/IRSRoundController.java b/src/main/java/com/iemr/flw/controller/IRSRoundController.java index 4425cdeb..77047f89 100644 --- a/src/main/java/com/iemr/flw/controller/IRSRoundController.java +++ b/src/main/java/com/iemr/flw/controller/IRSRoundController.java @@ -3,7 +3,10 @@ import com.iemr.flw.domain.iemr.IRSRound; import com.iemr.flw.dto.iemr.IRSRoundDTO; import com.iemr.flw.dto.iemr.IRSRoundListDTO; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.IRSRoundService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; import com.iemr.flw.utils.response.OutputResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -24,12 +27,23 @@ public class IRSRoundController { @Autowired private IRSRoundService irsRoundService; + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserService userService; + @PostMapping(value = "/add") - public ResponseEntity> addRound(@RequestBody IRSRoundListDTO dto) { + public ResponseEntity> addRound(@RequestBody IRSRoundListDTO dto,@RequestHeader("jwtToken") String token) { Map response = new LinkedHashMap<>(); try { if (dto.getRounds().size() != 0) { - List s = irsRoundService.addRounds(dto.getRounds()); + if(token==null){ + response.put("statusCode", 401); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(response) ; + } + Integer userId = jwtUtil.extractUserId(token); + List s = irsRoundService.addRounds(dto.getRounds(), userId, userService.getUserDetail(userId).getUserName()); if (s.size() != 0) { Map data = new HashMap<>(); data.put("entries", s); diff --git a/src/main/java/com/iemr/flw/controller/IncentiveController.java b/src/main/java/com/iemr/flw/controller/IncentiveController.java index 670d611b..fe1d93ac 100644 --- a/src/main/java/com/iemr/flw/controller/IncentiveController.java +++ b/src/main/java/com/iemr/flw/controller/IncentiveController.java @@ -1,8 +1,7 @@ package com.iemr.flw.controller; import com.iemr.flw.dto.identity.GetBenRequestHandler; -import com.iemr.flw.dto.iemr.IncentiveActivityDTO; -import com.iemr.flw.dto.iemr.IncentiveRequestDTO; +import com.iemr.flw.dto.iemr.*; import com.iemr.flw.service.IncentiveService; import com.iemr.flw.utils.JwtUtil; import com.iemr.flw.utils.response.OutputResponse; @@ -13,10 +12,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.sql.Timestamp; +import java.util.HashMap; import java.util.List; +import java.util.Map; @RestController @RequestMapping(value = "/incentive", consumes = "application/json", produces = "application/json") @@ -28,9 +31,12 @@ public class IncentiveController { @Autowired IncentiveService incentiveService; + @Autowired + private JwtUtil jwtUtil; + @Operation(summary = "save incentive master") - @RequestMapping(value = { "/masterData/saveAll" }, method = { RequestMethod.POST }) - public String saveIncentiveMasterData(@RequestBody List activityDTOS,@RequestHeader(value = "Authorization") String authorization, HttpServletRequest request) { + @RequestMapping(value = {"/masterData/saveAll"}, method = {RequestMethod.POST}) + public String saveIncentiveMasterData(@RequestBody List activityDTOS, @RequestHeader(value = "Authorization") String authorization, HttpServletRequest request) { OutputResponse response = new OutputResponse(); try { logger.info("Saving All incentives"); @@ -50,9 +56,9 @@ public String saveIncentiveMasterData(@RequestBody List ac } @Operation(summary = "get incentive master") - @RequestMapping(value = { "/masterData/getAll" }, method = { RequestMethod.POST }) + @RequestMapping(value = {"/masterData/getAll"}, method = {RequestMethod.POST}) public String saveIncentiveMasterData(@RequestBody IncentiveRequestDTO incentiveRequestDTO, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "Authorization") String Authorization) { OutputResponse response = new OutputResponse(); try { @@ -61,7 +67,7 @@ public String saveIncentiveMasterData(@RequestBody IncentiveRequestDTO incentive // add logic for different state or district if (incentiveRequestDTO != null) { String s = incentiveService.getIncentiveMaster(incentiveRequestDTO); - logger.info("All incentives"+s); + // logger.info("All incentives" + s); if (s != null) response.setResponse(s); @@ -77,21 +83,44 @@ public String saveIncentiveMasterData(@RequestBody IncentiveRequestDTO incentive } + @Operation(summary = "get high risk assessment data of all beneficiaries registered with given user id") + @RequestMapping(value = {"/fetchUserData"}, method = {RequestMethod.POST}) + public String getAllIncentivesByUserId(@RequestBody GetBenRequestHandler requestDTO, + @RequestHeader(value = "Authorization") String Authorization) { + OutputResponse response = new OutputResponse(); + try { + if (requestDTO != null) { + logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + String s = incentiveService.getAllIncentivesByUserId(requestDTO); + //logger.info("User Incentive:" + s); + if (s != null) + response.setResponse(s); + else + response.setError(5000, "No record found"); + } else + response.setError(5000, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in high risk assessment data : " + e); + response.setError(5000, "Error in high risk assessment data : " + e); + } + return response.toString(); + } @Operation(summary = "get high risk assessment data of all beneficiaries registered with given user id") - @RequestMapping(value = { "/fetchUserData" }, method = { RequestMethod.POST }) - public String getAllIncentivesByUserId(@RequestBody GetBenRequestHandler requestDTO, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestMapping(value = {"/claimedIncentiveByUser"}, method = {RequestMethod.POST}) + public String getAllIncentivesByUserIdGroupByCount(@RequestBody GetBenRequestHandler requestDTO, + @RequestHeader(value = "Authorization") String Authorization) { OutputResponse response = new OutputResponse(); try { if (requestDTO != null) { logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + requestDTO); - String s = incentiveService.getAllIncentivesByUserId(requestDTO); - logger.info("User Incentive:"+s); + String s = incentiveService.getAllIncentivesGroupedSummary(requestDTO); + logger.info("User Incentive:" + s); if (s != null) response.setResponse(s); else @@ -105,4 +134,86 @@ public String getAllIncentivesByUserId(@RequestBody GetBenRequestHandler request return response.toString(); } + @Operation(summary = "get high risk assessment data of all beneficiaries registered with given user id") + @RequestMapping(value = {"/AllIncentiveByActivityId"}, method = {RequestMethod.POST}) + public String getAllIncentivesByActivityIdAndUser(@RequestBody GetBenRequestHandler requestDTO, + @RequestHeader(value = "Authorization") String Authorization) { + OutputResponse response = new OutputResponse(); + try { + + if (requestDTO != null) { + logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + String s = incentiveService.getAllIncentivesGroupedActivity(requestDTO); + logger.info("User Incentive:" + s); + if (s != null) + response.setResponse(s); + else + response.setError(5000, "No record found"); + } else + response.setError(5000, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in high risk assessment data : " + e); + response.setError(5000, "Error in high risk assessment data : " + e); + } + return response.toString(); + } + + @RequestMapping(value = {"/update"}, method = RequestMethod.POST, consumes = {"multipart/form-data"}) + public String updateIncentive(@ModelAttribute PendingActivityDTO requestDTO) { + OutputResponse response = new OutputResponse(); + try { + + if (requestDTO != null) { + logger.info("request object with timestamp : " + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + String s = incentiveService.updateIncentive(requestDTO); + logger.info("User Incentive:" + s); + if (s != null) + response.setResponse(s); + else + response.setError(500, "No record found"); + } else + response.setError(500, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in high risk assessment data : " + e); + response.setError(500, "Error in high risk assessment data : " + e); + } + return response.toString(); + + + } + + @PostMapping("/updateClaim") + public ResponseEntity updateApprovalStatus( + @RequestBody UpdateClaimedStatusRequestDTO request, + @RequestHeader(value = "JwtToken") String token) { + + try { + if (token == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("UNAUTHORIZED"); + } + + String result = incentiveService.updateClaimStatus( + jwtUtil.extractUserId(token), + request.getMonth(), + request.getYear(), + request.isClaimed(), + token + ); + + Map response = new HashMap<>(); + response.put("statusCode", 200); + response.put("message", result); + + return ResponseEntity.ok(response); + + } catch (Exception e) { + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Server error: " + e.getMessage()); + } + } + + } diff --git a/src/main/java/com/iemr/flw/controller/MaaMeetingController.java b/src/main/java/com/iemr/flw/controller/MaaMeetingController.java index d9bcdb1b..012438c5 100644 --- a/src/main/java/com/iemr/flw/controller/MaaMeetingController.java +++ b/src/main/java/com/iemr/flw/controller/MaaMeetingController.java @@ -35,22 +35,102 @@ public MaaMeetingController(MaaMeetingService service) { @PostMapping(value = "/saveAll", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity saveMeeting( + + @RequestPart(value = "villageName", required = false) String villageName, + @RequestPart(value = "noOfPragnentWoment", required = false) String noOfPragnentWomen, + @RequestPart(value = "noOfLactingMother", required = false) String noOfLactingMother, + @RequestPart(value = "mitaninActivityCheckList", required = false) String mitaninActivityCheckList, + @RequestPart(value = "meetingDate") String meetingDate, + @RequestPart(value = "place", required = false) String place, + @RequestPart(value = "participants") String participants, + @RequestPart(value = "ashaId", required = false) String ashaId, + @RequestPart(value = "createdBy", required = false) String createdBy, + @RequestPart(value = "meetingImages", required = false) List meetingImages + ) { + try { + MaaMeetingRequestDTO dto = new MaaMeetingRequestDTO(); + + if (meetingDate != null && !meetingDate.isEmpty()) { + dto.setMeetingDate(LocalDate.parse(meetingDate)); + } + + dto.setPlace(place); + dto.setVillageName(villageName); + dto.setMitaninActivityCheckList(mitaninActivityCheckList); + dto.setCreatedBY(createdBy); + + if (participants != null && !participants.isEmpty()) { + dto.setParticipants(Integer.parseInt(participants)); + } + + if (ashaId != null && !ashaId.isEmpty()) { + dto.setAshaId(Integer.parseInt(ashaId)); + } + + if (noOfLactingMother != null && !noOfLactingMother.isEmpty()) { + dto.setNoOfLactingMother(Integer.parseInt(noOfLactingMother)); + } + + if (noOfPragnentWomen != null && !noOfPragnentWomen.isEmpty()) { + dto.setNoOfPragnentWomen(Integer.parseInt(noOfPragnentWomen)); + } + + if (meetingImages != null && !meetingImages.isEmpty()) { + dto.setMeetingImages(meetingImages.toArray(new MultipartFile[0])); + } + + service.saveMeeting(dto); + + return ResponseEntity.ok("Saved Successfully"); + + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.badRequest().body(e.getMessage()); + } + } + + @PostMapping(value = "/update", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity updateMeeting( @RequestPart("meetingDate") String meetingDate, @RequestPart("place") String place, @RequestPart("participants") String participants, + @RequestPart("id") Long meetingId, @RequestPart("ashaId") String ashaId, @RequestPart("createdBy") String createdBy, @RequestPart(value = "meetingImages", required = false) List meetingImages) { try { MaaMeetingRequestDTO dto = new MaaMeetingRequestDTO(); - dto.setMeetingDate(LocalDate.parse(meetingDate)); - dto.setPlace(place); - dto.setParticipants(Integer.parseInt(participants)); - dto.setAshaId(Integer.parseInt(ashaId)); - dto.setCreatedBY(createdBy); - dto.setMeetingImages(meetingImages != null ? meetingImages.toArray(new MultipartFile[0]) : null); + if (meetingDate != null) { + dto.setMeetingDate(LocalDate.parse(meetingDate)); - service.saveMeeting(dto); + } + if (place != null) { + dto.setPlace(place); + + } + if (participants != null) { + dto.setParticipants(Integer.parseInt(participants)); + + } + if (ashaId != null) { + dto.setAshaId(Integer.parseInt(ashaId)); + + } + if (createdBy != null) { + dto.setCreatedBY(createdBy); + + } + if (meetingImages != null) { + dto.setMeetingImages(meetingImages != null ? meetingImages.toArray(new MultipartFile[0]) : null); + + } + if(meetingId!=null){ + dto.setId(meetingId); + } + if (dto != null) { + service.updateMeeting(dto); + + } return ResponseEntity.ok("Saved Successfully"); } catch (Exception e) { return ResponseEntity.badRequest().body(e.getMessage()); diff --git a/src/main/java/com/iemr/flw/controller/MalariaFollowUpController.java b/src/main/java/com/iemr/flw/controller/MalariaFollowUpController.java index 4e3ae194..29204ab6 100644 --- a/src/main/java/com/iemr/flw/controller/MalariaFollowUpController.java +++ b/src/main/java/com/iemr/flw/controller/MalariaFollowUpController.java @@ -28,6 +28,9 @@ import com.iemr.flw.dto.iemr.MalariaFollowListUpDTO; import com.iemr.flw.dto.iemr.MalariaFollowUpDTO; import com.iemr.flw.service.MalariaFollowUpService; +import com.iemr.flw.utils.JwtUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -39,46 +42,59 @@ @RestController @RequestMapping(value = "/follow-up", headers = "Authorization") public class MalariaFollowUpController { + private final Logger logger = LoggerFactory.getLogger(MalariaFollowUpController.class); + + @Autowired + private JwtUtil jwtUtil; @Autowired private MalariaFollowUpService followUpService; @RequestMapping(value = "save", method = RequestMethod.POST) - public ResponseEntity> save(@RequestBody MalariaFollowUpDTO dto) { + public ResponseEntity> save(@RequestBody MalariaFollowUpDTO dto,@RequestHeader(value = "JwtToken") String token) { Map response = new HashMap<>(); try { - Boolean result = followUpService.saveFollowUp(dto); - if (result) { - response.put("status", "Success"); - response.put("statusCode", 200); - response.put("message", "Follow-up saved successfully"); - } else { - response.put("status", "Failed"); - response.put("statusCode", 400); + if(token!=null){ + + Boolean result = followUpService.saveFollowUp(dto,token); + if (result) { + response.put("status", "Success"); + response.put("statusCode", 200); + response.put("message", "Follow-up saved successfully"); + } else { + response.put("status", "Failed"); + response.put("statusCode", 5000); + } } + } catch (Exception e) { response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); } @RequestMapping(value = "get", method = RequestMethod.POST) - public ResponseEntity> getFollowUpsByUserId(@RequestBody GetDiseaseRequestHandler getDiseaseRequestHandler) { + public ResponseEntity> getFollowUpsByUserId(@RequestBody GetDiseaseRequestHandler getDiseaseRequestHandler,@RequestHeader(value = "JwtToken") String token) { Map response = new HashMap<>(); try { - List data = followUpService.getByUserId(getDiseaseRequestHandler.getUserId()); - response.put("status", "Success"); - response.put("statusCode", 200); - response.put("data", data); - if (data.isEmpty()) { - response.put("message", "No records found"); + if(token!=null){ + List data = followUpService.getByUserId(jwtUtil.extractUserId(token)); + response.put("status", "Success"); + response.put("statusCode", 200); + response.put("data", data); + if (data.isEmpty()) { + response.put("message", "No records found"); + } } + } catch (Exception e) { + logger.info("Fail Malaria followUp: "+e.getMessage()); + logger.info("Fail Malaria full error: "+e); response.put("status", "Error: " + e.getMessage()); - response.put("statusCode", 500); + response.put("statusCode", 5000); } return ResponseEntity.ok(response); diff --git a/src/main/java/com/iemr/flw/controller/MaternalHealthController.java b/src/main/java/com/iemr/flw/controller/MaternalHealthController.java index e23cc8ed..9c8459da 100644 --- a/src/main/java/com/iemr/flw/controller/MaternalHealthController.java +++ b/src/main/java/com/iemr/flw/controller/MaternalHealthController.java @@ -15,17 +15,18 @@ import io.swagger.v3.oas.annotations.Operation; import jakarta.servlet.http.HttpServletRequest; -import org.checkerframework.checker.units.qual.A; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.sql.Timestamp; import java.util.List; @RestController -@RequestMapping(value = "/maternalCare", headers = "Authorization", consumes = "application/json", produces = "application/json") +@RequestMapping(value = "/maternalCare", consumes = "application/json", produces = "application/json") public class MaternalHealthController { private final Logger logger = LoggerFactory.getLogger(CoupleController.class); @@ -91,21 +92,26 @@ public String getPregnantWomanList(@RequestBody GetBenRequestHandler requestDTO, response.setError(5000, "Error in pregnant woman get data : " + e); } return response.toString(); + } @Operation(summary = "save anc visit details") @RequestMapping(value = { "/ancVisit/saveAll" }, method = { RequestMethod.POST }) public String saveANCVisit(@RequestBody List ancVisitDTOs, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "JwtToken") String token) { OutputResponse response = new OutputResponse(); try { if (ancVisitDTOs.size() != 0) { logger.info("Saving ANC visits with timestamp : " + new Timestamp(System.currentTimeMillis())); - String s = maternalHealthService.saveANCVisit(ancVisitDTOs); - if (s != null) - response.setResponse(s); - else - response.setError(5000, "Saving anc data to db failed"); + if(token!=null){ + String s = maternalHealthService.saveANCVisit(ancVisitDTOs,jwtUtil.extractUserId(token)); + + if (s != null) + response.setResponse(s); + else + response.setError(5000, "Saving anc data to db failed"); + } + } else response.setError(5000, "Invalid/NULL request obj"); } catch (Exception e) { @@ -141,6 +147,67 @@ public String getANCVisitDetails(@RequestBody GetBenRequestHandler requestDTO, return response.toString(); } + @Operation(summary = "save anc visit question") + @RequestMapping(value = { "/ancVisit/counselling/saveAll" }, method = { RequestMethod.POST }) + public String saveANCVisitQuestion(@RequestBody List ancVisitQuestionsDTOS, + @RequestHeader(value = "JwtToken") String Authorization) { + OutputResponse response = new OutputResponse(); + try { + if (ancVisitQuestionsDTOS.size() != 0) { + + logger.info("Saving ANC visits with timestamp : " + new Timestamp(System.currentTimeMillis())); + String s = maternalHealthService.saveANCVisitQuestions(ancVisitQuestionsDTOS,Authorization); + if (s != null) + response.setResponse(s); + else + response.setError(500, "Saving anc data to db failed"); + } else + response.setError(500, "Invalid/NULL request obj"); + } catch (Exception e) { + logger.error("Error in save ANC visit details : ",e); + + response.setError(500, "Error in save ANC visit details : " + e); + } + return response.toString(); + } + + @Operation(summary = "get anc visit questions") + @RequestMapping(value = { "/ancVisit/counselling/getAll" }, method = { RequestMethod.POST }) + public ResponseEntity>> getANCVisitQuestion(@RequestBody GetBenRequestHandler requestDTO, + @RequestHeader(value = "JwtToken") String Authorization) { + StandardResponse> response = new StandardResponse<>(); + + try { + if (requestDTO != null) { + logger.info("Request: " + requestDTO); + + List result = maternalHealthService.getANCCounselling(requestDTO); + + response.setStatusCode(200); + response.setStatus("Success"); + response.setErrorMessage("Success"); + response.setData(result); + + return ResponseEntity.ok(response); + + } else { + response.setStatusCode(400); + response.setStatus("Failed"); + response.setErrorMessage("Invalid request object"); + response.setData(null); + return ResponseEntity.badRequest().body(response); + } + } catch (Exception e) { + logger.error("Exception in fetching HBNC visits", e); + + response.setStatusCode(500); + response.setStatus("Failed"); + response.setErrorMessage("Internal Server Error: " + e.getMessage()); + response.setData(null); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response); + } + } + @Operation(summary = "save Delivery Outcome details") @RequestMapping(value = { "/deliveryOutcome/saveAll" }, method = { RequestMethod.POST }) public String saveDeliveryOutcome(@RequestBody List deliveryOutcomeDTOS, @@ -163,6 +230,7 @@ public String saveDeliveryOutcome(@RequestBody List delivery response.setError(5000, "Error in save delivery outcome details : " + e); } return response.toString(); + } @Operation(summary = "get Delivery Outcome details") @@ -177,9 +245,9 @@ public String getDeliveryOutcome(@RequestBody GetBenRequestHandler requestDTO, List result = deliveryOutcomeService.getDeliveryOutcome(requestDTO); Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); String s = gson.toJson(result); - if (s != null) - response.setResponse(s); - else + if (result != null && !result.isEmpty()) { + response.setResponse(gson.toJson(result)); + }else response.setError(5000, "No record found"); } else response.setError(5000, "Invalid/NULL request obj"); diff --git a/src/main/java/com/iemr/flw/controller/StopTBController.java b/src/main/java/com/iemr/flw/controller/StopTBController.java new file mode 100644 index 00000000..7f73d29e --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/StopTBController.java @@ -0,0 +1,161 @@ +package com.iemr.flw.controller; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.iemr.flw.service.StopTBService; +import com.iemr.flw.utils.response.OutputResponse; +import io.swagger.v3.oas.annotations.Operation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/stoptb") +public class StopTBController { + + private final Logger logger = LoggerFactory.getLogger(StopTBController.class); + + // serializeNulls() so fields with no value (e.g. hivStatus, keyPopulationRiskFactor*) + // still appear in the response as null instead of being silently dropped + private final Gson gson = new GsonBuilder().serializeNulls().create(); + + @Autowired + private StopTBService stopTBService; + + // ── Nurse: General Examination ──────────────────────────────────────────── + + @PostMapping("/nurse/generalExamination/save") + @Operation(summary = "Save general examination for Stop TB beneficiary (array of objects)") + public String saveGeneralExamination(@RequestBody List> dataList) { + OutputResponse response = new OutputResponse(); + try { + List> result = stopTBService.saveGeneralExamination(dataList); + response.setResponse(gson.toJson(result)); + } catch (Exception e) { + logger.error("Error in saveGeneralExamination: " + e); + response.setError(5000, "Error saving general examination: " + e.getMessage()); + } + return response.toString(); + } + + @PostMapping("/nurse/generalExamination/getAll") + @Operation(summary = "Get all general examinations for a camp") + public String getAllGeneralExaminations(@RequestBody Map body) { + OutputResponse response = new OutputResponse(); + try { + Object raw = body.get("providerServiceMapID"); + if (raw == null) throw new Exception("providerServiceMapID is required"); + Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null; + Map data = stopTBService.getAllGeneralExaminations(Integer.parseInt(raw.toString()), villageID); + response.setResponse(gson.toJson(data)); + } catch (Exception e) { + logger.error("Error in getAllGeneralExaminations: " + e); + response.setError(5000, "Error fetching general examinations: " + e.getMessage()); + } + return response.toString(); + } + + // ── Nurse: TB Screening ─────────────────────────────────────────────────── + + @PostMapping("/nurse/tbScreening/save") + @Operation(summary = "Save TB screening for Stop TB beneficiary (array of objects)") + public String saveNurseTBScreening(@RequestBody List> dataList) { + OutputResponse response = new OutputResponse(); + try { + List> result = stopTBService.saveNurseTBScreening(dataList); + response.setResponse(gson.toJson(result)); + } catch (Exception e) { + logger.error("Error in saveNurseTBScreening: " + e); + response.setError(5000, "Error saving TB screening: " + e.getMessage()); + } + return response.toString(); + } + + @PostMapping("/nurse/tbScreening/getAll") + @Operation(summary = "Get all TB screenings for a camp") + public String getAllNurseTBScreenings(@RequestBody Map body) { + OutputResponse response = new OutputResponse(); + try { + Object raw = body.get("providerServiceMapID"); + if (raw == null) throw new Exception("providerServiceMapID is required"); + Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null; + Map data = stopTBService.getAllNurseTBScreenings(Integer.parseInt(raw.toString()), villageID); + response.setResponse(gson.toJson(data)); + } catch (Exception e) { + logger.error("Error in getAllNurseTBScreenings: " + e); + response.setError(5000, "Error fetching TB screenings: " + e.getMessage()); + } + return response.toString(); + } + + // ── Nurse: General OPD ──────────────────────────────────────────────────── + + @PostMapping("/nurse/generalOpd/save") + @Operation(summary = "Save general OPD record for Stop TB beneficiary (array of objects)") + public String saveGeneralOpd(@RequestBody List> dataList) { + OutputResponse response = new OutputResponse(); + try { + List> result = stopTBService.saveGeneralOpd(dataList); + response.setResponse(gson.toJson(result)); + } catch (Exception e) { + logger.error("Error in saveGeneralOpd: " + e); + response.setError(5000, "Error saving general OPD: " + e.getMessage()); + } + return response.toString(); + } + + @PostMapping("/nurse/generalOpd/getAll") + @Operation(summary = "Get all general OPD records for a camp") + public String getAllGeneralOpd(@RequestBody Map body) { + OutputResponse response = new OutputResponse(); + try { + Object raw = body.get("providerServiceMapID"); + if (raw == null) throw new Exception("providerServiceMapID is required"); + Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null; + Map data = stopTBService.getAllGeneralOpd(Integer.parseInt(raw.toString()), villageID); + response.setResponse(gson.toJson(data)); + } catch (Exception e) { + logger.error("Error in getAllGeneralOpd: " + e); + response.setError(5000, "Error fetching general OPD records: " + e.getMessage()); + } + return response.toString(); + } + + // ── Nurse: Diagnostics ─────────────────────────────────────────────────── + + @PostMapping("/nurse/diagnostics/save") + @Operation(summary = "Save diagnostics for Stop TB beneficiary (array of objects)") + public String saveDiagnostics(@RequestBody List> dataList) { + OutputResponse response = new OutputResponse(); + try { + List> result = stopTBService.saveDiagnostics(dataList); + response.setResponse(gson.toJson(result)); + } catch (Exception e) { + logger.error("Error in saveDiagnostics: " + e); + response.setError(5000, "Error saving diagnostics: " + e.getMessage()); + } + return response.toString(); + } + + @PostMapping("/nurse/diagnostics/getAll") + @Operation(summary = "Get all diagnostics records for a camp") + public String getAllDiagnostics(@RequestBody Map body) { + OutputResponse response = new OutputResponse(); + try { + Object raw = body.get("providerServiceMapID"); + if (raw == null) throw new Exception("providerServiceMapID is required"); + Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null; + Map data = stopTBService.getAllDiagnostics(Integer.parseInt(raw.toString()), villageID); + response.setResponse(gson.toJson(data)); + } catch (Exception e) { + logger.error("Error in getAllDiagnostics: " + e); + response.setError(5000, "Error fetching diagnostics records: " + e.getMessage()); + } + return response.toString(); + } + +} diff --git a/src/main/java/com/iemr/flw/controller/TBController.java b/src/main/java/com/iemr/flw/controller/TBController.java index 6beb9008..becc387a 100644 --- a/src/main/java/com/iemr/flw/controller/TBController.java +++ b/src/main/java/com/iemr/flw/controller/TBController.java @@ -1,14 +1,18 @@ package com.iemr.flw.controller; +import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; import com.iemr.flw.dto.identity.GetBenRequestHandler; +import com.iemr.flw.dto.iemr.TBConfirmedRequestDTO; import com.iemr.flw.dto.iemr.TBScreeningRequestDTO; import com.iemr.flw.dto.iemr.TBSuspectedRequestDTO; +import com.iemr.flw.service.TBConfirmedCaseService; import com.iemr.flw.service.TBScreeningService; import com.iemr.flw.service.TBSuspectedService; import com.iemr.flw.utils.response.OutputResponse; import io.swagger.v3.oas.annotations.Operation; +import org.checkerframework.checker.units.qual.A; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +32,9 @@ public class TBController { @Autowired private TBSuspectedService tbSuspectedService; + @Autowired + private TBConfirmedCaseService tbConfirmedCaseService; + @Operation(summary = "get tb screening data of all beneficiaries registered with given user id") @RequestMapping(value = { "/screening/getAll" }, method = { RequestMethod.POST }) public String getAllScreeningByUserId(@RequestBody GetBenRequestHandler requestDTO, @@ -42,9 +49,9 @@ public String getAllScreeningByUserId(@RequestBody GetBenRequestHandler requestD if (s != null) response.setResponse(s); else - response.setError(5000, "No record found"); + response.setError(500, "No record found"); } else - response.setError(5000, "Invalid/NULL request obj"); + response.setError(500, "Invalid/NULL request obj"); } catch (Exception e) { logger.error("Error in tb screening get data : " + e); response.setError(5000, "Error in tb screening get data : " + e); @@ -66,9 +73,9 @@ public String saveAllScreeningByUserId(@RequestBody TBScreeningRequestDTO reques if (s != null) response.setResponse(s); else - response.setError(5000, "No record found"); + response.setError(500, "No record found"); } else - response.setError(5000, "Invalid/NULL request obj"); + response.setError(500, "Invalid/NULL request obj"); } catch (Exception e) { logger.error("Error in save tb screening details : " + e); response.setError(5000, "Error in save tb suspected details : " + e); @@ -91,12 +98,12 @@ public String getAllSuspectedByUserId(@RequestBody GetBenRequestHandler requestD if (s != null) response.setResponse(s); else - response.setError(5000, "No record found"); + response.setError(500, "No record found"); } else - response.setError(5000, "Invalid/NULL request obj"); + response.setError(500, "Invalid/NULL request obj"); } catch (Exception e) { logger.error("Error in get data : " + e); - response.setError(5000, "Error in get data : " + e); + response.setError(500, "Error in get data : " + e); } return response.toString(); } @@ -115,13 +122,76 @@ public String saveAllSuspectedByUserId(@RequestBody TBSuspectedRequestDTO reques if (s != null) response.setResponse(s); else - response.setError(5000, "No record found"); + response.setError(500, "No record found"); } else - response.setError(5000, "Invalid/NULL request obj"); + response.setError(500, "Invalid/NULL request obj"); } catch (Exception e) { logger.error("Error in save tb suspected details : " + e); response.setError(5000, "Error in save tb suspected details : " + e); } return response.toString(); } + + @Operation(summary = "save tb confirmed case data of beneficiary") + @RequestMapping(value = { "/confirmed/save" }, method = { RequestMethod.POST }) + public String saveConfirmedCase( + @RequestBody TBConfirmedRequestDTO requestDTO, + @RequestHeader(value = "jwtToken") String token) { + + OutputResponse response = new OutputResponse(); + + try { + if (requestDTO != null) { + + logger.info("request object with timestamp : " + + new Timestamp(System.currentTimeMillis()) + " " + + requestDTO); + + String result = tbConfirmedCaseService.save(requestDTO.getTbConfirmedList(), token); + + if (result != null) + response.setResponse(result); + else + response.setError(500, "No record saved"); + + } else { + response.setError(500, "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error in save tb confirmed case details : ", e); + response.setError(500, "Error in save tb confirmed case details : " + e.getMessage()); + } + + return response.toString(); + } + + @Operation(summary = "get tb confirmed case by beneficiary id") + @RequestMapping(value = { "/confirmed/getAll" }, method = { RequestMethod.GET }) + public String getConfirmedByBenId( + @RequestHeader(value = "jwtToken") String token, + @RequestParam(required = false) Integer providerServiceMapID, + @RequestParam(required = false) Integer villageID) { + + OutputResponse response = new OutputResponse(); + + try { + String result = providerServiceMapID != null + ? tbConfirmedCaseService.getByProviderServiceMapId(providerServiceMapID, villageID) + : tbConfirmedCaseService.getByUserId(token); + + if (result != null) + response.setResponse(result); + else + response.setError(404, "No record found"); + + } catch (Exception e) { + logger.error("Error in get tb confirmed case details : ", e); + response.setError(500, "Error in get tb confirmed case details : " + e.getMessage()); + } + + return response.toString(); + } + + + } diff --git a/src/main/java/com/iemr/flw/controller/UwinSessionController.java b/src/main/java/com/iemr/flw/controller/UwinSessionController.java index 6fd31b16..6a273d9a 100644 --- a/src/main/java/com/iemr/flw/controller/UwinSessionController.java +++ b/src/main/java/com/iemr/flw/controller/UwinSessionController.java @@ -31,14 +31,14 @@ public class UwinSessionController { @Autowired private JwtUtil jwtUtil; - @RequestMapping(value = "saveAll", method = RequestMethod.POST, headers = "Authorization", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @RequestMapping(value = "saveAll", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity saveSession( @RequestPart("meetingDate") String meetingDate, @RequestPart("place") String place, @RequestPart("participants") String participants, @RequestPart("ashaId") String ashaId, @RequestPart("createdBy") String createdBy, - @RequestPart(value = "meetingImages", required = false) List images) throws Exception { + @RequestPart(value = "meetingImages", required = false) List images,@RequestHeader(value = "jwtToken") String jwtToken) throws Exception { Map response = new LinkedHashMap<>(); UwinSessionRequestDTO dto = new UwinSessionRequestDTO(); diff --git a/src/main/java/com/iemr/flw/controller/VillageLevelFormController.java b/src/main/java/com/iemr/flw/controller/VillageLevelFormController.java index ddbb7a76..8eb5eb41 100644 --- a/src/main/java/com/iemr/flw/controller/VillageLevelFormController.java +++ b/src/main/java/com/iemr/flw/controller/VillageLevelFormController.java @@ -36,121 +36,145 @@ import java.util.Map; @RestController -@RequestMapping(value = "/forms/villageLevel", headers = "Authorization") +@RequestMapping(value = "/forms/villageLevel") public class VillageLevelFormController { @Autowired private VillageLevelFormService villageLevelFormService; - @RequestMapping(value = "vhnd/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "vhnd/saveAll",method = RequestMethod.POST) public ResponseEntity> saveVhndForm(@RequestBody VhndDto dto) { Map response = new HashMap<>(); - if (!dto.getEntries().isEmpty()) { - Boolean isSaved = villageLevelFormService.saveForm(dto); - boolean ok = isSaved; - response.put("status", ok ? "Success" : "Fail"); - response.put("statusCode", ok ? 200 : 500); - response.put("message", "Save Successfully"); - return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); - - } else { + try { + if (!dto.getEntries().isEmpty()) { + Boolean isSaved = villageLevelFormService.saveForm(dto); + boolean ok = isSaved; + response.put("status", ok ? "Success" : "Fail"); + response.put("statusCode", ok ? 200 : 500); + response.put("message", "Save Successfully"); + return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); + + } else { + response.put("status", "Fail"); + response.put("statusCode", 400); + response.put("message", "Invalid Request Object"); + return ResponseEntity.ok(response); + + } + } catch (Exception e) { response.put("status", "Fail"); - response.put("statusCode", 400); - response.put("message", "Invalid Request Object"); - return ResponseEntity.ok(response); - + response.put("statusCode", 500); + response.put("errorMessage", e.getMessage()); + return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } - - } - @RequestMapping(value = "vhnc/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "vhnc/saveAll", method = RequestMethod.POST) public ResponseEntity> saveVhncForm(@RequestBody VhncDto dto) { Map response = new HashMap<>(); - if (!dto.getEntries().isEmpty()) { - Boolean isSaved = villageLevelFormService.saveVhncForm(dto); - boolean ok = isSaved; - response.put("status", ok ? "Success" : "Fail"); - response.put("statusCode", ok ? 200 : 500); - response.put("message", "Save Successfully"); - return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); - } else { + try { + if (!dto.getEntries().isEmpty()) { + Boolean isSaved = villageLevelFormService.saveVhncForm(dto); + boolean ok = isSaved; + response.put("status", ok ? "Success" : "Fail"); + response.put("statusCode", ok ? 200 : 500); + response.put("message", "Save Successfully"); + return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); + } else { + response.put("status", "Fail"); + response.put("statusCode", 400); + response.put("message", "Invalid Request Object"); + return ResponseEntity.ok(response); + } + } catch (Exception e) { response.put("status", "Fail"); - response.put("statusCode", 400); - response.put("message", "Invalid Request Object"); - return ResponseEntity.ok(response); - - + response.put("statusCode", 500); + response.put("errorMessage", e.getMessage()); + return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } - - } - @RequestMapping(value = "phc/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "phc/saveAll", method = RequestMethod.POST) public ResponseEntity> savePhcForm(@RequestBody PhcReviewMeetingDTO dto) { Map response = new HashMap<>(); - if (!dto.getEntries().isEmpty()) { - Boolean isSaved = villageLevelFormService.savePhcForm(dto); - boolean ok = isSaved; - response.put("status", ok ? "Success" : "Fail"); - response.put("statusCode", ok ? 200 : 500); - response.put("message", "Save Successfully"); - return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); - } else { + try { + if (!dto.getEntries().isEmpty()) { + Boolean isSaved = villageLevelFormService.savePhcForm(dto); + boolean ok = isSaved; + response.put("status", ok ? "Success" : "Fail"); + response.put("statusCode", ok ? 200 : 500); + response.put("message", "Save Successfully"); + return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); + } else { + response.put("status", "Fail"); + response.put("statusCode", 400); + response.put("message", "Invalid Request Object"); + return ResponseEntity.ok(response); + } + } catch (Exception e) { response.put("status", "Fail"); - response.put("statusCode", 400); - response.put("message", "Invalid Request Object"); - return ResponseEntity.ok(response); - + response.put("statusCode", 500); + response.put("errorMessage", e.getMessage()); + return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } - - } - @RequestMapping(value = "ahd/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "ahd/saveAll", method = RequestMethod.POST) public ResponseEntity> saveAhdForm(@RequestBody AhdMeetingDto dto) { Map response = new HashMap<>(); - if(!dto.getEntries().isEmpty()){ - Boolean isSaved = villageLevelFormService.saveAhdForm(dto); - boolean ok = isSaved; - response.put("status", ok ? "Success" : "Fail"); - response.put("statusCode", ok ? 200 : 500); - response.put("message", "Save Successfully"); - return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); - }else { + try { + if(!dto.getEntries().isEmpty()){ + Boolean isSaved = villageLevelFormService.saveAhdForm(dto); + boolean ok = isSaved; + response.put("status", ok ? "Success" : "Fail"); + response.put("statusCode", ok ? 200 : 500); + response.put("message", "Save Successfully"); + return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); + }else { + response.put("status", "Fail"); + response.put("statusCode", 400); + response.put("message", "Invalid Request Object"); + return ResponseEntity.ok(response); + } + } catch (Exception e) { response.put("status", "Fail"); - response.put("statusCode", 400); - response.put("message", "Invalid Request Object"); - return ResponseEntity.ok(response); + response.put("statusCode", 500); + response.put("errorMessage", e.getMessage()); + return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } - } - @RequestMapping(value = "deworming/saveAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "deworming/saveAll", method = RequestMethod.POST) public ResponseEntity> saveDewormingForm(@RequestBody DewormingDto dto) { Map response = new HashMap<>(); - if(!dto.getEntries().isEmpty()){ - Boolean isSaved = villageLevelFormService.saveDewormingForm(dto); - boolean ok = isSaved; - response.put("status", ok ? "Success" : "Fail"); - response.put("statusCode", ok ? 200 : 500); - response.put("message", "Save Successfully"); - return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); - }else { + try { + if(!dto.getEntries().isEmpty()){ + Boolean isSaved = villageLevelFormService.saveDewormingForm(dto); + boolean ok = isSaved; + response.put("status", ok ? "Success" : "Fail"); + response.put("statusCode", ok ? 200 : 500); + response.put("message", "Save Successfully"); + return new ResponseEntity<>(response, ok ? HttpStatus.OK : HttpStatus.INTERNAL_SERVER_ERROR); + }else { + response.put("status", "Fail"); + response.put("statusCode", 400); + response.put("message", "Invalid Request Object"); + return ResponseEntity.ok(response); + } + } catch (Exception e) { response.put("status", "Fail"); - response.put("statusCode", 400); - response.put("message", "Invalid Request Object"); - return ResponseEntity.ok(response); + response.put("statusCode", 500); + response.put("errorMessage", e.getMessage()); + return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } - } - @RequestMapping(value = "getAll", method = RequestMethod.POST, headers = "Authorization") + @RequestMapping(value = "getAll", method = RequestMethod.POST) public ResponseEntity> getVillageLevelFormData(@RequestBody GetVillageLevelRequestHandler getVillageLevelRequestHandler) { Map response = new LinkedHashMap<>(); diff --git a/src/main/java/com/iemr/flw/controller/health/HealthController.java b/src/main/java/com/iemr/flw/controller/health/HealthController.java new file mode 100644 index 00000000..93308554 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/health/HealthController.java @@ -0,0 +1,83 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +package com.iemr.flw.controller.health; + +import java.time.Instant; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.iemr.flw.service.health.HealthService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +@RestController +@RequestMapping("/health") +@Tag(name = "Health Check", description = "APIs for checking infrastructure health status") +public class HealthController { + + private static final Logger logger = LoggerFactory.getLogger(HealthController.class); + + private final HealthService healthService; + + public HealthController(HealthService healthService) { + this.healthService = healthService; + } + + @GetMapping + @Operation(summary = "Check infrastructure health", + description = "Returns the health status of MySQL, Redis, and other configured services") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "Services are UP or DEGRADED (operational with warnings)"), + @ApiResponse(responseCode = "503", description = "One or more critical services are DOWN") + }) + public ResponseEntity> checkHealth() { + logger.debug("Health check endpoint called"); + + try { + Map healthStatus = healthService.checkHealth(); + String overallStatus = (String) healthStatus.get("status"); + + HttpStatus httpStatus = "DOWN".equals(overallStatus) ? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.OK; + + logger.debug("Health check completed with status: {}", overallStatus); + return new ResponseEntity<>(healthStatus, httpStatus); + + } catch (Exception e) { + logger.error("Unexpected error during health check", e); + + Map errorResponse = Map.of( + "status", "DOWN", + "timestamp", Instant.now().toString() + ); + + return new ResponseEntity<>(errorResponse, HttpStatus.SERVICE_UNAVAILABLE); + } + } +} diff --git a/src/main/java/com/iemr/flw/controller/version/VersionController.java b/src/main/java/com/iemr/flw/controller/version/VersionController.java new file mode 100644 index 00000000..f2f2bf66 --- /dev/null +++ b/src/main/java/com/iemr/flw/controller/version/VersionController.java @@ -0,0 +1,80 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +package com.iemr.flw.controller.version; + +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; + +@RestController +public class VersionController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + + private static final String UNKNOWN_VALUE = "unknown"; + + @Operation(summary = "Get version information") + @GetMapping(value = "/version", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity> versionInformation() { + Map response = new LinkedHashMap<>(); + try { + logger.info("version Controller Start"); + Properties gitProperties = loadGitProperties(); + response.put("buildTimestamp", gitProperties.getProperty("git.build.time", UNKNOWN_VALUE)); + response.put("version", gitProperties.getProperty("git.build.version", UNKNOWN_VALUE)); + response.put("branch", gitProperties.getProperty("git.branch", UNKNOWN_VALUE)); + response.put("commitHash", gitProperties.getProperty("git.commit.id.abbrev", UNKNOWN_VALUE)); + } catch (Exception e) { + logger.error("Failed to load version information", e); + response.put("buildTimestamp", UNKNOWN_VALUE); + response.put("version", UNKNOWN_VALUE); + response.put("branch", UNKNOWN_VALUE); + response.put("commitHash", UNKNOWN_VALUE); + } + logger.info("version Controller End"); + return ResponseEntity.ok(response); + } + + private Properties loadGitProperties() throws IOException { + Properties properties = new Properties(); + try (InputStream input = getClass().getClassLoader() + .getResourceAsStream("git.properties")) { + if (input != null) { + properties.load(input); + } + } + return properties; + } +} diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java index ac336da1..e227776c 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHBeneficiaryDetailsRmnch.java @@ -102,6 +102,28 @@ public class RMNCHBeneficiaryDetailsRmnch { @Column(name = "longitude") private BigDecimal longitude; + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Expose + @Column(name = "digipin") + private String digipin; + + @Expose + @Column(name = "gpsTimestamp") + private Timestamp gpsTimestamp; + + @Expose + @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") + private Boolean isGpsUnavailable = false; + + @Expose + @Column(name = "gpsUnavailableReason") + private String gpsUnavailableReason; + @Expose @Column(name = "menstrualBFDId") private Integer menstrualBFDId; @@ -386,6 +408,9 @@ public class RMNCHBeneficiaryDetailsRmnch { @Expose private Integer noofAlivechildren; + @Expose + private Boolean isDeactivate; + @Expose @Transient private Integer servicePointID; @@ -409,6 +434,9 @@ public class RMNCHBeneficiaryDetailsRmnch { @Expose @Transient private String addressLine3; + @Expose + @Transient + private String pinCode; // ---------------------------------------------- @@ -518,4 +546,31 @@ public class RMNCHBeneficiaryDetailsRmnch { @Column(name = "noOfDaysForDelivery") private Integer noOfDaysForDelivery; + @Expose + @Transient + private String occupation; + @Expose + @Transient + private String economicStatus; + @Expose + @Transient + private Integer economicStatusId; + @Expose + @Transient + private String residentialArea; + @Expose + @Transient + private Integer residentialAreaId; + + public String getOccupation() { return occupation; } + public void setOccupation(String occupation) { this.occupation = occupation; } + public String getEconomicStatus() { return economicStatus; } + public void setEconomicStatus(String economicStatus) { this.economicStatus = economicStatus; } + public Integer getEconomicStatusId() { return economicStatusId; } + public void setEconomicStatusId(Integer economicStatusId) { this.economicStatusId = economicStatusId; } + public String getResidentialArea() { return residentialArea; } + public void setResidentialArea(String residentialArea) { this.residentialArea = residentialArea; } + public Integer getResidentialAreaId() { return residentialAreaId; } + public void setResidentialAreaId(Integer residentialAreaId) { this.residentialAreaId = residentialAreaId; } + } diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java index 9ab4f822..a0a0adf1 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHHouseHoldDetails.java @@ -325,4 +325,16 @@ public class RMNCHHouseHoldDetails { @Column(name = "mohallaName") private String mohallaName; + @Expose + @Column(name = "isDeactivate") + private Boolean isDeactivate; + + @Expose + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Expose + @Column(name = "gpsLongitude") + private Double gpsLongitude; + } diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java index c9468688..a589ec7a 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiaryaddress.java @@ -247,4 +247,22 @@ public class RMNCHMBeneficiaryaddress implements Serializable { @Expose @Column(name = "SyncedDate") private Timestamp SyncedDate; + + @Column(name = "gpsLatitude") + private Double gpsLatitude; + + @Column(name = "gpsLongitude") + private Double gpsLongitude; + + @Column(name = "digipin") + private String digipin; + + @Column(name = "gpsTimestamp") + private Timestamp gpsTimestamp; + + @Column(name = "isGpsUnavailable", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") + private Boolean isGpsUnavailable = false; + + @Column(name = "gpsUnavailableReason") + private String gpsUnavailableReason; } diff --git a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java index 72e994f5..1a4cec51 100644 --- a/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java +++ b/src/main/java/com/iemr/flw/domain/identity/RMNCHMBeneficiarydetail.java @@ -186,4 +186,31 @@ public class RMNCHMBeneficiarydetail { @Transient private Integer ProviderServiceMapID; + @Expose + @Column(name = "familyid") + private String familyId; + + @Column(name = "ExtraFields") + private String otherFields; + + @Expose + @Column(name = "economicStatus") + private String economicStatus; + + @Expose + @Column(name = "economicStatusId") + private Integer economicStatusId; + + @Expose + @Column(name = "residentialArea") + private String residentialArea; + + @Expose + @Column(name = "residentialAreaId") + private Integer residentialAreaId; + + @Expose + @Column(name = "address") + private String address; + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java b/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java index c5240d1c..4128f082 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ANCVisit.java @@ -167,6 +167,12 @@ public class ANCVisit { @Column(name = "date_of_sterilisation") private Timestamp dateSterilisation; + @Column (name = "place_of_anc") + private String placeOfAnc; + + @Column(name = "place_of_ancId") + private Integer placeOfAncId; + diff --git a/src/main/java/com/iemr/flw/domain/iemr/AbhaApiResponse.java b/src/main/java/com/iemr/flw/domain/iemr/AbhaApiResponse.java new file mode 100644 index 00000000..db38d11a --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/AbhaApiResponse.java @@ -0,0 +1,21 @@ +package com.iemr.flw.domain.iemr; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; +import lombok.Data; + +import java.util.List; + +@Data +public class AbhaApiResponse { + + @JsonProperty("status_code") + private String statusCode; + + private String message; + + @JsonProperty("data") + @JsonAlias("object_data") + private List data; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java new file mode 100644 index 00000000..46737f12 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/AncCounsellingCare.java @@ -0,0 +1,128 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "anc_counselling_care", schema = "db_iemr") +@Data +public class AncCounsellingCare { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "beneficiary_id", nullable = false) + private Long beneficiaryId; + + @Column(name = "visit_date") + private LocalDate visitDate; + + @Column(name = "home_visit_date", nullable = false) + private LocalDate homeVisitDate; + + @Column(name = "anc_visit_id", nullable = false) + private Long ancVisitId; + + @Column(name = "user_id") + private Integer userId; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "updated_by") + private String updatedBy; + + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + /* ---------- BOOLEAN FLAGS ---------- */ + + @Column(name = "select_all") + private Boolean selectAll = false; + + @Column(name = "swelling") + private Boolean swelling = false; + + @Column(name = "high_bp") + private Boolean highBp = false; + + @Column(name = "convulsions") + private Boolean convulsions = false; + + @Column(name = "anemia") + private Boolean anemia = false; + + @Column(name = "reduced_fetal_movement") + private Boolean reducedFetalMovement = false; + + @Column(name = "age_risk") + private Boolean ageRisk = false; + + @Column(name = "child_gap") + private Boolean childGap = false; + + @Column(name = "short_height") + private Boolean shortHeight = false; + + @Column(name = "pre_preg_weight") + private Boolean prePregWeight = false; + + @Column(name = "bleeding") + private Boolean bleeding = false; + + @Column(name = "miscarriage_history") + private Boolean miscarriageHistory = false; + + @Column(name = "four_plus_delivery") + private Boolean fourPlusDelivery = false; + + @Column(name = "first_delivery") + private Boolean firstDelivery = false; + + @Column(name = "twin_pregnancy") + private Boolean twinPregnancy = false; + + @Column(name = "c_section_history") + private Boolean cSectionHistory = false; + + @Column(name = "pre_existing_disease") + private Boolean preExistingDisease = false; + + @Column(name = "fever_malaria") + private Boolean feverMalaria = false; + + @Column(name = "jaundice") + private Boolean jaundice = false; + + @Column(name = "sickle_cell") + private Boolean sickleCell = false; + + @Column(name = "prolonged_labor") + private Boolean prolongedLabor = false; + + @Column(name = "malpresentation") + private Boolean malpresentation = false; + + /* ---------- Lifecycle Hooks ---------- */ + + @PrePersist + protected void onCreate() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedAt = LocalDateTime.now(); + } + + /* ---------- Getters & Setters ---------- */ + // Lombok use kar raha ho toh @Getter @Setter laga sakta hai +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java b/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java new file mode 100644 index 00000000..ee641db8 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/AshaSupervisorMapping.java @@ -0,0 +1,34 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "asha_supervisor_mapping") +@Data +@NoArgsConstructor +public class AshaSupervisorMapping { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "supervisorUserID") + private Integer supervisorUserID; + + @Column(name = "ashaUserID") + private Integer ashaUserID; + + @Column(name = "facilityID") + private Integer facilityID; + + @Column(name = "deleted", insertable = false, updatable = true) + private Boolean deleted; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java b/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java index 36fba04e..2df2bf43 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java +++ b/src/main/java/com/iemr/flw/domain/iemr/AshaWorker.java @@ -27,7 +27,7 @@ public class AshaWorker { private Integer employeeId; // Changed from Integer to String @Column(name = "dob") - private LocalDate dob; // Changed from String to LocalDate + private String dob; // Changed from String to LocalDate @Column(name = "mobile_number") @@ -40,7 +40,7 @@ public class AshaWorker { private String fatherOrSpouseName; @Column(name = "date_of_joining") - private LocalDate dateOfJoining; // Changed from String to LocalDate + private String dateOfJoining; // Changed from String to LocalDate @Column(name = "bank_account") @@ -98,8 +98,9 @@ public class AshaWorker { @Column(name = "ProviderServiceMapID") private Integer ProviderServiceMapID; + @Lob @Column(name = "profileImage") - private String profileImage; + private byte[] profileImage; @Column(name = "isFatherOrSpouse") private Boolean isFatherOrSpouse; diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenAnthropometryDetail.java b/src/main/java/com/iemr/flw/domain/iemr/BenAnthropometryDetail.java new file mode 100644 index 00000000..777e8011 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/BenAnthropometryDetail.java @@ -0,0 +1,70 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import java.sql.Timestamp; + +@Entity +@Table(name = "t_phy_anthropometry", schema = "db_iemr") +@Data +public class BenAnthropometryDetail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID") + private Long id; + + @Column(name = "BeneficiaryRegID") + private Long beneficiaryRegID; + + @Column(name = "BenVisitID") + private Long benVisitID; + + @Column(name = "ProviderServiceMapID") + private Integer providerServiceMapID; + + @Column(name = "VisitCode") + private Long visitCode; + + @Column(name = "Weight_Kg") + private Double weightKg; + + @Column(name = "Height_cm") + private Double heightCm; + + @Column(name = "BMI") + private Double bmi; + + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + + @Column(name = "Processed", insertable = false, updatable = true) + private String processed; + + @Column(name = "CreatedBy") + private String createdBy; + + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + + @Column(name = "ModifiedBy") + private String modifiedBy; + + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; + + @Column(name = "VanSerialNo") + private Long vanSerialNo; + + @Column(name = "VanID") + private Integer vanID; + + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "SyncedBy") + private String syncedBy; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenChiefComplaint.java b/src/main/java/com/iemr/flw/domain/iemr/BenChiefComplaint.java new file mode 100644 index 00000000..3b016c5f --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/BenChiefComplaint.java @@ -0,0 +1,73 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import java.sql.Timestamp; + +@Entity +@Table(name = "t_benchiefcomplaint", schema = "db_iemr") +@Data +public class BenChiefComplaint { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID") + private Long id; + + @Column(name = "BeneficiaryRegID") + private Long beneficiaryRegID; + + @Column(name = "BenVisitID") + private Long benVisitID; + + @Column(name = "ProviderServiceMapID") + private Integer providerServiceMapID; + + @Column(name = "VisitCode") + private Long visitCode; + + @Column(name = "ChiefComplaint") + private String chiefComplaint; + + @Column(name = "Duration") + private Integer duration; + + @Column(name = "UnitOfDuration") + private String unitOfDuration; + + @Column(name = "Description") + private String description; + + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + + @Column(name = "Processed", insertable = false, updatable = true) + private String processed; + + @Column(name = "CreatedBy") + private String createdBy; + + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + + @Column(name = "ModifiedBy") + private String modifiedBy; + + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; + + @Column(name = "VanSerialNo") + private Long vanSerialNo; + + @Column(name = "VanID") + private Integer vanID; + + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "SyncedBy") + private String syncedBy; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenFlowStatus.java b/src/main/java/com/iemr/flw/domain/iemr/BenFlowStatus.java new file mode 100644 index 00000000..b4600e26 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/BenFlowStatus.java @@ -0,0 +1,82 @@ +package com.iemr.flw.domain.iemr; + +import lombok.Data; +import jakarta.persistence.*; +import java.sql.Timestamp; + +@Entity +@Table(name = "i_ben_flow_outreach") +@Data +public class BenFlowStatus { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ben_flow_id") + private Long benFlowID; + + @Column(name = "beneficiary_reg_id") + private Long beneficiaryRegID; + + @Column(name = "beneficiary_id") + private Long beneficiaryID; + + @Column(name = "visit_category") + private String visitCategory; + + @Column(name = "nurse_flag") + private Short nurseFlag; + + @Column(name = "doctor_flag") + private Short doctorFlag; + + @Column(name = "pharmacist_flag") + private Short pharmacistFlag; + + @Column(name = "providerServiceMapID") + private Integer providerServiceMapId; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "ben_name") + private String benName; + + @Column(name = "ben_age_val") + private Integer benAgeVal; + + @Column(name = "ben_dob") + private Timestamp dob; + + @Column(name = "ben_gender_val") + private Short genderID; + + @Column(name = "ben_gender") + private String genderName; + + @Column(name = "ben_phone_no") + private String preferredPhoneNum; + + @Column(name = "districtID") + private Integer districtID; + + @Column(name = "district") + private String districtName; + + @Column(name = "villageID") + private Integer villageID; + + @Column(name = "village") + private String villageName; + + @Column(name = "registrationDate") + private Timestamp registrationDate; + + @Column(name = "created_by") + private String agentId; + + @Column(name = "created_date", insertable = false, updatable = false) + private Timestamp visitDate; + + @Column(name = "deleted", insertable = false) + private Boolean deleted; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/BenPhysicalVitalDetail.java b/src/main/java/com/iemr/flw/domain/iemr/BenPhysicalVitalDetail.java new file mode 100644 index 00000000..15b03aee --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/BenPhysicalVitalDetail.java @@ -0,0 +1,76 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import java.sql.Timestamp; + +@Entity +@Table(name = "t_phy_vitals", schema = "db_iemr") +@Data +public class BenPhysicalVitalDetail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID") + private Long id; + + @Column(name = "BeneficiaryRegID") + private Long beneficiaryRegID; + + @Column(name = "BenVisitID") + private Long benVisitID; + + @Column(name = "ProviderServiceMapID") + private Integer providerServiceMapID; + + @Column(name = "VisitCode") + private Long visitCode; + + @Column(name = "Temperature") + private Double temperature; + + @Column(name = "PulseRate") + private Short pulseRate; + + @Column(name = "SystolicBP_1stReading") + private Short systolicBP; + + @Column(name = "DiastolicBP_1stReading") + private Short diastolicBP; + + @Column(name = "BloodGlucose_Random") + private Short bloodGlucoseRandom; + + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + + @Column(name = "Processed", insertable = false, updatable = true) + private String processed; + + @Column(name = "CreatedBy") + private String createdBy; + + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + + @Column(name = "ModifiedBy") + private String modifiedBy; + + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; + + @Column(name = "VanSerialNo") + private Long vanSerialNo; + + @Column(name = "VanID") + private Integer vanID; + + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "SyncedBy") + private String syncedBy; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java b/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java new file mode 100644 index 00000000..e33e1543 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/CampaignOrs.java @@ -0,0 +1,59 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "campaign_ors",schema = "db_iemr") +@Data +public class CampaignOrs { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "start_date", nullable = false) + private LocalDate startDate; + + @Column(name = "end_date", nullable = false) + private LocalDate endDate; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "number_of_families", nullable = false) + private Integer numberOfFamilies = 0; + + @Column(name = "campaign_photos",columnDefinition = "LONGTEXT") + private String campaignPhotos; + + @Column(name = "created_by", length = 200) + private String createdBy; + + @Column(name = "updated_by", length = 200) + private String updatedBy; + + @Column(name = "created_date", updatable = false) + private LocalDateTime createdDate; + + @Column(name = "updated_date") + private LocalDateTime updatedDate; + + /* ---------- Auto timestamps ---------- */ + + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.updatedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedDate = LocalDateTime.now(); + } + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java b/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java new file mode 100644 index 00000000..989ed1d1 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/CbacDetailsImer.java @@ -0,0 +1,330 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ +package com.iemr.flw.domain.iemr; + +import java.sql.Timestamp; + +import jakarta.persistence.*; + +import com.google.gson.annotations.Expose; +import lombok.Data; + +@Entity +@Table(name = "t_cbacdetails") +@Data +public class CbacDetailsImer { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Expose + @Column(name = "Id", insertable = false) + private Long id; + @Expose + @Column(name = "BeneficiaryRegId") + private Long beneficiaryRegId; + + @Expose + @Column(name = "Visitcode") + private Long visitCode; + @Expose + @Column(name = "Cbac_Age") + private String cbacAge; + @Expose + @Column(name = "Cbac_Age_Score") + private Integer cbacAgeScore; + @Expose + @Column(name = "Cbac_ConusmeGutka") + private String cbacConsumeGutka; + @Expose + @Column(name = "Cbac_ConusmeGutka_Score") + private Integer cbacConsumeGutkaScore; + @Expose + @Column(name = "cbac_alcohol") + private String cbacAlcohol; + @Expose + @Column(name = "cbac_alcohol_Score") + private Integer cbacAlcoholScore; + @Expose + @Column(name = "Cbac_waist_Male") + private String cbacWaistMale; + @Expose + @Column(name = "Cbac_waist_Male_Score") + private Integer cbacWaistMaleScore; + @Expose + @Column(name = "Cbac_Waist_Female") + private String cbacWaistFemale; + @Expose + @Column(name = "Cbac_Waist_Female_Score") + private Integer cbacWaistFemaleScore; + @Expose + @Column(name = "Cbac_PhysicalActivity") + private String cbacPhysicalActivity; + @Expose + @Column(name = "Cbac_PhysicalActivity_Score") + private Integer cbacPhysicalActivityScore; + @Expose + @Column(name = "Cbac_FamilyHistory_bpdiabetes") + private String cbacFamilyHistoryBpdiabetes; + @Expose + @Column(name = "Cbac_FamilyHistory_bpdiabetes_Score") + private Integer cbacFamilyHistoryBpdiabetesScore; + @Expose + @Column(name = "Cbac_ShortnessBreath") + private String cbacShortnessBreath; + @Expose + @Column(name = "Cbac_Cough2weeks") + private String cbacCough2weeks; + @Expose + @Column(name = "Cbac_Bloodsputum") + private String cbacBloodsputum; + @Expose + @Column(name = "Cbac_fever2weeks") + private String cbacFever2weeks; + @Expose + @Column(name = "Cbac_WeightLoss") + private String cbacWeightLoss; + @Expose + @Column(name = "Cbac_NightSweats") + private String cbacNightSweats; + @Expose + @Column(name = "Cbac_AntiTBDrugs") + private String cbacAntiTBDrugs; + @Expose + @Column(name = "Cabc_TB") + private String cbacTb; + @Expose + @Column(name = "Cbac_TBHistory") + private String cbacTBHistory; + @Expose + @Column(name = "Cbac_Ulceration") + private String cbacUlceration; + @Expose + @Column(name = "Cbac_RecurrentTingling") + private String cbacRecurrentTingling; + @Expose + @Column(name = "Cbac_FitsHistory") + private String cbacFitsHistory; + @Expose + @Column(name = "Cbac_MouthopeningDifficulty") + private String cbacMouthopeningDifficulty; + @Expose + @Column(name = "Cbac_MouthUlcers") + private String cbacMouthUlcers; + @Expose + @Column(name = "Cbac_MouthUlcersGrowth") + private String cbacMouthUlcersGrowth; + @Expose + @Column(name = "Cbac_Mouthredpatch") + private String cbacMouthredpatch; + @Expose + @Column(name = "Cbac_Painchewing") + private String cbacPainchewing; + @Expose + @Column(name = "Cbac_Tonechange") + private String cbacTonechange; + @Expose + @Column(name = "Cbac_Hypopigmentedpatches") + private String cbacHypopigmentedpatches; + @Expose + @Column(name = "Cbac_Thickenedskin") + private String cbacThickenedskin; + @Expose + @Column(name = "Cbac_Nodulesonskin") + private String cbacNodulesonskin; + @Expose + @Column(name = "Cbac_RecurrentNumbness") + private String cbacRecurrentNumbness; + @Expose + @Column(name = "Cbac_BlurredVision") + private String cbacBlurredVision; + @Expose + @Column(name = "Cbac_Difficultyreading") + private String cbacDifficultyreading; + @Expose + @Column(name = "Cbac_Painineyes") + private String cbacPainineyes; + @Expose + @Column(name = "Cbac_RednessPain") + private String cbacRednessPain; + @Expose + @Column(name = "Cbac_DifficultyHearing") + private String cbacDifficultyHearing; + @Expose + @Column(name = "Cbac_Clawingfingers") + private String cbacClawingfingers; + @Expose + @Column(name = "Cbac_HandTingling") + private String cbacHandTingling; + @Expose + @Column(name = "Cbac_InabilityCloseeyelid") + private String cbacInabilityCloseeyelid; + @Expose + @Column(name = "Cbac_DifficultHoldingObjects") + private String cbacDifficultHoldingObjects; + @Expose + @Column(name = "Cbac_Feetweakness") + private String cbacFeetweakness; + @Expose + @Column(name = "Cbac_LumpBreast") + private String cbacLumpBreast; + @Expose + @Column(name = "Cbac_BloodnippleDischarge") + private String cbacBloodnippleDischarge; + @Expose + @Column(name = "Cbac_Breastsizechange") + private String cbacBreastsizechange; + @Expose + @Column(name = "Cbac_BleedingPeriods") + private String cbacBleedingPeriods; + @Expose + @Column(name = "Cbac_BleedingMenopause") + private String cbacBleedingMenopause; + @Expose + @Column(name = "Cbac_BleedingIntercourse") + private String cbacBleedingIntercourse; + @Expose + @Column(name = "Cbac_VaginalDischarge") + private String cbacVaginalDischarge; + @Expose + @Column(name = "Cbac_FeelingUnsteady") + private String cbacFeelingUnsteady; + @Expose + @Column(name = "Cbac_PhysicalDisabilitySuffering") + private String cbacPhysicalDisabilitySuffering; + @Expose + @Column(name = "Cbac_NeedhelpEverydayActivities") + private String cbacNeedhelpEverydayActivities; + @Expose + @Column(name = "Cbac_Forgetnearones") + private String cbacForgetnearones; + @Expose + @Column(name = "ProviderServiceMapID") + private Integer providerServiceMapId; + + @Expose + @Column(name = "Total_Score") + private Integer totalScore; + @Expose + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + + @Expose + @Column(name = "Processed", insertable = false, updatable = true) + private Character processed; + + @Expose + @Column(name = "CreatedBy") + private String createdBy; + + @Expose + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + + @Expose + @Column(name = "ModifiedBy") + private String modifiedBy; + + @Expose + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; + + @Expose + @Column(name = "VanSerialNo") + private Integer vanSerialNo; + @Expose + @Column(name = "VanID") + private Integer vanId; + @Expose + @Column(name = "VehicalNo") + private String vehicalNo; + @Expose + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceId; + @Expose + @Column(name = "SyncedBy") + private String syncedBy; + @Expose + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Transient + @Expose + private Long beneficiaryId; + + @Expose + @Column(name = "Cbac_OccupationalExposure") + private String CbacOccupationalExposure; + + @Expose + @Column(name = "Cbac_BotheredProblem_last2weeks") + private String CbacBotheredProblemLast2weeks; + + @Expose + @Column(name = "Cbac_LittleInterest_Pleasure") + private String CbacLittleInterestPleasure; + + @Expose + @Column(name = "Cbac_Depressed_hopeless") + private String CbacDepressedhopeless; + + @Expose + @Column(name = "Cbac_DiscolorationSkin") + private String CbacDiscolorationSkin; + + @Expose + @Column(name = "Cbac_Cooking_Oil") + private String CbacCookingOil; + + @Expose + @Column(name = "Cbac_OccupationalExposure_score") + private String CbacOccupationalExposureScore; + + @Expose + @Column(name = "Cbac_BotheredProblem_last2weeks_score") + private String CbacBotheredProblemLast2weeksScore; + + @Expose + @Column(name = "Cbac_LittleInterest_Pleasure_score") + private String CbacLittleInterestPleasureScore; + + @Expose + @Column(name = "Cbac_Depressed_hopeless_score") + private String CbacDepressedhopelessScore; + + @Expose + @Column(name = "Cbac_Cooking_Oil_score") + private String CbacCookingOilScore; + + + @Expose + @Column(name = "Cbac_Feeling_Down_score") + private String CbacFeelingDownScore; + + @Expose + @Column(name = "is_refer") + private Boolean isRefer; + + + + + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/ChildVaccination.java b/src/main/java/com/iemr/flw/domain/iemr/ChildVaccination.java index 45d5562e..4050b77c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ChildVaccination.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ChildVaccination.java @@ -10,6 +10,7 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import jakarta.persistence.Transient; +import org.checkerframework.checker.units.qual.C; @Entity @Table(name = "t_childvaccinedetail1", schema = "db_iemr", catalog = "") @@ -17,6 +18,8 @@ public class ChildVaccination { private long id; private Long beneficiaryRegId; private Long benVisitId; + + private Long ProviderServiceMapID; private String defaultReceivingAge; private Integer vaccineId; private String vaccineName; @@ -314,4 +317,14 @@ public String getReservedForChange() { public void setReservedForChange(String reservedForChange) { this.reservedForChange = reservedForChange; } + + @Basic + @Column(name = "ProviderServiceMapID") + public Long getProviderServiceMapID() { + return ProviderServiceMapID; + } + + public void setProviderServiceMapID(Long providerServiceMapID) { + ProviderServiceMapID = providerServiceMapID; + } } diff --git a/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java b/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java new file mode 100644 index 00000000..10689cff --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/ChronicDiseaseVisitEntity.java @@ -0,0 +1,75 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "cdtf_visit_details") +@Data +public class ChronicDiseaseVisitEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "beneficiary_id") + private Long benId; + + @Column(name = "household_id") + private Long hhId; + + @Column(name = "form_id") + private String formId; + + @Column(name = "version") + private Integer version; + + @Column(name = "visit_no") + private Integer visitNo; + + @Column(name = "follow_up_no") + private Integer followUpNo; + + @Column(name = "diagnosis_codes", columnDefinition = "TEXT") + private String diagnosisCodes; + + @Column(name = "treatment_start_date") + private LocalDate treatmentStartDate; + + @Column(name = "follow_up_date") + private LocalDate followUpDate; + + @Column(name = "form_data_json", columnDefinition = "JSON") + private String formDataJson; + + @Column(name = "user_id") + private Integer userID; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "created_date") + private LocalDateTime createdDate; + + @Column(name = "updated_by") + private Integer updatedBy; + + @Column(name = "updated_date") + private LocalDateTime updatedDate; + + // 🔹 Auto timestamps + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.updatedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedDate = LocalDateTime.now(); + } + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java b/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java index 6050fab5..d3a1b56c 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java +++ b/src/main/java/com/iemr/flw/domain/iemr/DeliveryOutcome.java @@ -17,7 +17,6 @@ public class DeliveryOutcome { @Column(name = "ben_id") private Long benId; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MMM dd, yyyy, h:mm:ss a") @Column(name = "delivery_date") private Timestamp dateOfDelivery; @@ -54,7 +53,6 @@ public class DeliveryOutcome { @Column(name = "still_birth") private Integer stillBirth; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "MMM dd, yyyy, h:mm:ss a") @Column(name = "discharge_date") private Timestamp dateOfDischarge; diff --git a/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java b/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java new file mode 100644 index 00000000..af183d66 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/DynamicForm.java @@ -0,0 +1,128 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import com.iemr.flw.masterEnum.FormType; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Table; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +/** + * Root entity for a dynamic form definition (e.g. TB Counselling Form). + */ +@Entity +@Table(name = "t_dynamic_form", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DynamicForm { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "formId") + private Long formId; + + @Column(name = "formUuid", unique = true, nullable = false, length = 100) + private String formUuid; + + @Column(name = "formName", nullable = false, length = 255) + private String formName; + + @Enumerated(EnumType.STRING) + @Column(name = "formType", nullable = false, length = 50) + private FormType formType; + + @Column(name = "isActive", nullable = false) + private Boolean isActive = true; + + /** Days after the most-recently-completed section before the next follow-up notification fires. + * Null means no follow-up notifications for this form. */ + @Column(name = "follow_up_delay_days") + private Integer followUpDelayDays; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @Column(name = "createdAt", nullable = false, updatable = false) + private Timestamp createdAt; + + @Column(name = "updatedAt", nullable = false) + private Timestamp updatedAt; + + @OneToMany(mappedBy = "dynamicForm", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @ToString.Exclude + private List versions = new ArrayList<>(); + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; + + @PrePersist + protected void onCreate() { + createdAt = new Timestamp(System.currentTimeMillis()); + updatedAt = new Timestamp(System.currentTimeMillis()); + } + + @PreUpdate + protected void onUpdate() { + updatedAt = new Timestamp(System.currentTimeMillis()); + } +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java b/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java new file mode 100644 index 00000000..2f0c12ad --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/FilariasisCampaign.java @@ -0,0 +1,66 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "campaign_filariasis_mda",schema = "db_iemr") +@Data +public class FilariasisCampaign { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "start_date", nullable = false) + private LocalDate startDate; + + @Column(name = "end_date", nullable = false) + private LocalDate endDate; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "number_of_families", nullable = false) + private Integer numberOfFamilies = 0; + + @Column(name = "number_of_individuals", nullable = false) + private Integer numberOfIndividuals = 0; + + /** + * Store JSON array like ["img1.jpg","img2.jpg"] + * MySQL JSON column + */ + @Column(name = "mda_photos", columnDefinition = "json") + private String campaignPhotos; + + @Column(name = "created_by", length = 200) + private String createdBy; + + @Column(name = "updated_by", length = 200) + private String updatedBy; + + @Column(name = "created_date", updatable = false) + private LocalDateTime createdDate; + + @Column(name = "updated_date") + private LocalDateTime updatedDate; + + /* ---------- Auto timestamps ---------- */ + + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.updatedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedDate = LocalDateTime.now(); + } + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java b/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java new file mode 100644 index 00000000..8b338ee5 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/FormResponse.java @@ -0,0 +1,137 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; + +/** + * Root entity for a beneficiary's response to a dynamic form. + * Tracks the exact form version used and the status lifecycle (DRAFT → SUBMITTED → COMPLETE). + * + * @author Piramal Swasthya + */ +@Entity +@Table(name = "t_form_response", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class FormResponse { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "responseId") + private Long responseId; + + @Column(name = "beneficiaryId", nullable = false) + private Long beneficiaryId; + + /** Denormalized from versionId for fast form-level queries. */ + @Column(name = "formId", nullable = false) + private Long formId; + + /** Exact FormVersion active at submission time — resolved server-side from isLatest=true. */ + @Column(name = "versionId", nullable = false) + private Long versionId; + + /** Logged-in ASHA/officer ID from the request body. */ + @Column(name = "officerId", nullable = false) + private Long officerId; + + /** DRAFT | SUBMITTED | COMPLETE */ + @Column(name = "status", nullable = false, length = 20) + private String status; + + /** Set when PRE_SUBMIT sections are saved via /submit. */ + @Column(name = "submittedAt") + private Timestamp submittedAt; + + /** Set when POST_SUBMIT sections are saved via /complete. */ + @Column(name = "completedAt") + private Timestamp completedAt; + + /** Updated to now() each time the most-recently-completed section is saved (PRE_SUBMIT or any + * POST_SUBMIT section). The follow-up notification scheduler uses this as its reference date. */ + @Column(name = "last_follow_up_at") + private Timestamp lastFollowUpAt; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @Column(name = "createdAt", nullable = false, updatable = false) + private Timestamp createdAt; + + @Column(name = "updatedAt", nullable = false) + private Timestamp updatedAt; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + @Builder.Default + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; + + @PrePersist + protected void onCreate() { + createdAt = new Timestamp(System.currentTimeMillis()); + updatedAt = new Timestamp(System.currentTimeMillis()); + if (status == null) { + status = "DRAFT"; + } + } + + @PreUpdate + protected void onUpdate() { + updatedAt = new Timestamp(System.currentTimeMillis()); + } +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormSection.java b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java new file mode 100644 index 00000000..b8454716 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/FormSection.java @@ -0,0 +1,118 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +/** + * A section within a dynamic form version (e.g. "Section A: Disease Awareness"). + * Each section belongs to exactly one FormVersion via the version_id FK. + */ +@Entity +@Table(name = "t_form_section", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FormSection { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "sectionId") + private Long sectionId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "version_id", nullable = false) + @ToString.Exclude + private FormVersion formVersion; + + @Column(name = "sectionUuid", nullable = false, length = 100) + private String sectionUuid; + + @Column(name = "sectionName", nullable = false, length = 255) + private String sectionName; + + @Column(name = "sectionName_hindi", length = 255) + private String sectionNameHindi; + + /** PRE_SUBMIT sections are shown before the form's main submit. POST_SUBMIT after. */ + @Column(name = "sectionPhase", nullable = false, length = 20) + private String sectionPhase; + + @Column(name = "isRequired", nullable = false) + private Boolean isRequired = true; + + @Column(name = "displayOrder", nullable = false) + private Integer displayOrder; + + /** True only on the last PRE_SUBMIT section — renders the Submit button. */ + @Column(name = "hasSubmitButton", nullable = false) + private Boolean hasSubmitButton = false; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @OneToMany(mappedBy = "formSection", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @ToString.Exclude + private List questions = new ArrayList<>(); + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java b/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java new file mode 100644 index 00000000..5902aa21 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/FormVersion.java @@ -0,0 +1,115 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.PrePersist; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +/** + * A versioned snapshot of a dynamic form's section structure. + * Every structural change creates a new FormVersion; only one version has isLatest=true per form. + * + * @author Piramal Swasthya + */ +@Entity +@Table(name = "t_form_version", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FormVersion { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "versionId") + private Long versionId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "formId", nullable = false) + @ToString.Exclude + private DynamicForm dynamicForm; + + @Column(name = "versionNumber", nullable = false) + private Integer versionNumber; + + @Column(name = "isLatest", nullable = false) + private Boolean isLatest = true; + + @Column(name = "createdAt", nullable = false, updatable = false) + private Timestamp createdAt; + + @Column(name = "createdBy", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @Column(name = "notes", columnDefinition = "TEXT") + private String notes; + + @OneToMany(mappedBy = "formVersion", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @ToString.Exclude + private List sections = new ArrayList<>(); + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; + + @PrePersist + protected void onCreate() { + createdAt = new Timestamp(System.currentTimeMillis()); + } +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java b/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java index bcaeabc4..205716cc 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java +++ b/src/main/java/com/iemr/flw/domain/iemr/HbycChildVisit.java @@ -53,7 +53,7 @@ public class HbycChildVisit { private String other_place_of_death; @Column(name = "baby_weight") - private BigDecimal baby_weight; // 0.5 - 7.0 + private Integer baby_weight; // 0.5 - 7.0 @Column(name = "is_child_sick") private Boolean is_child_sick; diff --git a/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java b/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java index 0f078f5f..6f3143e0 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IRSRound.java @@ -28,4 +28,10 @@ public class IRSRound { @Column(name = "householdId") private Long householdId; + @Column(name = "created_by") + private String createdBy; + + @Column(name = "user_id") + private Integer userId; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java index b5c039f5..016f6271 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivity.java @@ -36,7 +36,6 @@ public class IncentiveActivity { @Column(name = "group_name") private String group; - @Column(name = "fmr_code") private String fmrCode; @@ -59,4 +58,8 @@ public class IncentiveActivity { private Boolean isDeleted; + @Column(name = "state_activity_code") + private Integer stateActivityCode; + + } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java index 5b921bb4..b6d193e6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentiveActivityRecord.java @@ -3,6 +3,8 @@ import lombok.Data; import jakarta.persistence.*; + +import javax.management.MXBean; import java.sql.Timestamp; @Entity @@ -46,4 +48,43 @@ public class IncentiveActivityRecord { @Column(name = "updated_by") private String updatedBy; + + @Column(name = "is_eligible",columnDefinition = "tinyint(1) default 1") + private Boolean isEligible=true; + + @Column(name = "is_default_activity",columnDefinition = "tinyint(1) default 0") + private Boolean isDefaultActivity = false; + + @Column(name = "approval_status",columnDefinition = "int default 102") + Integer approvalStatus = 102; + + @Column(name = "verifiedBy_userId") + private Integer verifiedByUserId; + + @Column(name = "verifiedBy_userName") + private String verifiedByUserName; + + @Column(name = "reason") + private String reason; + + @Column(name = "other_reason") + private String otherReason; + + @Column(name = "is_claimed",columnDefinition = "tinyint(1) default 0") + private Boolean isClaimed = false; + + @Column(name = "approval_date") + private Timestamp approvalDate; + + @Column(name = "calimed_date") + private Timestamp calimedDate; + + @Transient + private String supervisorRole; + + @Transient + private String activityDec; + + @Transient + private String groupName; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java b/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java new file mode 100644 index 00000000..3f35dc59 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/IncentivePendingActivity.java @@ -0,0 +1,39 @@ +package com.iemr.flw.domain.iemr; + +import java.util.Date; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Table(name = "incentive_pending_activity", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class IncentivePendingActivity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "activity_id", nullable = false) + private Long activityId; + + @Column(name = "record_id", nullable = false) + private Long recordId; + + @Column(name = "m_incentive_id") + private Long mincentiveId; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "created_date") + private Date createdDate; + + @Column(name = "updated_date") + private Date updatedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java b/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java index 2bfb2970..0e843714 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MaaMeeting.java @@ -5,6 +5,7 @@ import java.sql.Timestamp; import java.time.LocalDate; +import java.util.List; @Entity @Data @@ -39,6 +40,18 @@ public class MaaMeeting { @Column(name = "meeting_images", columnDefinition = "LONGTEXT") private String meetingImagesJson; + @Column(name = "village_name") + private String villageName; + + @Column(name = "no_of_pragnent_women") + private Integer noOfPragnentWomen; + + @Column(name = "no_of_lacting_mother") + private Integer noOfLactingMother; + + @Column(name = "mitanin_activity_checkList") + private String mitaninActivityCheckList; + @Column(name = "created_by") private String createdBy; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/MalariaFollowUp.java b/src/main/java/com/iemr/flw/domain/iemr/MalariaFollowUp.java index cd7384e1..bc30e7dd 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MalariaFollowUp.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MalariaFollowUp.java @@ -2,7 +2,9 @@ import jakarta.persistence.*; import lombok.Data; +import org.hibernate.annotations.UpdateTimestamp; +import java.sql.Timestamp; import java.util.Date; @Entity @@ -47,4 +49,11 @@ public class MalariaFollowUp { @Column(name = "referral_date") @Temporal(TemporalType.DATE) private Date referralDate; + + @Column(name = "modified_by") + private String modifiedBy; + + @UpdateTimestamp + @Column(name = "last_mod_date") + private Timestamp lastModDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java b/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java index 9444d1af..1f57d23a 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java +++ b/src/main/java/com/iemr/flw/domain/iemr/MosquitoNetEntity.java @@ -9,21 +9,22 @@ @Data @Table(name = "i_mobilization_mosquito_net",schema = "db_iemr") public class MosquitoNetEntity { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(name = "beneficiary_id") private Long beneficiaryId; + @Column(name = "household_id") private Long houseHoldId; + @Column(name = "visit_date") private LocalDate visitDate; @Column(name = "user_name") private String userName; - @Column(name = "user_id") private Integer userId; diff --git a/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java new file mode 100644 index 00000000..50af2b38 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/OptionCondition.java @@ -0,0 +1,103 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.sql.Timestamp; + +/** + * Conditional action triggered when a specific option is selected. + * actionType: SHOW_QUESTION | DISABLE_SECTION_VALIDATION | LOCK_FORM + * Exactly one of targetQuestion / targetSection is non-null per row. + */ +@Entity +@Table(name = "t_option_condition", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OptionCondition { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "conditionId") + private Long conditionId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "optionId", nullable = false) + @ToString.Exclude + private QuestionOption questionOption; + + @Column(name = "actionType", nullable = false, length = 40) + private String actionType; + + /** Set when actionType = SHOW_QUESTION. */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "targetQuestionId", nullable = true) + @ToString.Exclude + private SectionQuestion targetQuestion; + + /** Set when actionType = DISABLE_SECTION_VALIDATION. */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "targetSectionId", nullable = true) + @ToString.Exclude + private FormSection targetSection; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java b/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java index 50ec3375..4dea0ce7 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/PHCReviewForm.java @@ -42,6 +42,19 @@ public class PHCReviewForm { @Column(name = "created_date", updatable = false) private Timestamp createdDate; + @Column(name = "village_name ") + private String villageName; + + @Column(name = "mitanin_history") + private String mitaninHistory; + + @Column(name = "mitanin_activity_checkList") + private String mitaninActivityCheckList; + + @Column(name = "place_Id") + private Integer placeId; + @Column(name = "form_type") private String formType; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/domain/iemr/PhyGeneralExamination.java b/src/main/java/com/iemr/flw/domain/iemr/PhyGeneralExamination.java new file mode 100644 index 00000000..b99fd804 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/PhyGeneralExamination.java @@ -0,0 +1,79 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import java.sql.Timestamp; + +@Entity +@Table(name = "t_Phy_GeneralExam", schema = "db_iemr") +@Data +public class PhyGeneralExamination { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "ID") + private Long id; + + @Column(name = "BeneficiaryRegID") + private Long beneficiaryRegID; + + @Column(name = "BenVisitID") + private Long benVisitID; + + @Column(name = "ProviderServiceMapID") + private Integer providerServiceMapID; + + @Column(name = "VisitCode") + private Long visitCode; + + @Column(name = "Pallor") + private String pallor; + + @Column(name = "Jaundice") + private String jaundice; + + @Column(name = "Cyanosis") + private String cyanosis; + + @Column(name = "Clubbing") + private String clubbing; + + @Column(name = "Lymphadenopathy") + private String lymphadenopathy; + + @Column(name = "Edema") + private String edema; + + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + + @Column(name = "Processed", insertable = false, updatable = true) + private String processed; + + @Column(name = "CreatedBy") + private String createdBy; + + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + + @Column(name = "ModifiedBy") + private String modifiedBy; + + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; + + @Column(name = "VanSerialNo") + private Long vanSerialNo; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "SyncedBy") + private String syncedBy; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/PrescribedDrugDetail.java b/src/main/java/com/iemr/flw/domain/iemr/PrescribedDrugDetail.java new file mode 100644 index 00000000..9a0a1502 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/PrescribedDrugDetail.java @@ -0,0 +1,82 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import java.sql.Timestamp; + +@Entity +@Table(name = "t_prescribeddrug", schema = "db_iemr") +@Data +public class PrescribedDrugDetail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "PrescribedDrugID", insertable = false, updatable = false) + private Long id; + + @Column(name = "BeneficiaryRegID") + private Long beneficiaryRegID; + + @Column(name = "BenVisitID") + private Long benVisitID; + + @Column(name = "ProviderServiceMapID") + private Integer providerServiceMapID; + + @Column(name = "VisitCode") + private Long visitCode; + + @Column(name = "PrescriptionID") + private Long prescriptionID; + + @Column(name = "GenericDrugName") + private String drugName; + + @Column(name = "Dose") + private String dose; + + @Column(name = "Frequency") + private String frequency; + + @Column(name = "Duration") + private String duration; + + @Column(name = "DuartionUnit") + private String durationUnit; + + @Column(name = "SpecialInstruction") + private String specialInstruction; + + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + + @Column(name = "Processed", insertable = false, updatable = true) + private String processed; + + @Column(name = "CreatedBy") + private String createdBy; + + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + + @Column(name = "ModifiedBy") + private String modifiedBy; + + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; + + @Column(name = "VanSerialNo") + private Long vanSerialNo; + + @Column(name = "VanID") + private Integer vanID; + + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "SyncedBy") + private String syncedBy; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/PrescriptionDetail.java b/src/main/java/com/iemr/flw/domain/iemr/PrescriptionDetail.java new file mode 100644 index 00000000..5bc5295d --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/PrescriptionDetail.java @@ -0,0 +1,70 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import java.sql.Timestamp; + +@Entity +@Table(name = "t_prescription", schema = "db_iemr") +@Data +public class PrescriptionDetail { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "PrescriptionID", insertable = false, updatable = false) + private Long prescriptionID; + + @Column(name = "BeneficiaryRegID") + private Long beneficiaryRegID; + + @Column(name = "BenVisitID") + private Long benVisitID; + + @Column(name = "ProviderServiceMapID") + private Integer providerServiceMapID; + + @Column(name = "VisitCode") + private Long visitCode; + + @Column(name = "DiagnosisProvided") + private String diagnosisProvided; + + @Column(name = "Instruction") + private String instruction; + + @Column(name = "Remarks") + private String remarks; + + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + + @Column(name = "Processed", insertable = false, updatable = true) + private String processed; + + @Column(name = "CreatedBy") + private String createdBy; + + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + + @Column(name = "ModifiedBy") + private String modifiedBy; + + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; + + @Column(name = "VanSerialNo") + private Long vanSerialNo; + + @Column(name = "VanID") + private Integer vanID; + + @Column(name = "ParkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "SyncedBy") + private String syncedBy; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java b/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java new file mode 100644 index 00000000..ddf7b8b6 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/PulsePolioCampaign.java @@ -0,0 +1,60 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Entity +@Table(name = "campaign_pulse_polio",schema = "db_iemr") +@Data +public class PulsePolioCampaign { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "start_date", nullable = false) + private LocalDate startDate; + + @Column(name = "end_date", nullable = false) + private LocalDate endDate; + + @Column(name = "user_id", nullable = false) + private Integer userId; + + @Column(name = "number_of_children", nullable = false) + private Integer numberOfChildren = 0; + + + @Column(name = "campaign_photos",columnDefinition = "LONGTEXT") + private String campaignPhotos; + + @Column(name = "created_by", length = 200) + private String createdBy; + + @Column(name = "updated_by", length = 200) + private String updatedBy; + + @Column(name = "created_date", updatable = false) + private LocalDateTime createdDate; + + @Column(name = "updated_date") + private LocalDateTime updatedDate; + + /* ---------- Auto timestamps ---------- */ + + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.updatedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.updatedDate = LocalDateTime.now(); + } + + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java new file mode 100644 index 00000000..2bc02cbd --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionOption.java @@ -0,0 +1,109 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +/** + * A selectable option for a RADIO or MCQ question. + */ +@Entity +@Table(name = "t_question_option", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QuestionOption { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "optionId") + private Long optionId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "questionId", nullable = false) + @ToString.Exclude + private SectionQuestion sectionQuestion; + + @Column(name = "optionLabel", nullable = false, length = 255) + private String optionLabel; + + @Column(name = "optionLabel_hindi", length = 100) + private String optionLabelHindi; + + @Column(name = "optionValue", nullable = false, length = 100) + private String optionValue; + + @Column(name = "optionValue_hindi", length = 100) + private String optionValueHindi; + + @Column(name = "displayOrder", nullable = false) + private Integer displayOrder; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @OneToMany(mappedBy = "questionOption", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @ToString.Exclude + private List conditions = new ArrayList<>(); + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java new file mode 100644 index 00000000..aabfc877 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionResponse.java @@ -0,0 +1,103 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; + +/** + * Stores one answer to a single question within a section response. + * MCQ questions produce multiple rows (one per selected option) — no unique constraint on (sectionResponseId, questionId). + * RADIO: optionId set, answerText null. + * MCQ: optionId set per selection, answerText null. + * TEXT/DATE/AUTO_FILL: answerText set, optionId null. + * DISPLAY: no row stored (read-only question type). + * + * @author Piramal Swasthya + */ +@Entity +@Table(name = "t_question_response", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class QuestionResponse { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "questionResponseId") + private Long questionResponseId; + + @Column(name = "sectionResponseId", nullable = false) + private Long sectionResponseId; + + @Column(name = "questionId", nullable = false) + private Long questionId; + + /** Set for RADIO (one row) and MCQ (one row per selected option). */ + @Column(name = "optionId") + private Long optionId; + + /** Set for TEXT, DATE, AUTO_FILL answers. */ + @Lob + @Column(name = "answerText") + private String answerText; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + @Builder.Default + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java new file mode 100644 index 00000000..b7d41dc1 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/QuestionValidation.java @@ -0,0 +1,101 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import com.iemr.flw.masterEnum.ValidationType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.sql.Timestamp; + +/** + * Server-side validation rule for a question. + * validationType: MAX_LENGTH | MIN_DATE | MAX_DATE | REGEX | MANDATORY_IF + */ +@Entity +@Table(name = "t_question_validation", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QuestionValidation { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "validationId") + private Long validationId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "questionId", nullable = false) + @ToString.Exclude + private SectionQuestion sectionQuestion; + + @Enumerated(EnumType.STRING) + @Column(name = "validationType", nullable = false, length = 30) + private ValidationType validationType; + + /** e.g. "500" for MAX_LENGTH, "TODAY" for MAX_DATE, a regex pattern for REGEX. */ + @Column(name = "validationParam", length = 255) + private String validationParam; + + @Column(name = "errorMessage", nullable = false, length = 500) + private String errorMessage; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java index eb8b0107..d6bcd7b6 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningKalaAzar.java @@ -45,7 +45,7 @@ public class ScreeningKalaAzar { @Column(name = "house_hold_details_Id",nullable = false) private Long houseHoldDetailsId; - @Column(name = "userID") + @Column(name = "user_id") private Integer userId; @Temporal(TemporalType.DATE) @@ -97,7 +97,7 @@ public class ScreeningKalaAzar { @Column(name = "created_by") private String createdBy; - @Column(name = "diseaseTypeID") + @Column(name = "disease_type_id") private Integer diseaseTypeId; @Column(name = "refer_to_name") diff --git a/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java b/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java index 225a1dfc..6a485eef 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java +++ b/src/main/java/com/iemr/flw/domain/iemr/ScreeningLeprosy.java @@ -26,7 +26,6 @@ import jakarta.persistence.*; import lombok.Data; - import java.sql.Timestamp; import java.util.Date; @@ -84,25 +83,25 @@ public class ScreeningLeprosy { @Column(name = "beneficiary_statusId") private Integer beneficiaryStatusId; - @Column(name = "beneficiary_status", length = 50) + @Column(name = "beneficiary_status") private String beneficiaryStatus; @Column(name = "date_of_death") private Date dateOfDeath; - @Column(name = "place_of_death", length = 50) + @Column(name = "place_of_death") private String placeOfDeath; @Column(name = "other_place_of_death", columnDefinition = "TEXT") private String otherPlaceOfDeath; - @Column(name = "reason_for_death", length = 50) + @Column(name = "reason_for_death") private String reasonForDeath; @Column(name = "other_reason_for_death", columnDefinition = "TEXT") private String otherReasonForDeath; - @Column(name = "leprosy_symptoms", length = 255) + @Column(name = "leprosy_symptoms") private String leprosySymptoms; @Column(name = "leprosy_symptoms_position") @@ -114,7 +113,7 @@ public class ScreeningLeprosy { @Column(name = "current_visit_number") private Integer currentVisitNumber; - @Column(name = "visit_label", length = 50) + @Column(name = "visit_label") private String visitLabel; @Column(name = "visit_number") @@ -123,7 +122,7 @@ public class ScreeningLeprosy { @Column(name = "is_confirmed") private Boolean isConfirmed; - @Column(name = "leprosy_state", length = 50) + @Column(name = "leprosy_state", length = 255) private String leprosyState; @Temporal(TemporalType.DATE) @@ -143,6 +142,78 @@ public class ScreeningLeprosy { @Column(name = "treatment_status", length = 100) private String treatmentStatus; + @Column(name = "recurrent_ulceration_id") + private Integer recurrentUlcerationId; + + @Column(name = "recurrent_tingling_id") + private Integer recurrentTinglingId; + + @Column(name = "hypopigmented_patch_id") + private Integer hypopigmentedPatchId; + + @Column(name = "thickened_skin_id") + private Integer thickenedSkinId; + + @Column(name = "skin_nodules_id") + private Integer skinNodulesId; + + @Column(name = "skin_patch_discoloration_id") + private Integer skinPatchDiscolorationId; + + @Column(name = "recurrent_numbness_id") + private Integer recurrentNumbnessId; + + @Column(name = "clawing_fingers_id") + private Integer clawingFingersId; + + @Column(name = "tingling_numbness_extremities_id") + private Integer tinglingNumbnessExtremitiesId; + + @Column(name = "inability_close_eyelid_id") + private Integer inabilityCloseEyelidId; + + @Column(name = "difficulty_holding_objects_id") + private Integer difficultyHoldingObjectsId; + + @Column(name = "weakness_feet_id") + private Integer weaknessFeetId; + + @Column(name = "recurrent_ulceration") + private String recurrentUlceration; + + @Column(name = "recurrent_tingling") + private String recurrentTingling; + + @Column(name = "hypopigmented_patch") + private String hypopigmentedPatch; + + @Column(name = "thickened_skin") + private String thickenedSkin; + + @Column(name = "skin_nodules") + private String skinNodules; + + @Column(name = "skin_patch_discoloration") + private String skinPatchDiscoloration; + + @Column(name = "recurrent_numbness") + private String recurrentNumbness; + + @Column(name = "clawing_fingers") + private String clawingFingers; + + @Column(name = "tingling_numbness_extremities") + private String tinglingNumbnessExtremities; + + @Column(name = "inability_close_eyelid") + private String inabilityCloseEyelid; + + @Column(name = "difficulty_holding_objects") + private String difficultyHoldingObjects; + + @Column(name = "weakness_feet") + private String weaknessFeet; + @Column(name = "CreatedBy", length = 100) private String createdBy; diff --git a/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java new file mode 100644 index 00000000..1bd7991b --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionQuestion.java @@ -0,0 +1,135 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import com.iemr.flw.masterEnum.QuestionType; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +/** + * A question within a form section. + * questionType: RADIO | MCQ | TEXT | DATE | DISPLAY | AUTO_FILL + */ +@Entity +@Table(name = "t_section_question", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SectionQuestion { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "questionId") + private Long questionId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "sectionId", nullable = false) + @ToString.Exclude + private FormSection formSection; + + @Column(name = "questionUuid", nullable = false, length = 100) + private String questionUuid; + + @Lob + @Column(name = "questionText", nullable = false) + private String questionText; + + @Column(name = "questionText_hindi", columnDefinition = "TEXT") + private String questionTextHindi; + + @Enumerated(EnumType.STRING) + @Column(name = "questionType", nullable = false, length = 20) + private QuestionType questionType; + + @Column(name = "isMandatory", nullable = false) + private Boolean isMandatory = true; + + @Column(name = "displayOrder", nullable = false) + private Integer displayOrder; + + /** Convenience shortcut — enforced by FormValidationEngine for TEXT questions. */ + @Column(name = "maxLength") + private Integer maxLength; + + /** e.g. "TODAY" for date fields with a default. */ + @Column(name = "defaultValue", length = 500) + private String defaultValue; + + /** If true, answerText is encrypted via CryptoUtil before persistence. */ + @Column(name = "containsPii", nullable = false) + private Boolean containsPii = false; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @OneToMany(mappedBy = "sectionQuestion", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @ToString.Exclude + private List options = new ArrayList<>(); + + @OneToMany(mappedBy = "sectionQuestion", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @ToString.Exclude + private List validations = new ArrayList<>(); + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java b/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java new file mode 100644 index 00000000..d8877a50 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/SectionResponse.java @@ -0,0 +1,96 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; + +/** + * Tracks completion state of one section within a form response. + * sectionId FK to t_form_section already implies the form version via its version_id FK. + * + * @author Piramal Swasthya + */ +@Entity +@Table(name = "t_section_response", schema = "db_iemr") +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SectionResponse { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "sectionResponseId") + private Long sectionResponseId; + + @Column(name = "responseId", nullable = false) + private Long responseId; + + @Column(name = "sectionId", nullable = false) + private Long sectionId; + + /** PENDING | IN_PROGRESS | DONE | SKIPPED */ + @Column(name = "status", nullable = false, length = 20) + private String status; + + @Column(name = "savedAt") + private Timestamp savedAt; + + @Column(name = "created_by", length = 100) + private String createdBy; + + @Column(name = "updated_by", length = 100) + private String updatedBy; + + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + @Builder.Default + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "SyncedDate") + private Timestamp syncedDate; + + @Column(name = "Syncedby", length = 50) + private String syncedBy; + + @Column(name = "SyncFailureReason") + private String syncFailureReason; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java b/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java new file mode 100644 index 00000000..f9abde57 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/StopTBDiagnostics.java @@ -0,0 +1,140 @@ +package com.iemr.flw.domain.iemr; + +import lombok.Data; +import jakarta.persistence.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.sql.Timestamp; + +@Entity +@Table(name = "tb_stoptb_diagnostics", schema = "db_iemr") +@Data +public class StopTBDiagnostics { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "ben_reg_id") + private Long benRegID; + + @Column(name = "provider_service_map_id") + private Integer providerServiceMapID; + + // PRD: user-provided date, not editable once submitted + @Column(name = "visit_date") + private Timestamp visitDate; + + @Column(name = "nikshay_id", length = 50) + private String nikshayId; + + // Digital Chest X-ray + @Column(name = "is_referred_for_digital_chest_xray") + private Boolean isReferredForDigitalChestXray; + + @Column(name = "reason_for_denial_chest_xray", length = 255) + private String reasonForDenialChestXray; + + @Column(name = "reason_for_denial_chest_xray_other", length = 255) + private String reasonForDenialChestXrayOther; + + @Column(name = "is_digital_chest_xray_conducted_id") + private Integer isDigitalChestXrayConductedId; + + @Column(name = "is_digital_chest_xray_conducted") + private Boolean isDigitalChestXrayConducted; + + @Column(name = "reason_not_conducted_chest_xray", length = 255) + private String reasonNotConductedChestXray; + + @Column(name = "reason_not_conducted_chest_xray_other", length = 255) + private String reasonNotConductedChestXrayOther; + + // Positive | Negative + @Column(name = "digital_chest_xray_result_id") + private Integer digitalChestXrayResultId; + + @Column(name = "digital_chest_xray_result", length = 20) + private String digitalChestXrayResult; + + // Sputum Collection + @Column(name = "is_referred_for_sputum_collection") + private Boolean isReferredForSputumCollection; + + @Column(name = "reason_for_denial_sputum", length = 500) + private String reasonForDenialSputum; + + @Column(name = "reason_for_denial_sputum_other", length = 255) + private String reasonForDenialSputumOther; + + @Column(name = "sputum_submitted_at", length = 255) + private String sputumSubmittedAt; + + // Truenat / NAAT + @Column(name = "is_truenat_conducted_id") + private Integer isTruenatConductedId; + + @Column(name = "is_truenat_conducted") + private Boolean isTruenatConducted; + + @Column(name = "reason_not_conducted_naat", length = 255) + private String reasonNotConductedNaat; + + @Column(name = "reason_not_conducted_naat_other", length = 255) + private String reasonNotConductedNaatOther; + + // Positive | Negative + @Column(name = "truenat_result_id") + private Integer truenatResultId; + + @Column(name = "truenat_result", length = 20) + private String truenatResult; + + // Liquid Culture — enabled if History of TB = Yes AND Anti-TB drugs = Yes + @Column(name = "recommended_for_liquid_culture_id") + private Integer recommendedForLiquidCultureId; + + @Column(name = "recommended_for_liquid_culture") + private Boolean recommendedForLiquidCulture; + + // Positive | Negative — editable after submission (results come after 40-45 days) + @Column(name = "liquid_culture_result_id") + private Integer liquidCultureResultId; + + @Column(name = "liquid_culture_result", length = 20) + private String liquidCultureResult; + + @Column(name = "created_by") + private String createdBy; + + @CreationTimestamp + @Column(name = "created_date", updatable = false) + private Timestamp createdDate; + + @Column(name = "modified_by") + private String modifiedBy; + + @UpdateTimestamp + @Column(name = "last_mod_date") + private Timestamp lastModDate; + + @Column(name = "deleted") + private Boolean deleted = false; + + // Sync fields + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "visitCode") + private Long visitCode; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralExamination.java b/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralExamination.java new file mode 100644 index 00000000..9972d916 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralExamination.java @@ -0,0 +1,133 @@ +package com.iemr.flw.domain.iemr; + +import lombok.Data; +import jakarta.persistence.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.sql.Timestamp; + +@Entity +@Table(name = "tb_stoptb_general_examination", schema = "db_iemr") +@Data +public class StopTBGeneralExamination { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "beneficiary_reg_id") + private Long beneficiaryRegID; + + @Column(name = "provider_service_map_id") + private Integer providerServiceMapID; + + // Vitals + @Column(name = "pulse_rate") + private Integer pulseRate; + + @Column(name = "systolic_bp") + private Integer systolicBP; + + @Column(name = "diastolic_bp") + private Integer diastolicBP; + + @Column(name = "random_blood_sugar") + private Double randomBloodSugar; + + // Clinical signs — ID + label ("PRESENT" / "ABSENT") + @Column(name = "pallor_id") + private Integer pallorId; + + @Column(name = "pallor") + private String pallor; + + @Column(name = "icterus_id") + private Integer icterusId; + + @Column(name = "icterus") + private String icterus; + + @Column(name = "lymphadenopathy_id") + private Integer lymphadenopathyId; + + @Column(name = "lymphadenopathy") + private String lymphadenopathy; + + @Column(name = "oedema_id") + private Integer oedemaId; + + @Column(name = "oedema") + private String oedema; + + @Column(name = "cyanosis_id") + private Integer cyanosisId; + + @Column(name = "cyanosis") + private String cyanosis; + + @Column(name = "clubbing_id") + private Integer clubbingId; + + @Column(name = "clubbing") + private String clubbing; + + // JSON arrays serialised from mobile + @Column(name = "key_population_risk_factor_ids", columnDefinition = "TEXT") + private String keyPopulationRiskFactorIds; + + @Column(name = "key_population_risk_factors", columnDefinition = "TEXT") + private String keyPopulationRiskFactors; + + @Column(name = "hiv_status_id") + private Integer hivStatusId; + + // "Positive" | "Reactive" | "Negative" | "Unknown" + @Column(name = "hiv_status") + private String hivStatus; + + @Column(name = "referral_to_hwc_needed_id") + private Integer referralToHWCNeededId; + + @Column(name = "referral_to_hwc_needed") + private Boolean referralToHWCNeeded; + + @Column(name = "created_by") + private String createdBy; + + @CreationTimestamp + @Column(name = "created_date", updatable = false) + private Timestamp createdDate; + + @Column(name = "modified_by") + private String modifiedBy; + + @UpdateTimestamp + @Column(name = "last_mod_date") + private Timestamp lastModDate; + + @Column(name = "deleted") + private Boolean deleted = false; + + // Sync fields + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "visitCode") + private Long visitCode; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "benVisitID") + private Long benVisitID; + + @Column(name = "ben_id") + private Long benId; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralOpd.java b/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralOpd.java new file mode 100644 index 00000000..4cfbb912 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/StopTBGeneralOpd.java @@ -0,0 +1,81 @@ +package com.iemr.flw.domain.iemr; + +import lombok.Data; +import jakarta.persistence.*; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import java.sql.Timestamp; + +@Entity +@Table(name = "tb_stoptb_general_opd", schema = "db_iemr") +@Data +public class StopTBGeneralOpd { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "ben_reg_id") + private Long benRegID; + + @Column(name = "provider_service_map_id") + private Integer providerServiceMapID; + + @Column(name = "chief_complaint", columnDefinition = "TEXT") + private String chiefComplaint; + + // JSON array of selected drug names + @Column(name = "medication", columnDefinition = "TEXT") + private String medication; + + @Column(name = "dosage") + private String dosage; + + // Once daily | Twice daily | Thrice daily | SoS + @Column(name = "frequency") + private String frequency; + + // 1 day | 2 days | 3 days | 5 days | 7 days + @Column(name = "duration") + private String duration; + + @Column(name = "notes", columnDefinition = "TEXT") + private String notes; + + @Column(name = "created_by") + private String createdBy; + + @CreationTimestamp + @Column(name = "created_date", updatable = false) + private Timestamp createdDate; + + @Column(name = "modified_by") + private String modifiedBy; + + @UpdateTimestamp + @Column(name = "last_mod_date") + private Timestamp lastModDate; + + @Column(name = "deleted") + private Boolean deleted = false; + + // Sync fields + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "visitCode") + private Long visitCode; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "benVisitID") + private Long benVisitID; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java new file mode 100644 index 00000000..c2c51a6f --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCase.java @@ -0,0 +1,105 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; +import org.hibernate.annotations.UpdateTimestamp; + +import java.sql.Timestamp; +import java.time.LocalDate; + +@Entity +@Data +@Table(name = "tb_confirmed_cases",schema = "db_iemr") +public class TBConfirmedCase { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + @Column(name = "ben_id", nullable = false) + private Long benId; + + @Column(name = "user_id",nullable = false) + private Integer userId; + + + @Column(name = "regimen_type") + private String regimenType; + + @Column(name = "treatment_start_date") + private LocalDate treatmentStartDate; + + @Column(name = "expected_treatment_completion_date") + private LocalDate expectedTreatmentCompletionDate; + + @Column(name = "follow_up_date") + private LocalDate followUpDate; + + @Column(name = "monthly_follow_up_done") + private String monthlyFollowUpDone; + + @Column(name = "adherence_to_medicines") + private String adherenceToMedicines; + + @Column(name = "any_discomfort") + private Boolean anyDiscomfort; + + @Column(name = "treatment_completed") + private Boolean treatmentCompleted; + + @Column(name = "actual_treatment_completion_date") + private LocalDate actualTreatmentCompletionDate; + + @Column(name = "treatment_outcome") + private String treatmentOutcome; + + @Column(name = "date_of_death") + private LocalDate dateOfDeath; + + @Column(name = "place_of_death") + private String placeOfDeath; + + @Column(name = "reason_for_death") + private String reasonForDeath = "Tuberculosis"; + + @Column(name = "reason_for_not_completing") + private String reasonForNotCompleting; + + @Column(name = "created_at") + private LocalDate createdAt = LocalDate.now(); + + @Column(name = "updated_at") + private LocalDate updatedAt; + + @Column(name = "modified_by") + private String modifiedBy; + + @UpdateTimestamp + @Column(name = "last_mod_date") + private Timestamp lastModDate; + + // Sync fields + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "benRegID") + private Long benRegID; + + @Column(name = "providerServiceMapID") + private Integer providerServiceMapID; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "visitCode") + private Long visitCode; +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java new file mode 100644 index 00000000..7a521177 --- /dev/null +++ b/src/main/java/com/iemr/flw/domain/iemr/TBConfirmedCaseDTO.java @@ -0,0 +1,34 @@ +package com.iemr.flw.domain.iemr; + +import jakarta.persistence.*; +import lombok.Data; + +import java.sql.Timestamp; +import java.time.LocalDate; + +@Data +public class TBConfirmedCaseDTO { + + private Integer id; + private Long benId; + private Timestamp updateDate; + private String updatedBy; + private Integer userId; + private Integer suspectedTbId; + private String regimenType; + private LocalDate treatmentStartDate; + private LocalDate expectedTreatmentCompletionDate; + private LocalDate followUpDate; + private String monthlyFollowUpDone; + private String adherenceToMedicines; + private Boolean anyDiscomfort; + private Boolean treatmentCompleted; + private LocalDate actualTreatmentCompletionDate; + private String treatmentOutcome; + private LocalDate dateOfDeath; + private String placeOfDeath; + private String reasonForDeath ; + private String reasonForNotCompleting; + private Boolean counselled; + +} diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java index 9bf7ea8d..06e36309 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBScreening.java @@ -1,6 +1,7 @@ package com.iemr.flw.domain.iemr; import lombok.Data; +import org.hibernate.annotations.UpdateTimestamp; import jakarta.persistence.*; import java.sql.Timestamp; @@ -23,27 +24,174 @@ public class TBScreening { @Column(name = "visit_date") private Timestamp visitDate; + @Column(name = "cough_check_id") + private Integer coughMoreThan2WeeksId; + @Column(name = "cough_check") private Boolean coughMoreThan2Weeks; + @Column(name = "blood_check_id") + private Integer bloodInSputumId; + @Column(name = "blood_check") private Boolean bloodInSputum; + @Column(name = "fever_check_id") + private Integer feverMoreThan2WeeksId; + @Column(name = "fever_check") private Boolean feverMoreThan2Weeks; + @Column(name = "weight_check_id") + private Integer lossOfWeightId; + @Column(name = "weight_check") private Boolean lossOfWeight; + @Column(name = "sweats_check_id") + private Integer nightSweatsId; + @Column(name = "sweats_check") private Boolean nightSweats; + @Column(name = "history_check_id") + private Integer historyOfTbId; + @Column(name = "history_check") private Boolean historyOfTb; + @Column(name = "drugs_check_id") + private Integer takingAntiTBDrugsId; + @Column(name = "drugs_check") private Boolean takingAntiTBDrugs; + @Column(name = "family_check_id") + private Integer familySufferingFromTBId; + @Column(name = "family_check") private Boolean familySufferingFromTB; + + @Column(name = "rise_of_fever_id") + private Integer riseOfFeverId; + + @Column(name = "rise_of_fever") + private Boolean riseOfFever; + + @Column(name = "loss_of_appetite_id") + private Integer lossOfAppetiteId; + + @Column(name = "loss_of_appetite") + private Boolean lossOfAppetite; + + // Risk Factors section — JSON arrays serialised from mobile + @Column(name = "key_population_risk_factor_ids", columnDefinition = "TEXT") + private String keyPopulationRiskFactorIds; + + @Column(name = "key_population_risk_factors", columnDefinition = "TEXT") + private String keyPopulationRiskFactors; + + @Column(name = "hiv_status_id") + private Integer hivStatusId; + + // "Positive" | "Reactive" | "Negative" | "Unknown" + @Column(name = "hiv_status") + private String hivStatus; + + @Column(name = "age") + private Boolean age; + + @Column(name = "diabetic") + private Boolean diabetic; + + @Column(name = "tobacco_user") + private Boolean tobaccoUser; + + @Column(name = "bmi") + private Boolean bmi; + + @Column(name = "contact_with_tb_patient") + private Boolean contactWithTBPatient; + + @Column(name = "history_of_tb_in_last_five_yrs") + private Boolean historyOfTBInLastFiveYrs; + + @Column(name = "sympotomatic") + private String sympotomatic; + + @Column(name = "asymptomatic") + private String asymptomatic; + + @Column(name = "recommandate_test") + private String recommandateTest; + + // Added for Stop TB nurse flow — nullable, not used by ASHA flow + @Column(name = "ben_reg_id") + private Long benRegID; + + @Column(name = "provider_service_map_id") + private Integer providerServiceMapID; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "modified_by") + private String modifiedBy; + + @UpdateTimestamp + @Column(name = "last_mod_date") + private Timestamp lastModDate; + + @Column(name = "deleted", insertable = false) + private Boolean deleted; + + // Diagnostics / referrals — Stop TB nurse flow only + @Column(name = "referred_for_digital_chest_xray_id") + private Integer referredForDigitalChestXrayId; + + @Column(name = "referred_for_digital_chest_xray") + private Boolean referredForDigitalChestXray; + + @Column(name = "referred_for_sputum_collection_id") + private Integer referredForSputumCollectionId; + + @Column(name = "referred_for_sputum_collection") + private Boolean referredForSputumCollection; + + @Column(name = "sputum_sample_submitted_at", length = 50) + private String sputumSampleSubmittedAt; + + @Column(name = "recommended_for_truenat_id") + private Integer recommendedForTruenatId; + + @Column(name = "recommended_for_truenat") + private Boolean recommendedForTruenat; + + @Column(name = "recommended_for_liquid_culture_id") + private Integer recommendedForLiquidCultureId; + + @Column(name = "recommended_for_liquid_culture") + private Boolean recommendedForLiquidCulture; + + @Column(name = "test_denial_reasons", columnDefinition = "TEXT") + private String testDenialReasons; + + // Sync fields — stamped by local laptop on save, used by MMU DataSync for local→central push + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "visitCode") + private Long visitCode; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "createdDate") + private java.sql.Timestamp createdDate; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java b/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java index 7cb945a8..0c8d2fc4 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java +++ b/src/main/java/com/iemr/flw/domain/iemr/TBSuspected.java @@ -1,6 +1,7 @@ package com.iemr.flw.domain.iemr; import lombok.Data; +import org.hibernate.annotations.UpdateTimestamp; import jakarta.persistence.*; import java.sql.Timestamp; @@ -40,4 +41,70 @@ public class TBSuspected { @Column(name = "followups") private String followUps; + + // Visit Information + @Column(name = "visit_label") + private String visitLabel; + + @Column(name = "type_of_tb_case") + private String typeOfTBCase; + + @Column(name = "reason_for_suspicion", length = 500) + private String reasonForSuspicion; + + + // Chest X-Ray + @Column(name = "is_chest_xray_done") + private Boolean isChestXRayDone; + + @Column(name = "chest_xray_result", length = 100) + private String chestXRayResult; + + // Referral & Confirmation + @Column(name = "referral_facility", length = 200) + private String referralFacility; + + @Column(name = "is_tb_confirmed") + private Boolean isTBConfirmed; + + @Column(name = "is_drtb_confirmed") + private Boolean isDRTBConfirmed; + + @Column(name = "provider_service_map_id") + private Integer providerServiceMapId; + + @Column(name = "is_confirmed") + private Boolean isConfirmed; + + @Column(name = "modified_by") + private String modifiedBy; + + @UpdateTimestamp + @Column(name = "last_mod_date") + private Timestamp lastModDate; + + // Sync fields + @Column(name = "vanID") + private Integer vanID; + + @Column(name = "parkingPlaceID") + private Integer parkingPlaceID; + + @Column(name = "processed") + private String processed = "N"; + + @Column(name = "vanSerialNo") + private Long vanSerialNo; + + @Column(name = "benRegID") + private Long benRegID; + + @Column(name = "created_by") + private String createdBy; + + @Column(name = "created_date") + private Timestamp createdDate; + + @Column(name = "visitCode") + private Long visitCode; } diff --git a/src/main/java/com/iemr/flw/domain/iemr/M_User.java b/src/main/java/com/iemr/flw/domain/iemr/User.java similarity index 91% rename from src/main/java/com/iemr/flw/domain/iemr/M_User.java rename to src/main/java/com/iemr/flw/domain/iemr/User.java index 0187a613..d422f926 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/M_User.java +++ b/src/main/java/com/iemr/flw/domain/iemr/User.java @@ -1,7 +1,6 @@ package com.iemr.flw.domain.iemr; import java.sql.Timestamp; -import java.time.LocalDate; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.gson.annotations.Expose; @@ -14,18 +13,10 @@ import jakarta.persistence.Table; import lombok.Data; -import com.google.gson.annotations.Expose; -import jakarta.persistence.*; -import lombok.Data; -import java.sql.Date; -import java.sql.Timestamp; -import java.time.LocalDate; - @Entity -@Table(name = "m_User", schema = "db_iemr") +@Table(name = "m_user", schema = "db_iemr") @Data -public class M_User { - +public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose @@ -144,11 +135,11 @@ public class M_User { @Column(name = "failed_attempt", insertable = false) private Integer failedAttempt; - public M_User() { + public User() { // TODO Auto-generated constructor stub } - public M_User(Integer userID, String userName) { + public User(Integer userID, String userName) { // TODO Auto-generated constructor stub this.userID = userID; this.userName = userName; diff --git a/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java b/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java index f995a71d..9ab6d5cb 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java +++ b/src/main/java/com/iemr/flw/domain/iemr/UwinSession.java @@ -23,6 +23,9 @@ public class UwinSession { @Column(name = "date", nullable = false) private Timestamp date; + @Column(name = "session_date", nullable = false) + private Timestamp sessionDate; + @Column(name = "place", nullable = false) private String place; diff --git a/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java b/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java index 488b33c4..758cc449 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VHNDForm.java @@ -37,6 +37,39 @@ public class VHNDForm { @Column(name = "form_type") private String formType; + @Column(name = "vhnd_place_id") + private Integer vhndPlaceId; + + @Column(name = "pregnant_women_anc") + private String pregnantWomenAnc; + + @Column(name = "lactating_mothers_pnc") + private String lactatingMothersPnc; + + @Column(name = "children_immunization") + private String childrenImmunization; + + @Column(name = "select_all_education") + private Boolean selectAllEducation; + + @Column(name = "knowledge_balanced_diet") + private String knowledgeBalancedDiet; + + @Column(name = "care_during_pregnancy") + private String careDuringPregnancy; + + @Column(name = "importance_breastfeeding") + private String importanceBreastfeeding; + + @Column(name = "complementary_feeding") + private String complementaryFeeding; + + @Column(name = "hygiene_sanitation") + private String hygieneSanitation; + + @Column(name = "family_planning_healthcare") + private String familyPlanningHealthcare; + @Column(name = "created_by") private String createdBy; diff --git a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java index 5b53b27e..858554da 100644 --- a/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java +++ b/src/main/java/com/iemr/flw/domain/iemr/VhncForm.java @@ -1,6 +1,7 @@ package com.iemr.flw.domain.iemr; import jakarta.persistence.*; +import jakarta.xml.bind.annotation.XmlAccessorOrder; import lombok.Data; import org.hibernate.annotations.CreationTimestamp; @@ -43,4 +44,26 @@ public class VhncForm { @Column(name = "form_type") private String formType; + + @Column(name = "village_name") + private String villageName; + + @Column(name = "anm") + private Integer anm; + + @Column(name = "aww") + private Integer aww; + + @Column(name = "no_of_pragnent_women") + private Integer noOfPragnentWoment; + + @Column(name = "no_of_lacting_mother") + private Integer noOfLactingMother; + + @Column(name = "no_of_committee") + private Integer noOfCommittee; + + @Column(name = "followup_previous") + private Boolean followupPrevius; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/abhaBeneficiary/AbhaBeneficiaryDTO.java b/src/main/java/com/iemr/flw/dto/abhaBeneficiary/AbhaBeneficiaryDTO.java new file mode 100644 index 00000000..dab9dec3 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/abhaBeneficiary/AbhaBeneficiaryDTO.java @@ -0,0 +1,65 @@ +package com.iemr.flw.dto.abhaBeneficiary; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class AbhaBeneficiaryDTO { + @JsonProperty("personName") + private String personName; + + private String firstName; + + private String lastName; + + @JsonProperty("age") + private String age; + + @JsonProperty("address") + private String address; + + @JsonProperty("district") + private String district; + + @JsonProperty("mobileNo") + private String mobileNo; + + @JsonProperty("block") + private String block; + + @JsonProperty("cardNo") + private String cardNo; + + @JsonProperty("villagename") + private String villagename; + + @JsonProperty("gender") + private String gender; + + @JsonProperty("district_Code") + private String districtCode; + + @JsonProperty("block_Code") + private String blockCode; + + @JsonProperty("village_Code") + private String villageCode; + + @JsonProperty("rural_Urban") + private String ruralUrban; + + @JsonProperty("abhaId") + private String abhaId; + + @JsonProperty("vvs") + private String vvs; + + @JsonProperty("familyid") + private String familyid; + + @JsonProperty("dob") + @JsonAlias("dob_secc") + private String dob; + +} diff --git a/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java b/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java index 00e452c5..94bfed1c 100644 --- a/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java +++ b/src/main/java/com/iemr/flw/dto/identity/GetBenRequestHandler.java @@ -12,6 +12,46 @@ public class GetBenRequestHandler { private Integer ashaId; + private Integer providerServiceMapID; + + public Integer getProviderServiceMapID() { + return providerServiceMapID; + } + + public void setProviderServiceMapID(Integer providerServiceMapID) { + this.providerServiceMapID = providerServiceMapID; + } + + private Long activityId; + + private Integer month; + + private Integer year; + + public Integer getMonth() { + return month; + } + + public void setMonth(Integer month) { + this.month = month; + } + + public Integer getYear() { + return year; + } + + public void setYear(Integer year) { + this.year = year; + } + + public Long getActivityId() { + return activityId; + } + + public void setActivityId(Long activityId) { + this.activityId = activityId; + } + public Integer getAshaId() { return ashaId; } @@ -52,6 +92,10 @@ public void setVillageID(Integer villageID) { this.villageID = villageID; } + public void setVillageId(Integer villageId) { + this.villageID = villageId; + } + public Timestamp getFromDate() { return fromDate; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java index f028655f..b4cf0033 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/ANCVisitDTO.java @@ -63,6 +63,8 @@ public class ANCVisitDTO { private Timestamp visitDate; private Timestamp dateSterilisation; private Boolean isYesOrNo; + private String placeOfAnc; + private Integer placeOfAncId; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/AbhaRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AbhaRequestDTO.java new file mode 100644 index 00000000..9ec31c6f --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AbhaRequestDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class AbhaRequestDTO { + private String cardNo; + private Long houseHoldId; + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java new file mode 100644 index 00000000..76aff81d --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareDTO.java @@ -0,0 +1,15 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class AncCounsellingCareDTO { + private String formId; + private Long beneficiaryId; + private String visitDate; + private AncCounsellingCareListDTO fields; + +} + + + diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java new file mode 100644 index 00000000..981e34e2 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareListDTO.java @@ -0,0 +1,79 @@ +package com.iemr.flw.dto.iemr; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; + +@Data +public class AncCounsellingCareListDTO { + + @SerializedName("home_visit_date") + private String homeVisitDate; + + @SerializedName("select_all") + private String selectAll; + + @SerializedName("swelling") + private String swelling; + + @SerializedName("high_bp") + private String highBp; + + @SerializedName("convulsions") + private String convulsions; + + @SerializedName("anemia") + private String anemia; + + @SerializedName("reduced_fetal_movement") + private String reducedFetalMovement; + + @SerializedName("age_risk") + private String ageRisk; + + @SerializedName("child_gap") + private String childGap; + + @SerializedName("short_height") + private String shortHeight; + + @SerializedName("pre_preg_weight") + private String prePregWeight; + + @SerializedName("bleeding") + private String bleeding; + + @SerializedName("miscarriage_history") + private String miscarriageHistory; + + @SerializedName("four_plus_delivery") + private String fourPlusDelivery; + + @SerializedName("first_delivery") + private String firstDelivery; + + @SerializedName("twin_pregnancy") + private String twinPregnancy; + + @SerializedName("c_section_history") + private String cSectionHistory; + + @SerializedName("pre_existing_disease") + private String preExistingDisease; + + @SerializedName("fever_malaria") + private String feverMalaria; + + @SerializedName("jaundice") + private String jaundice; + + @SerializedName("sickle_cell") + private String sickleCell; + + @SerializedName("prolonged_labor") + private String prolongedLabor; + + @SerializedName("malpresentation") + private String malpresentation; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java new file mode 100644 index 00000000..2e019558 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AncCounsellingCareResponseDTO.java @@ -0,0 +1,17 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +import java.util.Map; + +@Data +public class AncCounsellingCareResponseDTO { + private String formId; + private Long beneficiaryId; + private String visitDate; + private Map fields; // for dynamic form fields + +} + + + diff --git a/src/main/java/com/iemr/flw/dto/iemr/AshaByFacilityRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/AshaByFacilityRequestDTO.java new file mode 100644 index 00000000..9ae46ad4 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/AshaByFacilityRequestDTO.java @@ -0,0 +1,11 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class AshaByFacilityRequestDTO { + private Integer facilityId; + private Integer month; + private Integer year; + private Integer approvalStatus; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java b/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java index 122f652d..e39f0641 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/CdrDTO.java @@ -54,6 +54,8 @@ public class CdrDTO { private String deathCertImage1; private String deathCertImage2; + private String cdrImage; + private Timestamp updatedDate; diff --git a/src/main/java/com/iemr/flw/dto/iemr/ChronicDiseaseVisitDTO.java b/src/main/java/com/iemr/flw/dto/iemr/ChronicDiseaseVisitDTO.java new file mode 100644 index 00000000..2a2790ad --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/ChronicDiseaseVisitDTO.java @@ -0,0 +1,44 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Column; +import lombok.Data; + +import java.time.LocalDate; + +@Data +public class ChronicDiseaseVisitDTO { + + @JsonProperty("id") + private Long id; + + @JsonProperty("benId") + private Long benId; + + @JsonProperty("hhId") + private Long hhId; + + @JsonProperty("formId") + private String formId; + + @JsonProperty("version") + private Integer version; + + @JsonProperty("visitNo") + private Integer visitNo; + + @JsonProperty("followUpNo") + private Integer followUpNo; + + @Column(name = "followUpDate") + private LocalDate followUpDate; + + @JsonProperty("diagnosisCodes") + private String diagnosisCodes; + + @JsonProperty("treatmentStartDate") + private String treatmentStartDate; // yyyy-MM-dd + + @JsonProperty("formDataJson") + private String formDataJson; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java index 941721ca..5e94697a 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DeliveryOutcomeDTO.java @@ -10,7 +10,6 @@ public class DeliveryOutcomeDTO { private Long id; private Long benId; - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") private Timestamp dateOfDelivery; private String timeOfDelivery; private String placeOfDelivery; diff --git a/src/main/java/com/iemr/flw/dto/iemr/DiseaseLeprosyDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DiseaseLeprosyDTO.java index c0acbe71..47489c54 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/DiseaseLeprosyDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/DiseaseLeprosyDTO.java @@ -72,4 +72,28 @@ public class DiseaseLeprosyDTO { private Timestamp createdDate; private String modifiedBy; private Timestamp lastModDate; + private Integer recurrentUlcerationId; + private Integer recurrentTinglingId; + private Integer hypopigmentedPatchId; + private Integer thickenedSkinId; + private Integer skinNodulesId; + private Integer skinPatchDiscolorationId; + private Integer recurrentNumbnessId; + private Integer clawingFingersId; + private Integer tinglingNumbnessExtremitiesId; + private Integer inabilityCloseEyelidId; + private Integer difficultyHoldingObjectsId; + private Integer weaknessFeetId; + private String recurrentUlceration; + private String recurrentTingling; + private String hypopigmentedPatch; + private String thickenedSkin; + private String skinNodules; + private String skinPatchDiscoloration; + private String recurrentNumbness; + private String clawingFingers; + private String tinglingNumbnessExtremities; + private String inabilityCloseEyelid; + private String difficultyHoldingObjects; + private String weaknessFeet; } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java new file mode 100644 index 00000000..c9ecb63c --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/DynamicFormDTO.java @@ -0,0 +1,65 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import com.iemr.flw.masterEnum.FormType; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Transfer object for a full dynamic form definition. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DynamicFormDTO { + + private Long formId; + + @NotBlank(message = "formUuid is required") + private String formUuid; + + @NotBlank(message = "formName is required") + private String formName; + + @NotNull(message = "formType is required") + private FormType formType; + + private Boolean isActive = true; + + /** Days after the most-recently-completed section before the next follow-up notification fires. + * Null means no follow-up notifications. */ + private Integer followUpDelayDays; + + /** Current version number — populated by service on read, ignored on write. */ + private Integer versionNumber; + + @Valid + private List sections = new ArrayList<>(); +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupListDTO.java index 3480aa0b..12cba394 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupListDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupListDTO.java @@ -3,13 +3,16 @@ import com.google.gson.annotations.SerializedName; import lombok.Data; +import java.util.List; +import java.util.stream.Collectors; + @Data public class EyeCheckupListDTO { @SerializedName("visit_date") private String visit_date; @SerializedName("symptoms_observed") - private String symptoms_observed; + private Object symptoms_observed; @SerializedName("eye_affected") private String eye_affected; @@ -26,4 +29,16 @@ public class EyeCheckupListDTO { @SerializedName("discharge_summary_upload") private String discharge_summary_upload; + public String getSymptomsAsString() { + if (symptoms_observed == null) return null; + + if (symptoms_observed instanceof List) { + return ((List) symptoms_observed) + .stream() + .map(Object::toString) + .collect(Collectors.joining(", ")); + } + return symptoms_observed.toString(); + } + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupRequestDTO.java index f0c6d8bb..2bd9f2c8 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupRequestDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/EyeCheckupRequestDTO.java @@ -9,6 +9,7 @@ public class EyeCheckupRequestDTO { private Long houseHoldId; private String visitDate; private String userName; + private String eyeSide; private EyeCheckupListDTO fields; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java new file mode 100644 index 00000000..2e53ee29 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class FilariasisCampaignDTO { + private Long id; + private String visitDate; + private FilariasisCampaignListDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListDTO.java new file mode 100644 index 00000000..81438df9 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListDTO.java @@ -0,0 +1,30 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class FilariasisCampaignListDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate startDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate endDate; + + @JsonProperty("no_of_families") + private String numberOfFamilies; + + @JsonProperty("no_of_individuals") + private String numberOfIndividuals; + + @JsonProperty("mda_photos") + private List mdaPhotos; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListResponseDTO.java new file mode 100644 index 00000000..700d4665 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisCampaignListResponseDTO.java @@ -0,0 +1,31 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class FilariasisCampaignListResponseDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate startDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate endDate; + + @JsonProperty("no_of_families") + private Double numberOfFamilies; + + @JsonProperty("no_of_individuals") + private Double numberOfIndividuals; + + @JsonProperty("mda_photos") + private List mdaPhotos; + + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FilariasisResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FilariasisResponseDTO.java new file mode 100644 index 00000000..7b6dc5aa --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FilariasisResponseDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class FilariasisResponseDTO { + private Long id; + private Long houseHoldId; + private FilariasisCampaignListResponseDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java new file mode 100644 index 00000000..d53a5823 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FormResponseDTO.java @@ -0,0 +1,57 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; +import java.util.List; + +/** + * Outbound representation of a saved form response including all section and question answers. + * + * @author Piramal Swasthya + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class FormResponseDTO { + + private Long responseId; + private Long beneficiaryId; + private Long formId; + private Long versionId; + private Long officerId; + private String status; + private String createdBy; + private String updatedBy; + private Timestamp submittedAt; + private Timestamp completedAt; + private Timestamp lastFollowUpAt; + private Timestamp createdAt; + private Timestamp updatedAt; + private List sections; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FormResponseRequest.java b/src/main/java/com/iemr/flw/dto/iemr/FormResponseRequest.java new file mode 100644 index 00000000..a90cb84b --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FormResponseRequest.java @@ -0,0 +1,58 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Inbound request to save or submit a dynamic form response. + * + * @author Piramal Swasthya + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FormResponseRequest { + + /** Present on re-submit: update an existing SUBMITTED response's sections instead of creating new. */ + private Long responseId; + + @NotBlank(message = "formUuid is required") + private String formUuid; + + @NotNull(message = "beneficiaryId is required") + private Long beneficiaryId; + + @NotNull(message = "officerId is required") + private Long officerId; + + @Valid + private List sections = new ArrayList<>(); +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java new file mode 100644 index 00000000..2db1f8c7 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FormSectionDTO.java @@ -0,0 +1,64 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Transfer object for a form section definition. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FormSectionDTO { + + private Long sectionId; + + @NotBlank(message = "sectionUuid is required") + private String sectionUuid; + + @NotBlank(message = "sectionName is required") + private String sectionName; + + private String sectionNameHindi; + + @NotBlank(message = "sectionPhase is required (PRE_SUBMIT or POST_SUBMIT)") + private String sectionPhase; + + private Boolean isRequired = true; + + @NotNull(message = "displayOrder is required") + private Integer displayOrder; + + private Boolean hasSubmitButton = false; + + @Valid + private List questions = new ArrayList<>(); +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/FormVersionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/FormVersionDTO.java new file mode 100644 index 00000000..742b0f7b --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/FormVersionDTO.java @@ -0,0 +1,41 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Transfer object for form version metadata. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class FormVersionDTO { + + private Long versionId; + private Integer versionNumber; + private Boolean isLatest; + private String createdBy; + private String notes; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java b/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java index acc54ca8..172132e0 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/HbycDTO.java @@ -47,7 +47,7 @@ public class HbycDTO { private String other_place_of_death; @SerializedName("baby_weight") - private BigDecimal baby_weight; + private Integer baby_weight; @SerializedName("is_child_sick") private String is_child_sick; diff --git a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java index 58da9958..354e762d 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/IncentiveRecordDTO.java @@ -1,5 +1,7 @@ package com.iemr.flw.dto.iemr; +import jakarta.persistence.Column; +import jakarta.persistence.Transient; import lombok.Data; import java.sql.Timestamp; @@ -30,5 +32,35 @@ public class IncentiveRecordDTO { private Timestamp updatedDate; private String updatedBy; + + private Boolean isEligible; + + private Boolean isDefaultActivity; + + private Integer approvalStatus; + + private Integer verifiedByUserId; + + private String verifiedByUserName; + + private String activityDec; + + private String groupName; + + private String reason; + + private String otherReason; + + private Boolean isClaimed; + + private Timestamp approvalDate; + + private Timestamp calimedDate; + + private String supervisorRole; + + + + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingRequestDTO.java index c08c8d64..e4ca6af5 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingRequestDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingRequestDTO.java @@ -1,17 +1,24 @@ package com.iemr.flw.dto.iemr; import lombok.Data; +import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.multipart.MultipartFile; import java.sql.Timestamp; import java.time.LocalDate; +import java.util.List; @Data public class MaaMeetingRequestDTO { + private Long id; private LocalDate meetingDate; private String place; private Integer participants; private MultipartFile[] meetingImages; // up to 5 images private Integer ashaId; + private String villageName; + private Integer noOfPragnentWomen; + private Integer noOfLactingMother; + private String mitaninActivityCheckList; private String createdBY; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingResponseDTO.java index 9ba81ad8..b56356c2 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingResponseDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MaaMeetingResponseDTO.java @@ -35,6 +35,11 @@ public class MaaMeetingResponseDTO { example = "[\"iVBORw0KGgoAAAANSUhEUgAA...\", \"iVBORw0KGgoAAAANSUhEUgBB...\"]") private List meetingImages; + private String villageName; + private String noOfPragnentWomen; + private String noOfLactingMother; + private String mitaninActivityCheckList; + @Column(name = "created_by") private String createdBy; diff --git a/src/main/java/com/iemr/flw/dto/iemr/MalariaFollowListUpDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MalariaFollowListUpDTO.java index 1a8b8e6e..56dff196 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MalariaFollowListUpDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MalariaFollowListUpDTO.java @@ -25,11 +25,15 @@ package com.iemr.flw.dto.iemr; import lombok.Data; + +import java.sql.Timestamp; import java.util.Date; @Data public class MalariaFollowListUpDTO { private Long id; + private Timestamp updateDate; + private String updatedBy; private Long benId; private Long houseHoldDetailsId; private Integer userId ; diff --git a/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java b/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java index 5b07e40a..e59047ab 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/MdsrDTO.java @@ -35,4 +35,10 @@ public class MdsrDTO { private Timestamp updatedDate; private String updatedBy; + + private String mdsr1File; + + private String mdsr2File; + + private String mdsrDeathCertFile; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/OptionConditionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OptionConditionDTO.java new file mode 100644 index 00000000..d43167a7 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OptionConditionDTO.java @@ -0,0 +1,58 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Transfer object for a conditional action triggered when an option is selected. + * Exactly one of targetQuestionId / targetSectionId should be non-null. + * + * On create/update: use targetQuestionUuid or targetSectionUuid to reference target. + * On read: targetQuestionId + targetQuestionUuid (or targetSectionId + targetSectionUuid) are + * returned as flat references — the full target object appears in the form's questions/sections list. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OptionConditionDTO { + + private Long conditionId; + + @NotBlank(message = "actionType is required") + private String actionType; + + /** DB ID of the target question. */ + private Long targetQuestionId; + + /** DB ID of the target section. */ + private Long targetSectionId; + + /** UUID of the target question. */ + private String targetQuestionUuid; + + /** UUID of the target section. */ + private String targetSectionUuid; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignDTO.java new file mode 100644 index 00000000..dbd83c26 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class OrsCampaignDTO { + private Long id; + private String visitDate; + private OrsCampaignListDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListDTO.java new file mode 100644 index 00000000..552c4fc8 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListDTO.java @@ -0,0 +1,30 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.util.List; + +@Data +public class OrsCampaignListDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate StartDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate EndDate; + + @JsonProperty("number_of_families") + private String NumberOfFamilies; + + @JsonProperty("campaign_photos") + private List campaignPhotos; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListResponseDTO.java new file mode 100644 index 00000000..e72fb04c --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignListResponseDTO.java @@ -0,0 +1,25 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class OrsCampaignListResponseDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate StartDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate EndDate; + + @JsonProperty("number_of_families") + private Double NumberOfFamilies; + + @JsonProperty("campaign_photos") + private List campaignPhotos; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignResponseDTO.java new file mode 100644 index 00000000..5c8b954d --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsCampaignResponseDTO.java @@ -0,0 +1,9 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class OrsCampaignResponseDTO { + private Long id; + private OrsCampaignListResponseDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionListDTO.java index 25ab11b5..45ef5429 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionListDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/OrsDistributionListDTO.java @@ -10,7 +10,7 @@ public class OrsDistributionListDTO { private String visit_date; @SerializedName("num_under5_children") - private Double num_under5_children; + private Double num_under5_children=1.0; @SerializedName("num_ors_packets") private Double num_ors_packets; diff --git a/src/main/java/com/iemr/flw/dto/iemr/PaymentItem.java b/src/main/java/com/iemr/flw/dto/iemr/PaymentItem.java new file mode 100644 index 00000000..2bb0ecea --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PaymentItem.java @@ -0,0 +1,18 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class PaymentItem { + @JsonProperty("activity_code") + public String activityCode; + + @JsonProperty("count") + public String count; + + @JsonProperty("incentive_amount") + public String incentiveAmount; + + + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/PaymentRequest.java b/src/main/java/com/iemr/flw/dto/iemr/PaymentRequest.java new file mode 100644 index 00000000..88218b26 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PaymentRequest.java @@ -0,0 +1,43 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class PaymentRequest { + @JsonProperty("submission_id") + public String submissionId; + + @JsonProperty("partner_code") + public String partnerCode; + + @JsonProperty("period") + public Period period; + + @JsonProperty("asha_id") + public String ashaId; + + @JsonProperty("generated_at") + public String generatedAt; + + @JsonProperty("verified_by") + public VerifiedBy verifiedBy; + + @JsonProperty("items") + public List items; + + public PaymentRequest() {} + + public PaymentRequest(String submissionId, String partnerCode, Period period, + String ashaId, String generatedAt, + VerifiedBy verifiedBy, List items) { + this.submissionId = submissionId; + this.partnerCode = partnerCode; + this.period = period; + this.ashaId = ashaId; + this.generatedAt = generatedAt; + this.verifiedBy = verifiedBy; + this.items = items; + } + } + diff --git a/src/main/java/com/iemr/flw/dto/iemr/PendingActivityDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PendingActivityDTO.java new file mode 100644 index 00000000..5fcdd537 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PendingActivityDTO.java @@ -0,0 +1,15 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@Data +public class PendingActivityDTO { + private Long id; + private Integer userId; + private List images; + private String moduleName; + private String activityName; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/Period.java b/src/main/java/com/iemr/flw/dto/iemr/Period.java new file mode 100644 index 00000000..049e35be --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/Period.java @@ -0,0 +1,19 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class Period { + @JsonProperty("start") + public String start; + + @JsonProperty("end") + public String end; + + public Period() {} + + + + } + diff --git a/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java index 00830988..b08386c6 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/PhcReviewMeetingFormDTO.java @@ -1,5 +1,6 @@ package com.iemr.flw.dto.iemr; +import jakarta.persistence.Column; import lombok.Data; @Data @@ -8,8 +9,13 @@ public class PhcReviewMeetingFormDTO { private String phcReviewDate; private String place; private Integer noOfBeneficiariesAttended; + private String villageName; + private String mitaninHistory; + private String mitaninActivityCheckList; + private Integer placeId; private String image1; private String image2; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignDTO.java new file mode 100644 index 00000000..7f6cfc87 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignDTO.java @@ -0,0 +1,10 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class PolioCampaignDTO { + private Long id; + private String visitDate; + private PolioCampaignListDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListDTO.java new file mode 100644 index 00000000..a42ef3c6 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListDTO.java @@ -0,0 +1,28 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class PolioCampaignListDTO { + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("start_date") + private LocalDate startDate; + + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy") + @JsonProperty("end_date") + private LocalDate endDate; + + @JsonProperty("children_vaccinated") + private String numberOfChildren; + + @JsonProperty("campaign_photos") + private List campaignPhotos; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListResponseDTO.java new file mode 100644 index 00000000..f27468f3 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignListResponseDTO.java @@ -0,0 +1,25 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.time.LocalDate; +import java.util.List; + +@Data +public class PolioCampaignListResponseDTO { + @JsonProperty("start_date") + private LocalDate startDate; + + @JsonProperty("end_date") + private LocalDate endDate; + + @JsonProperty("children_vaccinated") + private Double numberOfChildren; + + @JsonProperty("campaign_photos") + private List campaignPhotos; + + +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignResponseDTO.java new file mode 100644 index 00000000..a6504236 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/PolioCampaignResponseDTO.java @@ -0,0 +1,9 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class PolioCampaignResponseDTO { + private Long id; + private PolioCampaignListResponseDTO fields; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/QuestionAnswerRequest.java b/src/main/java/com/iemr/flw/dto/iemr/QuestionAnswerRequest.java new file mode 100644 index 00000000..8ee08c45 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionAnswerRequest.java @@ -0,0 +1,63 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * A single question's answer within a section answer request. + * Exactly one of optionValue, optionValues, answerText, or answerDate should be set per question type: + * RADIO → optionValue (single string) + * MCQ → optionValues (list of strings, one row saved per element) + * TEXT/AUTO_FILL → answerText + * DATE → answerDate (ISO date string) or answerText + * DISPLAY → omit entirely (ignored by service) + * + * @author Piramal Swasthya + */ +@JsonIgnoreProperties(ignoreUnknown = false) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QuestionAnswerRequest { + + @NotBlank(message = "questionUuid is required") + private String questionUuid; + + /** RADIO — single selected option value. */ + private String optionValue; + + /** MCQ — list of selected option values. */ + private List optionValues; + + /** TEXT / AUTO_FILL — free-text answer. */ + private String answerText; + + /** DATE — ISO date string answer. */ + private String answerDate; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java new file mode 100644 index 00000000..0328263c --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionOptionDTO.java @@ -0,0 +1,59 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Transfer object for a selectable option on a RADIO or MCQ question. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QuestionOptionDTO { + + private Long optionId; + + @NotBlank(message = "optionLabel is required") + private String optionLabel; + + private String optionLabelHindi; + + @NotBlank(message = "optionValue is required") + private String optionValue; + + private String optionValueHindi; + + @NotNull(message = "displayOrder is required") + private Integer displayOrder; + + @Valid + private List conditions = new ArrayList<>(); +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java new file mode 100644 index 00000000..f5f76d63 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionResponseDTO.java @@ -0,0 +1,47 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Outbound representation of a single question's stored answer. + * For MCQ questions, multiple QuestionResponseDTO entries share the same questionId. + * + * @author Piramal Swasthya + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class QuestionResponseDTO { + + private Long questionResponseId; + private Long questionId; + /** Populated for RADIO and MCQ answers. */ + private Long optionId; + /** Populated for TEXT, DATE, AUTO_FILL answers. */ + private String answerText; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/QuestionValidationDTO.java b/src/main/java/com/iemr/flw/dto/iemr/QuestionValidationDTO.java new file mode 100644 index 00000000..72c144c5 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/QuestionValidationDTO.java @@ -0,0 +1,49 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import com.iemr.flw.masterEnum.ValidationType; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Transfer object for a server-side validation rule on a question. + * validationType: MAX_LENGTH | MIN_DATE | MAX_DATE | REGEX | MANDATORY_IF + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class QuestionValidationDTO { + + private Long validationId; + + @NotNull(message = "validationType is required") + private ValidationType validationType; + + private String validationParam; + + @NotBlank(message = "errorMessage is required") + private String errorMessage; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/SectionAnswerRequest.java b/src/main/java/com/iemr/flw/dto/iemr/SectionAnswerRequest.java new file mode 100644 index 00000000..b63d7a0c --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/SectionAnswerRequest.java @@ -0,0 +1,50 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Answers for one section within a form response request. + * + * @author Piramal Swasthya + */ +@JsonIgnoreProperties(ignoreUnknown = false) +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SectionAnswerRequest { + + @NotBlank(message = "sectionUuid is required") + private String sectionUuid; + + @Valid + private List answers = new ArrayList<>(); +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java b/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java new file mode 100644 index 00000000..11a81430 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/SectionQuestionDTO.java @@ -0,0 +1,76 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import com.iemr.flw.masterEnum.QuestionType; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +/** + * Transfer object for a question within a section. + * visibleByDefault is computed by the service — not stored in DB. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class SectionQuestionDTO { + + private Long questionId; + + @NotBlank(message = "questionUuid is required") + private String questionUuid; + + @NotBlank(message = "questionText is required") + private String questionText; + + private String questionTextHindi; + + @NotNull(message = "questionType is required") + private QuestionType questionType; + + private Boolean isMandatory = true; + + @NotNull(message = "displayOrder is required") + private Integer displayOrder; + + private Integer maxLength; + + private String defaultValue; + + private Boolean containsPii = false; + + /** Computed at read time: false if this question is a target of any OptionCondition. */ + private Boolean visibleByDefault = true; + + @Valid + private List options = new ArrayList<>(); + + @Valid + private List validations = new ArrayList<>(); +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/SectionResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/SectionResponseDTO.java new file mode 100644 index 00000000..dac289a7 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/SectionResponseDTO.java @@ -0,0 +1,48 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.dto.iemr; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.sql.Timestamp; +import java.util.List; + +/** + * Outbound representation of one section's response data. + * + * @author Piramal Swasthya + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SectionResponseDTO { + + private Long sectionResponseId; + private Long sectionId; + private String status; + private Timestamp savedAt; + private List answers; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedCasesResponseDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedCasesResponseDTO.java new file mode 100644 index 00000000..42504dcd --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedCasesResponseDTO.java @@ -0,0 +1,11 @@ +package com.iemr.flw.dto.iemr; + +import com.iemr.flw.domain.iemr.TBConfirmedCase; +import lombok.Data; + +import java.util.List; +@Data +public class TBConfirmedCasesResponseDTO { + Integer userId ; + List tbConfirmedCases; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java new file mode 100644 index 00000000..d3e76a4a --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/TBConfirmedRequestDTO.java @@ -0,0 +1,13 @@ +package com.iemr.flw.dto.iemr; + +import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; +import lombok.Data; +import java.util.List; + +@Data +public class TBConfirmedRequestDTO { + + private Long userId; + + private List tbConfirmedList; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java index 270526bd..36f48dfc 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBScreeningDTO.java @@ -29,91 +29,15 @@ public class TBScreeningDTO { private Boolean familySufferingFromTB; - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getBenId() { - return benId; - } - - public void setBenId(Long benId) { - this.benId = benId; - } - - public Timestamp getVisitDate() { - return visitDate; - } - - public void setVisitDate(Timestamp visitDate) { - this.visitDate = visitDate; - } - - public Boolean getCoughMoreThan2Weeks() { - return coughMoreThan2Weeks; - } - - public void setCoughMoreThan2Weeks(Boolean coughMoreThan2Weeks) { - this.coughMoreThan2Weeks = coughMoreThan2Weeks; - } - - public Boolean getBloodInSputum() { - return bloodInSputum; - } - - public void setBloodInSputum(Boolean bloodInSputum) { - this.bloodInSputum = bloodInSputum; - } - - public Boolean getFeverMoreThan2Weeks() { - return feverMoreThan2Weeks; - } - - public void setFeverMoreThan2Weeks(Boolean feverMoreThan2Weeks) { - this.feverMoreThan2Weeks = feverMoreThan2Weeks; - } - - public Boolean getLossOfWeight() { - return lossOfWeight; - } - - public void setLossOfWeight(Boolean lossOfWeight) { - this.lossOfWeight = lossOfWeight; - } - - public Boolean getNightSweats() { - return nightSweats; - } - - public void setNightSweats(Boolean nightSweats) { - this.nightSweats = nightSweats; - } - - public Boolean getHistoryOfTb() { - return historyOfTb; - } - - public void setHistoryOfTb(Boolean historyOfTb) { - this.historyOfTb = historyOfTb; - } - - public Boolean getTakingAntiTBDrugs() { - return takingAntiTBDrugs; - } - - public void setTakingAntiTBDrugs(Boolean takingAntiTBDrugs) { - this.takingAntiTBDrugs = takingAntiTBDrugs; - } - - public Boolean getFamilySufferingFromTB() { - return familySufferingFromTB; - } - - public void setFamilySufferingFromTB(Boolean familySufferingFromTB) { - this.familySufferingFromTB = familySufferingFromTB; - } + private Boolean riseOfFever; + private Boolean lossOfAppetite; + private Boolean age; + private Boolean diabetic; + private Boolean tobaccoUser; + private Boolean bmi; + private Boolean contactWithTBPatient; + private Boolean historyOfTBInLastFiveYrs; + private String sympotomatic; + private String asymptomatic; + private String recommandateTest; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java b/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java index 8d224a9c..72b731d0 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/TBSuspectedDTO.java @@ -8,20 +8,24 @@ public class TBSuspectedDTO { private Long id; + private Timestamp updateDate; + private String updatedBy; private Long benId; - + private String visitLabel; private Timestamp visitDate; - + private String typeOfTBCase; + private String reasonForSuspicion; private Boolean isSputumCollected; - private String sputumSubmittedAt; - private String nikshayId; - private String sputumTestResult; - + private Boolean isChestXRayDone; + private String chestXRayResult; + private String referralFacility; + private Boolean isTBConfirmed; + private Boolean isConfirmed; + private Boolean isDRTBConfirmed; private Boolean referred; - private String followUps; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/UpdateApprovalRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/UpdateApprovalRequestDTO.java new file mode 100644 index 00000000..ff786730 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/UpdateApprovalRequestDTO.java @@ -0,0 +1,14 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class UpdateApprovalRequestDTO { + private Integer ashaId; + private Integer month; + private Integer year; + private Integer approvalStatus; + private String incentiveIds; + private String reason; + private String otherReason; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java b/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java new file mode 100644 index 00000000..052b7d12 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/UpdateClaimedStatusRequestDTO.java @@ -0,0 +1,11 @@ +package com.iemr.flw.dto.iemr; + +import lombok.Data; + +@Data +public class UpdateClaimedStatusRequestDTO { + private Integer ashaId; + private Integer month; + private Integer year; + private boolean isClaimed; +} diff --git a/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java b/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java index 81d74903..c336e1c9 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/UserServiceRoleDTO.java @@ -4,6 +4,8 @@ import lombok.Getter; import lombok.Setter; +import java.util.Map; + @Data @Getter @Setter @@ -23,6 +25,15 @@ public class UserServiceRoleDTO { private String blockName; private String villageId; private String villageName; + private Map facilityData; + + // Stop TB / Nikshay location scope — populated only when serviceName = "Stop TB". + // Set via setters after construction (additive, not part of the base constructor + // so every other service line's DTO construction stays exactly as it is today). + private String tuId; + private String tuName; + private String healthFacilityId; + private String healthFacilityName; public UserServiceRoleDTO(Integer userId, String name, String userName, Integer stateId, String stateName, Integer workingDistrictId, String workingDistrictName, Short serviceProviderId, Integer roleId, String roleName, Integer providerServiceMapId, Integer blockId, String blockName, String villageId, String villageName) { this.userId = userId; diff --git a/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java index 0dec7976..bee7f247 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/VHNDFormDTO.java @@ -24,6 +24,7 @@ */ package com.iemr.flw.dto.iemr; +import jakarta.persistence.Column; import lombok.Data; @Data @@ -33,6 +34,17 @@ public class VHNDFormDTO { private Integer noOfBeneficiariesAttended; private String image1; private String image2; + private Integer vhndPlaceId; + private String pregnantWomenAnc; + private String lactatingMothersPnc; + private String childrenImmunization; + private Boolean selectAllEducation; + private String knowledgeBalancedDiet; + private String careDuringPregnancy; + private String importanceBreastfeeding; + private String complementaryFeeding; + private String hygieneSanitation; + private String familyPlanningHealthcare; } diff --git a/src/main/java/com/iemr/flw/dto/iemr/VerifiedBy.java b/src/main/java/com/iemr/flw/dto/iemr/VerifiedBy.java new file mode 100644 index 00000000..e64deb39 --- /dev/null +++ b/src/main/java/com/iemr/flw/dto/iemr/VerifiedBy.java @@ -0,0 +1,17 @@ +package com.iemr.flw.dto.iemr; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class VerifiedBy { + @JsonProperty("employee_id") + public String employeeId; + + @JsonProperty("name") + public String name; + + public VerifiedBy() {} + + + } diff --git a/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java b/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java index 8a12be96..a2515b42 100644 --- a/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java +++ b/src/main/java/com/iemr/flw/dto/iemr/VhncFormDTO.java @@ -34,4 +34,12 @@ public class VhncFormDTO { private Integer noOfBeneficiariesAttended; private String image1; private String image2; + private String villageName; + private Integer anm; + private Integer aww; + private Integer noOfPragnentWoment; + private Integer noOfLactingMother; + private Integer noOfCommittee; + private Boolean followupPrevius; + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/mapper/DynamicFormMapper.java b/src/main/java/com/iemr/flw/mapper/DynamicFormMapper.java new file mode 100644 index 00000000..551e93a6 --- /dev/null +++ b/src/main/java/com/iemr/flw/mapper/DynamicFormMapper.java @@ -0,0 +1,105 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.mapper; + +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.domain.iemr.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.OptionCondition; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.QuestionValidation; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.DynamicFormDTO; +import com.iemr.flw.dto.iemr.FormSectionDTO; +import com.iemr.flw.dto.iemr.FormVersionDTO; +import com.iemr.flw.dto.iemr.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** + * MapStruct mapper for dynamic form definition — entity ↔ DTO conversion. + */ +@Mapper(componentModel = "spring") +public interface DynamicFormMapper { + + // ── Entity → DTO ────────────────────────────────────────────────────────── + + @Mapping(target = "sections", ignore = true) + @Mapping(target = "versionNumber", ignore = true) + DynamicFormDTO toDto(DynamicForm entity); + + FormVersionDTO toDto(FormVersion entity); + + @Mapping(target = "questions", ignore = true) + FormSectionDTO toDto(FormSection entity); + + @Mapping(target = "visibleByDefault", ignore = true) + @Mapping(target = "options", ignore = true) + @Mapping(target = "validations", ignore = true) + SectionQuestionDTO toDto(SectionQuestion entity); + + @Mapping(target = "conditions", ignore = true) + QuestionOptionDTO toDto(QuestionOption entity); + + @Mapping(source = "targetQuestion.questionId", target = "targetQuestionId") + @Mapping(source = "targetQuestion.questionUuid", target = "targetQuestionUuid") + @Mapping(source = "targetSection.sectionId", target = "targetSectionId") + @Mapping(source = "targetSection.sectionUuid", target = "targetSectionUuid") + OptionConditionDTO toDto(OptionCondition entity); + + QuestionValidationDTO toDto(QuestionValidation entity); + + // ── DTO → Entity ────────────────────────────────────────────────────────── + + @Mapping(target = "versions", ignore = true) + @Mapping(target = "createdAt", ignore = true) + @Mapping(target = "updatedAt", ignore = true) + DynamicForm toEntity(DynamicFormDTO dto); + + @Mapping(target = "dynamicForm", ignore = true) + @Mapping(target = "sections", ignore = true) + @Mapping(target = "createdAt", ignore = true) + FormVersion toEntity(FormVersionDTO dto); + + @Mapping(target = "questions", ignore = true) + FormSection toEntity(FormSectionDTO dto); + + @Mapping(target = "formSection", ignore = true) + @Mapping(target = "options", ignore = true) + @Mapping(target = "validations", ignore = true) + SectionQuestion toEntity(SectionQuestionDTO dto); + + @Mapping(target = "sectionQuestion", ignore = true) + @Mapping(target = "conditions", ignore = true) + QuestionOption toEntity(QuestionOptionDTO dto); + + @Mapping(target = "questionOption", ignore = true) + @Mapping(target = "targetQuestion", ignore = true) + @Mapping(target = "targetSection", ignore = true) + OptionCondition toEntity(OptionConditionDTO dto); + + @Mapping(target = "sectionQuestion", ignore = true) + QuestionValidation toEntity(QuestionValidationDTO dto); +} diff --git a/src/main/java/com/iemr/flw/masterEnum/FormType.java b/src/main/java/com/iemr/flw/masterEnum/FormType.java new file mode 100644 index 00000000..779fce19 --- /dev/null +++ b/src/main/java/com/iemr/flw/masterEnum/FormType.java @@ -0,0 +1,34 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.masterEnum; + +/** + * Allowed types for a dynamic form definition. + * + * @author Piramal Swasthya + */ +public enum FormType { + COUNSELLING_MODULE, + SCREENING, + COUNSELLING, + TB_COUNSELLING +} diff --git a/src/main/java/com/iemr/flw/masterEnum/GroupName.java b/src/main/java/com/iemr/flw/masterEnum/GroupName.java index 8d6736eb..e53733b0 100644 --- a/src/main/java/com/iemr/flw/masterEnum/GroupName.java +++ b/src/main/java/com/iemr/flw/masterEnum/GroupName.java @@ -33,3 +33,6 @@ public String getDisplayName() { } + + + diff --git a/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java b/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java new file mode 100644 index 00000000..e40ecc98 --- /dev/null +++ b/src/main/java/com/iemr/flw/masterEnum/IncentiveApprovalStatus.java @@ -0,0 +1,35 @@ +package com.iemr.flw.masterEnum; + +public enum IncentiveApprovalStatus { + + VERIFIED(101, "Verified"), + PENDING(102, "Pending"), + REJECTED(103, "Rejected"), + OVERDUE(104, "Overdue"); + + private final int code; + private final String label; + + IncentiveApprovalStatus(int code, String label) { + this.code = code; + this.label = label; + } + + public int getCode() { + return code; + } + + public String getLabel() { + return label; + } + + // 🔥 Reverse lookup (code → enum) + public static IncentiveApprovalStatus fromCode(int code) { + for (IncentiveApprovalStatus status : values()) { + if (status.code == code) { + return status; + } + } + throw new IllegalArgumentException("Invalid approval status code: " + code); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/masterEnum/IncentiveName.java b/src/main/java/com/iemr/flw/masterEnum/IncentiveName.java new file mode 100644 index 00000000..052ab011 --- /dev/null +++ b/src/main/java/com/iemr/flw/masterEnum/IncentiveName.java @@ -0,0 +1,139 @@ +package com.iemr.flw.masterEnum; + +public enum IncentiveName { + + // ---------------- CHILD HEALTH ---------------- + HBNC_0_42_DAYS(GroupName.CHILD_HEALTH), + HBYC_QUARTERLY_VISITS(GroupName.CHILD_HEALTH), + SNCU_LBW_FOLLOWUP(GroupName.CHILD_HEALTH), + SAM_REFERRAL_NRC(GroupName.CHILD_HEALTH), + CHILD_DEATH_REPORTING(GroupName.CHILD_HEALTH), + E_HBNC_CACHAR(GroupName.CHILD_HEALTH), + MAA_QUARTERLY_MEETING(GroupName.CHILD_HEALTH), + NATIONAL_DEWORMING_DAY(GroupName.CHILD_HEALTH), + ORS_DISTRIBUTION(GroupName.CHILD_HEALTH), + NATIONAL_IRON_PLUS(GroupName.CHILD_HEALTH), + NIPI_CHILDREN(GroupName.CHILD_HEALTH), + + // ---------------- IMMUNIZATION ---------------- + FULL_IMMUNIZATION_0_1(GroupName.IMMUNIZATION), + COMPLETE_IMMUNIZATION_1_2(GroupName.IMMUNIZATION), + DPT_IMMUNIZATION_5_YEARS(GroupName.IMMUNIZATION), + CHILD_MOBILIZATION_SESSIONS(GroupName.IMMUNIZATION), + + // ---------------- MATERNAL HEALTH ---------------- + ANC_REGISTRATION_1ST_TRIM(GroupName.MATERNAL_HEALTH), + FULL_ANC(GroupName.MATERNAL_HEALTH), + COMPREHENSIVE_ABORTION_CARE(GroupName.MATERNAL_HEALTH), + INST_DELIVERY_HRP(GroupName.MATERNAL_HEALTH), + EPMSMA_INST_DELIVERY(GroupName.MATERNAL_HEALTH), + EPMSMA_HRP_IDENTIFIED(GroupName.MATERNAL_HEALTH), + MATERNAL_DEATH_REPORT(GroupName.MATERNAL_HEALTH), + MH_MISOPROSTOL(GroupName.MATERNAL_HEALTH), + MH_EARLY_REG_BANK(GroupName.MATERNAL_HEALTH), + MH_ANC_3RD_TRIM(GroupName.MATERNAL_HEALTH), + MH_MOTIVATE_INST_DEL(GroupName.MATERNAL_HEALTH), + MH_HR_POSTNATAL(GroupName.MATERNAL_HEALTH), + + // ---------------- JSY ---------------- + JSY_1ST_DEL_ANC_RURAL(GroupName.JSY), + JSY_1ST_DEL_INST_RURAL(GroupName.JSY), + JSY_2ND_DEL_ANC_RURAL(GroupName.JSY), + JSY_2ND_DEL_INST_RURAL(GroupName.JSY), + JSY_3RD_DEL_ANC_RURAL(GroupName.JSY), + JSY_3RD_DEL_INST_RURAL(GroupName.JSY), + JSY_4TH_DEL_ANC_RURAL(GroupName.JSY), + JSY_4TH_DEL_INST_RURAL(GroupName.JSY), + JSY_ANC_URBAN(GroupName.JSY), + JSY_INST_URBAN(GroupName.JSY), + + // ---------------- FAMILY PLANNING ---------------- + FP_ANC_MPA1(GroupName.FAMILY_PLANNING), + FP_ANC_MPA2(GroupName.FAMILY_PLANNING), + FP_ANC_MPA3(GroupName.FAMILY_PLANNING), + FP_ANC_MPA4(GroupName.FAMILY_PLANNING), + FP_ANC_MPA5(GroupName.FAMILY_PLANNING), + FIRST_SECOND_CHILD_GAP(GroupName.FAMILY_PLANNING), + FP_DELAY_2Y(GroupName.FAMILY_PLANNING), + FP_LIMIT_2CHILD(GroupName.FAMILY_PLANNING), + FP_PPIUCD(GroupName.FAMILY_PLANNING), + FP_PAIUCD(GroupName.FAMILY_PLANNING), + FP_CONDOM(GroupName.FAMILY_PLANNING), + FP_ORALPILLS(GroupName.FAMILY_PLANNING), + FP_EC(GroupName.FAMILY_PLANNING), + FP_FEMALE_STER(GroupName.FAMILY_PLANNING), + FP_PPS(GroupName.FAMILY_PLANNING), + FP_MINILAP(GroupName.FAMILY_PLANNING), + FP_MALE_STER(GroupName.FAMILY_PLANNING), + FP_EC_SURVEY(GroupName.FAMILY_PLANNING), + FP_SAAS_BAHU(GroupName.FAMILY_PLANNING), + FP_NP_KIT(GroupName.FAMILY_PLANNING), + + // ---------------- ADOLESCENT HEALTH ---------------- + AH_SANITARY(GroupName.ADOLESCENT_HEALTH), + AH_PEER_ED(GroupName.ADOLESCENT_HEALTH), + AH_MOBILIZE(GroupName.ADOLESCENT_HEALTH), + + // ---------------- ASHA ROUTINE ---------------- + ASHA_MONTHLY_ROUTINE(GroupName.ASHA_MONTHLY_ROUTINE), + + // ---------------- UMBRELLA PROGRAMMES ---------------- + NPCB_GOVT_CATARACT(GroupName.UMBRELLA_PROGRAMMES), + NPCB_PRIVATE_CATARACT(GroupName.UMBRELLA_PROGRAMMES), + DSTB_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + DRTB_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + INFORMANT_INCENTIVE(GroupName.UMBRELLA_PROGRAMMES), + TPT_PROVIDING(GroupName.UMBRELLA_PROGRAMMES), + BANK_ACCOUNT_NPY(GroupName.UMBRELLA_PROGRAMMES), + HOUSE_TO_HOUSE_SURVEY(GroupName.UMBRELLA_PROGRAMMES), + NLEP_TRAINING(GroupName.UMBRELLA_PROGRAMMES), + NLEP_CASE_DETECTION(GroupName.UMBRELLA_PROGRAMMES), + NLEP_PB_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + NLEP_MB_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + LEPROSY_PARTIAL_ASHA(GroupName.UMBRELLA_PROGRAMMES), + NVBDCP_SLIDE_COLLECTION(GroupName.UMBRELLA_PROGRAMMES), + NVBDCP_MALARIA_TREATMENT(GroupName.UMBRELLA_PROGRAMMES), + AES_JE_REFERRAL(GroupName.UMBRELLA_PROGRAMMES), + DENGUE_CHIKUNGUNYA(GroupName.UMBRELLA_PROGRAMMES), + NIDDCP_SALT_TEST(GroupName.UMBRELLA_PROGRAMMES), + + // ---------------- NCD ---------------- + NCD_POP_ENUMERATION(GroupName.NCD), + NCD_FOLLOWUP_TREATMENT(GroupName.NCD), + NCD_NEW_PATIENT_MEDICATION_SUPPORT(GroupName.NCD), + + // ---------------- ADDITIONAL INCENTIVE ---------------- + ADDITIONAL_ASHA_INCENTIVE(GroupName.ADDITIONAL_INCENTIVE), + + // ---------------- OTHER INCENTIVES ---------------- + ABHA_ID_CREATION(GroupName.OTHER_INCENTIVES), + MOBILE_BILL_REIMB(GroupName.OTHER_INCENTIVES), + + // ---------------- ACTIVITY ---------------- + ANC_FOUR_CHECKUPS_SUPPORT(GroupName.ACTIVITY), + INST_DELIVERY_ESCORT(GroupName.ACTIVITY), + FILARIASIS_MEDICINE_DISTRIBUTION(GroupName.ACTIVITY), + VHND_PARTICIPATION(GroupName.ACTIVITY), + CLUSTER_MEETING(GroupName.ACTIVITY), + VHSNC_MEETING(GroupName.ACTIVITY), + MITANIN_REGISTER(GroupName.ACTIVITY), + HWC_REFERRAL_10_CASES(GroupName.ACTIVITY), + LACTATING_MOTHERS_HOME_VISIT(GroupName.ACTIVITY), + MITANIN_REGISTER_5_INFO_FILL(GroupName.ACTIVITY), + HIGH_RISK_POSTPARTUM_HEALTH_CHECK(GroupName.ACTIVITY), + MOSQUITO_NET_DISTRIBUTION_MOBILIZATION(GroupName.ACTIVITY), + HIGH_RISK_POSTPARTUM_CARE(GroupName.ACTIVITY), + MONTHLY_HONORARIUM(GroupName.ACTIVITY), + FULL_ANC_45(GroupName.ACTIVITY), + MH_MOTIVATE_INST_DEL_46(GroupName.ACTIVITY); + + private final GroupName groupName; + + IncentiveName(GroupName groupName) { + this.groupName = groupName; + } + + public GroupName getGroupName() { + return groupName; + } +} diff --git a/src/main/java/com/iemr/flw/masterEnum/QuestionType.java b/src/main/java/com/iemr/flw/masterEnum/QuestionType.java new file mode 100644 index 00000000..ae4b91e1 --- /dev/null +++ b/src/main/java/com/iemr/flw/masterEnum/QuestionType.java @@ -0,0 +1,43 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.masterEnum; + +/** + * Exhaustive set of question input types for dynamic form questions. + * No other values may be stored in t_section_question.questionType. + * + * @author Piramal Swasthya + */ +public enum QuestionType { + /** Single-select from a predefined list of options. */ + RADIO, + /** Multi-select from a predefined list of options. */ + MCQ, + /** Free-text input. */ + TEXT, + /** Date picker input. */ + DATE, + /** Read-only display text — carries no answer data. */ + DISPLAY, + /** Value auto-filled from context (e.g. ASHA worker ID). */ + AUTO_FILL +} diff --git a/src/main/java/com/iemr/flw/masterEnum/ValidationType.java b/src/main/java/com/iemr/flw/masterEnum/ValidationType.java new file mode 100644 index 00000000..931e2469 --- /dev/null +++ b/src/main/java/com/iemr/flw/masterEnum/ValidationType.java @@ -0,0 +1,42 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.masterEnum; + +/** + * Exhaustive set of validation rule types for dynamic form questions. + * No other values may be stored in t_question_validation.validationType. + * + * @author Piramal Swasthya + */ +public enum ValidationType { + /** Maximum character length for text inputs. validationParam = integer string e.g. "100". */ + MAX_LENGTH, + /** Minimum allowed date. validationParam = ISO date string or "TODAY". */ + MIN_DATE, + /** Maximum allowed date. validationParam = ISO date string or "TODAY". */ + MAX_DATE, + /** Java-compatible regular expression the answer must match. validationParam = regex pattern. */ + REGEX, + /** Field becomes mandatory when another field equals a specific value. + * validationParam format: "QUESTION_UUID=OPTION_VALUE" e.g. "Q-GENDER=FEMALE". */ + MANDATORY_IF +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java index 96301fb3..c9d00c72 100644 --- a/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java +++ b/src/main/java/com/iemr/flw/repo/identity/BeneficiaryRepo.java @@ -12,7 +12,10 @@ import java.math.BigInteger; import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.Optional; +import java.util.stream.Stream; @Repository public interface BeneficiaryRepo extends JpaRepository { @@ -22,22 +25,30 @@ public interface BeneficiaryRepo extends JpaRepository findById(Long benID); + List findByHouseoldId(Long houseHoldId); + List findByBenficieryid(Long benID); + @Query(value = "SELECT beneficiaryRegID FROM db_identity.i_beneficiarydetails_rmnch WHERE BeneficiaryId = :benId", nativeQuery = true) Long getBenRegIdFromBenId(@Param("benId") Long benId); @Query(nativeQuery = true, value = " SELECT userid FROM db_iemr.m_user WHERE UserName = :userName ") Integer getUserIDByUserName(@Param("userName") String userName); - @Query(value = " SELECT t FROM RMNCHMBeneficiaryaddress t WHERE DATE(t.createdDate) BETWEEN DATE(:fromDate) " - + " AND DATE(:toDate) AND t.createdBy = :userName ") - Page getBenDataWithinDates(@Param("userName") String userName, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate, Pageable pageable); + + @Query("SELECT t FROM RMNCHMBeneficiaryaddress t " + + "WHERE t.createdDate BETWEEN :fromDate AND :toDate " + + "AND t.createdBy = :userName") + Page getBenDataWithinDates( + @Param("userName") String userName, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate, + Pageable pageable); @Query(value = " SELECT t FROM RMNCHMBeneficiaryaddress t WHERE t.createdBy = :userName ") Page getBenDataByUser(@Param("userName") String userName, Pageable pageable); @Query(value = " SELECT t FROM RMNCHMBeneficiarymapping t WHERE t.benAddressId = :addressID") - RMNCHMBeneficiarymapping getByAddressID(@Param("addressID") BigInteger addressID); + List getByAddressID(@Param("addressID") BigInteger addressID); @Query(value = " SELECT t FROM RMNCHMBeneficiarymapping t WHERE t.benRegId = :BenRegId") RMNCHMBeneficiarymapping getById(@Param("BenRegId") BigInteger BenRegId); @@ -61,7 +72,7 @@ Page getBenDataWithinDates(@Param("userName") String u BigInteger getBenIdFromRegID(@Param("benRegID") Long benRegID); @Query(value = " SELECT t FROM RMNCHBeneficiaryDetailsRmnch t WHERE t.BenRegId =:benRegID ") - RMNCHBeneficiaryDetailsRmnch getDetailsByRegID(@Param("benRegID") Long benRegID); + List getDetailsByRegID(@Param("benRegID") Long benRegID); @Query(value = " SELECT t FROM RMNCHBornBirthDetails t WHERE t.BenRegId =:benRegID ") RMNCHBornBirthDetails getBornBirthByRegID(@Param("benRegID") Long benRegID); @@ -72,17 +83,44 @@ Page getBenDataWithinDates(@Param("userName") String u @Query(nativeQuery = true, value = " SELECT HealthIdNumber,HealthID FROM db_iemr.m_benhealthidmapping WHERE BeneficiaryRegID = :benRegId ") Object[] getBenHealthIdNumber(@Param("benRegId") BigInteger benRegId); + + @Query(nativeQuery = true, value = " SELECT HealthIdNumber,HealthID FROM db_iemr.m_benhealthidmapping WHERE HealthIdNumber = :HealthIdNumber ") + Object[] getHealthIdNumber(@Param("HealthIdNumber") String HealthIdNumber); @Query(nativeQuery = true, value = " SELECT HealthID,HealthIdNumber,isNewAbha FROM db_iemr.t_healthid WHERE HealthIdNumber = :healthIdNumber ") ArrayList getBenHealthDetails(@Param("healthIdNumber") String healthIdNumber); - @Query("SELECT b FROM RMNCHMBeneficiarymapping b WHERE b.benRegId = :benRegId") - RMNCHMBeneficiarymapping findByBenRegIdFromMapping(@Param("benRegId") BigInteger benRegId); + // benRegId has no unique constraint on i_beneficiarymapping — a beneficiary can have + // more than one mapping row, so this must return a list, not assume a single result. + @Query("SELECT b FROM RMNCHMBeneficiarymapping b WHERE b.benRegId = :benRegId ORDER BY b.benMapId DESC") + List findByBenRegIdFromMapping(@Param("benRegId") BigInteger benRegId); + @Query("SELECT d FROM RMNCHMBeneficiarydetail d WHERE d.beneficiaryDetailsId = :beneficiaryDetailsId") RMNCHMBeneficiarydetail findByBeneficiaryDetailsId(@Param("beneficiaryDetailsId") BigInteger beneficiaryDetailsId); - - - + @Query("SELECT d FROM RMNCHMBeneficiarydetail d WHERE d.BenRegId = :benRegID") + RMNCHMBeneficiarydetail getDetailByBenRegID(@Param("benRegID") BigInteger benRegID); + + + // BeneficiaryRepo — replaces 3 separate queries per beneficiary + @Query(value = """ + SELECT + ibd.BeneficiaryId AS benId, + bd.firstName AS firstName, + bd.lastName AS lastName + FROM db_identity.i_beneficiarydetails_rmnch ibd + JOIN db_identity.i_beneficiarymapping bm + ON bm.BenRegId = ibd.BeneficiaryRegID + JOIN db_identity.i_beneficiarydetails bd + ON bd.beneficiaryDetailsId = bm.BenDetailsId + WHERE ibd.BeneficiaryId IN :benIds + """, nativeQuery = true) + List findBenNamesByBenIds(@Param("benIds") List benIds); + +// BeneficiaryRepo — replaces the per-row getBenIdFromRegID call +@Query("SELECT b.BenRegId, b.benficieryid " + + "FROM RMNCHBeneficiaryDetailsRmnch b " + + "WHERE b.BenRegId IN :regIds AND b.benficieryid IS NOT NULL") +List getBenIdsFromRegIDs(@Param("regIds") List regIds); } diff --git a/src/main/java/com/iemr/flw/repo/identity/HouseHoldRepo.java b/src/main/java/com/iemr/flw/repo/identity/HouseHoldRepo.java index 514eeb6b..a5ee8f25 100644 --- a/src/main/java/com/iemr/flw/repo/identity/HouseHoldRepo.java +++ b/src/main/java/com/iemr/flw/repo/identity/HouseHoldRepo.java @@ -5,8 +5,10 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.util.List; + public interface HouseHoldRepo extends JpaRepository { @Query(" SELECT t FROM RMNCHHouseHoldDetails t WHERE t.houseoldId =:houseoldId ") - RMNCHHouseHoldDetails getByHouseHoldID(@Param("houseoldId") long houseoldId); + List getByHouseHoldID(@Param("houseoldId") long houseoldId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/ANCVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/ANCVisitRepo.java index 067e6acc..67e3e7b9 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/ANCVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/ANCVisitRepo.java @@ -17,8 +17,13 @@ public interface ANCVisitRepo extends JpaRepository { List getANCForPW(@Param("userId") String userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query(value = "SELECT anc FROM ANCVisit anc WHERE anc.createdBy = :userId and anc.isActive = true") + List getANCForPW(@Param("userId") String userId); + @Query - ANCVisit findANCVisitByBenIdAndAncVisitAndIsActive(Long benId, Integer ancVisit, boolean b); + List findANCVisitByBenIdAndAncVisitAndIsActive(Long benId, Integer ancVisit, boolean b); + + List findByBenId(Long benId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/AncCounsellingCareRepo.java b/src/main/java/com/iemr/flw/repo/iemr/AncCounsellingCareRepo.java new file mode 100644 index 00000000..714dae59 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/AncCounsellingCareRepo.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.AncCare; +import com.iemr.flw.domain.iemr.AncCounsellingCare; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface AncCounsellingCareRepo extends JpaRepository { + List findAllByUserId(Integer userId); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java new file mode 100644 index 00000000..78bb368b --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/AshaSupervisorLoginRepo.java @@ -0,0 +1,85 @@ +package com.iemr.flw.repo.iemr; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; + +import com.iemr.flw.domain.iemr.AshaSupervisorMapping; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface AshaSupervisorLoginRepo extends CrudRepository { + + ArrayList findBySupervisorUserIDAndDeletedFalse(Integer supervisorUserID); + + // API 1: All ASHAs mapped to a supervisor with facility info + @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID AND u.Deleted = false " + + "JOIN m_facility f ON f.FacilityID = asm.facilityID AND f.Deleted = false " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false", nativeQuery = true) + List getAllMappedAshas(@Param("supervisorUserID") Integer supervisorUserID); + + // API 2: ASHAs at a specific facility for a supervisor with user details + @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID " + + "AND u.Deleted = false " + + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + + "JOIN incentive_activity_record iar " + + "ON iar.asha_id = asm.ashaUserID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.facilityID = :facilityID " + + "AND asm.deleted = false " + + "AND iar.is_claimed = true " + + "AND iar.start_date >= :startDate " + + "AND iar.end_date < :endDate " + + "AND (:approvalStatus = 0 " + + "OR iar.approval_status = :approvalStatus)", + nativeQuery = true) + List getAshasAtFacility( + @Param("supervisorUserID") Integer supervisorUserID, + @Param("facilityID") Integer facilityID, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + + @Query(value = "SELECT DISTINCT asm.ashaUserID, " + + "u.FirstName, " + + "u.LastName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u " + + "ON u.UserID = asm.ashaUserID " + + "AND u.Deleted = false " + + "LEFT JOIN m_gender g " + + "ON g.GenderID = u.GenderID " + + "JOIN incentive_activity_record iar " + + "ON iar.asha_id = asm.ashaUserID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false " + + "AND iar.is_claimed = true " + + "AND iar.start_date >= :startDate " + + "AND iar.end_date < :endDate " + + "AND ( :approvalStatus = 0 " + + "OR iar.approval_status = :approvalStatus )", + nativeQuery = true) + List getAshasAtFacility( + @Param("supervisorUserID") Integer supervisorUserID, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/BenAnthropometryRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BenAnthropometryRepo.java new file mode 100644 index 00000000..1856eb06 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/BenAnthropometryRepo.java @@ -0,0 +1,15 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.BenAnthropometryDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface BenAnthropometryRepo extends JpaRepository { + + List findByBeneficiaryRegIDOrderByCreatedDateDesc(Long beneficiaryRegID); + + BenAnthropometryDetail findByBenVisitID(Long benVisitID); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/BenChiefComplaintRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BenChiefComplaintRepo.java new file mode 100644 index 00000000..47a73f98 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/BenChiefComplaintRepo.java @@ -0,0 +1,9 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.BenChiefComplaint; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BenChiefComplaintRepo extends JpaRepository { +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/BenFlowStatusRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BenFlowStatusRepo.java new file mode 100644 index 00000000..4658f7cc --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/BenFlowStatusRepo.java @@ -0,0 +1,38 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.BenFlowStatus; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.sql.Timestamp; +import java.util.List; + +@Repository +public interface BenFlowStatusRepo extends JpaRepository { + + @Query("SELECT b FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId AND b.nurseFlag = 1 AND b.deleted = false ORDER BY b.registrationDate DESC") + List getNurseWorklist(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); + + @Query("SELECT b FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId AND b.deleted = false ORDER BY b.registrationDate DESC") + List getRegistrarWorklist(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); + + @Query("SELECT b FROM BenFlowStatus b WHERE b.beneficiaryRegID = :benRegID AND b.deleted = false ORDER BY b.registrationDate DESC") + List findByBeneficiaryRegID(@Param("benRegID") Long benRegID); + + @Modifying + @Query("UPDATE BenFlowStatus b SET b.nurseFlag = 9, b.pharmacistFlag = 1 WHERE b.benFlowID = :benFlowID") + int updateAfterNurseSubmit(@Param("benFlowID") Long benFlowID); + + // Stop TB: nurse done, counsellor pending when diagnostic is positive (set by device push) + @Modifying + @Query("UPDATE BenFlowStatus b SET b.nurseFlag = 9 WHERE b.benFlowID = :benFlowID") + int updateStopTBAfterNurseSubmit(@Param("benFlowID") Long benFlowID); + + // Stop TB: device operator pushes positive diagnostic → route to counsellor + @Modifying + @Query("UPDATE BenFlowStatus b SET b.doctorFlag = 1 WHERE b.beneficiaryRegID = :benRegID AND b.visitCategory = 'Stop TB' AND b.deleted = false") + int routeToStopTBCounsellor(@Param("benRegID") Long benRegID); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/BenPhysicalVitalRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BenPhysicalVitalRepo.java new file mode 100644 index 00000000..7e474935 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/BenPhysicalVitalRepo.java @@ -0,0 +1,15 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.BenPhysicalVitalDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface BenPhysicalVitalRepo extends JpaRepository { + + List findByBeneficiaryRegIDOrderByCreatedDateDesc(Long beneficiaryRegID); + + BenPhysicalVitalDetail findByBenVisitID(Long benVisitID); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java index b5277c19..9cb35662 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/BenReferDetailsRepo.java @@ -24,11 +24,15 @@ import com.iemr.flw.domain.iemr.BenReferDetails; +import io.swagger.v3.oas.annotations.info.License; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Optional; + @Repository public interface BenReferDetailsRepo extends JpaRepository { @@ -40,4 +44,19 @@ public interface BenReferDetailsRepo extends JpaRepository findByCreatedBy(String userName); + + @Query(value = """ + SELECT COUNT(*) + FROM db_iemr.t_benreferdetails + WHERE CreatedBy = :userName + AND MONTH(CreatedDate) = :month + AND YEAR(CreatedDate) = :year + """, nativeQuery = true) + Long countMonthlyReferrals( + @Param("userName") String userName, + @Param("month") Integer month, + @Param("year") Integer year); + } diff --git a/src/main/java/com/iemr/flw/repo/iemr/BenVisitDetailsRepo.java b/src/main/java/com/iemr/flw/repo/iemr/BenVisitDetailsRepo.java index dfd605ef..47aacb2b 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/BenVisitDetailsRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/BenVisitDetailsRepo.java @@ -2,10 +2,26 @@ import com.iemr.flw.domain.iemr.BenVisitDetail; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.sql.Timestamp; import java.util.List; @Repository public interface BenVisitDetailsRepo extends JpaRepository { - public List findByBeneficiaryRegId(Long benRegID);} + + List findByBeneficiaryRegId(Long benRegID); + + @Query("SELECT v FROM BenVisitDetail v WHERE v.beneficiaryRegId = :benRegID " + + "AND v.visitCategory = 'Stop TB' " + + "AND v.visitDateTime >= :dayStart AND v.visitDateTime < :dayEnd") + BenVisitDetail findStopTBVisitForToday(@Param("benRegID") Long benRegID, + @Param("dayStart") Timestamp dayStart, + @Param("dayEnd") Timestamp dayEnd); + + @Query("SELECT COUNT(v) FROM BenVisitDetail v WHERE v.beneficiaryRegId = :benRegID " + + "AND v.visitCategory = 'Stop TB'") + Integer countStopTBVisits(@Param("benRegID") Long benRegID); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/CbacIemrDetailsRepo.java b/src/main/java/com/iemr/flw/repo/iemr/CbacIemrDetailsRepo.java new file mode 100644 index 00000000..5e93dfad --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/CbacIemrDetailsRepo.java @@ -0,0 +1,44 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.CbacDetailsImer; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + + +import java.util.List; + +@Repository +public interface CbacIemrDetailsRepo extends CrudRepository { + + public CbacDetailsImer findByBeneficiaryRegIdAndVisitCode(Long beneficiaryRegId, Long visitCode); + + List findByCreatedBy(String userName); + + @Query(value = "SELECT BeneficiaryID FROM db_identity.m_beneficiaryregidmapping " + + "WHERE BenRegId = :benRegId AND Deleted = 0", nativeQuery = true) + Long getBeneficiaryId(@Param("benRegId") Long benRegId); + +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/CdrRepo.java b/src/main/java/com/iemr/flw/repo/iemr/CdrRepo.java index d5e0e711..069362e8 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/CdrRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/CdrRepo.java @@ -14,7 +14,5 @@ public interface CdrRepo extends JpaRepository { CDR findCDRByBenId(Long benId); - @Query(" SELECT c FROM CDR c WHERE c.createdBy = :userId and c.createdDate >= :fromDate and c.createdDate <= :toDate") - List getAllCdrByBenId(@Param("userId") String userId, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + ListfindByCreatedBy(String userName); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/ChildRegisterRepo.java b/src/main/java/com/iemr/flw/repo/iemr/ChildRegisterRepo.java index 7d10f595..f456428b 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/ChildRegisterRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/ChildRegisterRepo.java @@ -18,4 +18,8 @@ List getChildDetailsForUser(@Param("userId") String userId, // @Query(value = "Select * from db_identity.i_cbacdetails where beneficiaryRegId = :benRegId and createdDate = :createdDate limit 1", nativeQuery = true) ChildRegister findChildRegisterByBenIdAndCreatedDate(Long benRegId, Timestamp createdDate); + + Long countByBenId(Long benId); + + List findByBenId(Long benId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java b/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java index 9ed0943c..99487cc2 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/ChildVaccinationRepo.java @@ -18,11 +18,34 @@ List getChildVaccinationDetails(@Param("userId") String userId ChildVaccination findChildVaccinationByBeneficiaryRegIdAndCreatedDateAndVaccineName(Long benRegId, Timestamp createdDate, String vaccine); - @Query(value = "select count(*) from db_iemr.t_childvaccinedetail1 cv left outer join db_iemr.m_immunizationservicevaccination v on " + - "cv.VaccineName = v.VaccineName where cv.beneficiaryRegId = :benRegId and v.Currentimmunizationserviceid in (1,2,3,4,5) and " + - "v.category = 'CHILD'", nativeQuery = true) + @Query(value = """ + SELECT COUNT(DISTINCT cv.VaccineName) + FROM db_iemr.t_childvaccinedetail1 cv + JOIN db_iemr.m_immunizationservicevaccination v + ON cv.VaccineName = v.VaccineName + WHERE cv.BeneficiaryRegID = :benRegId + AND v.Currentimmunizationserviceid IN (1,2,3,4,5) + AND v.category = 'CHILD' + """, nativeQuery = true) Integer getFirstYearVaccineCountForBenId(@Param("benRegId") Long benRegId); + @Query(value = """ + SELECT COUNT(DISTINCT cv.VaccineName) + FROM db_iemr.t_childvaccinedetail1 cv + WHERE cv.BeneficiaryRegID = :benRegId + AND cv.VaccineName IN ( + 'BCG Vaccine', + 'OPV-1', + 'OPV-2', + 'OPV-3', + 'Pentavalent-1', + 'Pentavalent-2', + 'Pentavalent-3', + 'Measles & Rubella (MR)-1' + ) + """, nativeQuery = true) + Integer getEligibleFirstYearVaccines(@Param("benRegId") Long benRegId); + @Query(value = "select count(*) from db_iemr.m_immunizationservicevaccination v where v.Currentimmunizationserviceid in (1,2,3,4,5) " + @@ -42,4 +65,16 @@ List getChildVaccinationDetails(@Param("userId") String userId "cv.VaccineName = v.VaccineName where cv.beneficiaryRegId = :benRegId and v.Currentimmunizationserviceid = 8 and v.VaccineName = " + "'DPT Booster-2' and v.category = 'CHILD'), 1, 0);", nativeQuery = true) Integer checkDptVaccinatedUser(@Param("benRegId") Long benRegId); + + @Query(value = """ + SELECT COUNT(DISTINCT cv.VaccineName) + FROM db_iemr.t_childvaccinedetail1 cv + WHERE cv.BeneficiaryRegID = :benRegId + AND cv.VaccineName IN ( + 'DPT Booster-1', + 'Measles & Rubella (MR)-2', + 'OPV Booster' + ) + """, nativeQuery = true) + Integer getEligibleSecondYearVaccines(@Param("benRegId") Long benRegId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/ChronicDiseaseVisitRepository.java b/src/main/java/com/iemr/flw/repo/iemr/ChronicDiseaseVisitRepository.java new file mode 100644 index 00000000..e63835a9 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/ChronicDiseaseVisitRepository.java @@ -0,0 +1,14 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.ChronicDiseaseVisitEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ChronicDiseaseVisitRepository + extends JpaRepository { + + List findByUserID(Integer ashaId); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/DeliveryOutcomeRepo.java b/src/main/java/com/iemr/flw/repo/iemr/DeliveryOutcomeRepo.java index 643d7c9a..cf09f625 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/DeliveryOutcomeRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/DeliveryOutcomeRepo.java @@ -16,5 +16,7 @@ public interface DeliveryOutcomeRepo extends JpaRepository getDeliveryOutcomeByAshaId(@Param("userId") String userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + List findByCreatedBy(String userName); + DeliveryOutcome findDeliveryOutcomeByBenIdAndIsActive(Long benId, Boolean isActive); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java b/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java index 567b62a5..36873319 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java +++ b/src/main/java/com/iemr/flw/repo/iemr/DiseaseLeprosyRepository.java @@ -16,4 +16,6 @@ public interface DiseaseLeprosyRepository extends JpaRepository getByCreatedBy(@Param("createdBy") String createdBy); + + } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/DynamicFormRepo.java b/src/main/java/com/iemr/flw/repo/iemr/DynamicFormRepo.java new file mode 100644 index 00000000..69260ea1 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/DynamicFormRepo.java @@ -0,0 +1,47 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.masterEnum.FormType; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +/** + * Repository for dynamic form definitions. + */ +@Repository +public interface DynamicFormRepo extends JpaRepository { + + Optional findByFormUuid(String formUuid); + + Optional findByFormUuidAndIsActive(String formUuid, Boolean isActive); + + List findByIsActiveOrderByFormIdAsc(Boolean isActive); + + Optional findByFormTypeAndIsActive(FormType formType, Boolean isActive); + + List findByIsActiveTrueAndFollowUpDelayDaysIsNotNull(); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/EligibleCoupleRegisterRepo.java b/src/main/java/com/iemr/flw/repo/iemr/EligibleCoupleRegisterRepo.java index 2eae0b05..218c5b2b 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/EligibleCoupleRegisterRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/EligibleCoupleRegisterRepo.java @@ -14,7 +14,12 @@ public interface EligibleCoupleRegisterRepo extends JpaRepository findByCreatedBy(String userName); + @Query(" SELECT ecr FROM EligibleCoupleRegister ecr WHERE ecr.createdBy = :userId and ecr.createdDate >= :fromDate and ecr.createdDate <= :toDate") List getECRegRecords(@Param("userId") String userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + + @Query(" SELECT ecr FROM EligibleCoupleRegister ecr WHERE ecr.createdBy = :userId") + List getECRegRecords(@Param("userId") String userId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/EmployeeMasterRepo.java b/src/main/java/com/iemr/flw/repo/iemr/EmployeeMasterRepo.java index d3ac8edf..943b43b1 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/EmployeeMasterRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/EmployeeMasterRepo.java @@ -1,12 +1,14 @@ package com.iemr.flw.repo.iemr; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; @Repository -public interface EmployeeMasterRepo extends JpaRepository { - M_User findByUserID(Integer userID); - - M_User getUserByUserID(Integer parseLong); +public interface EmployeeMasterRepo extends JpaRepository { + @Query("SELECT u FROM User u WHERE u.userID = :userID and u.deleted=false and u.statusID in (1, 2)") + User findUserByUserID(@Param("userID") Integer userID); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/EyeCheckUpVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/EyeCheckUpVisitRepo.java index c0e3df73..fd713c44 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/EyeCheckUpVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/EyeCheckUpVisitRepo.java @@ -10,4 +10,5 @@ public interface EyeCheckUpVisitRepo extends JpaRepository { List findByUserId(Integer userId); + List findByCreatedBy(String userName); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/FacilityLoginRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FacilityLoginRepo.java new file mode 100644 index 00000000..2f956b3b --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/FacilityLoginRepo.java @@ -0,0 +1,98 @@ +package com.iemr.flw.repo.iemr; + +import java.util.List; + +import com.iemr.flw.domain.iemr.AshaSupervisorMapping; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + + +@Repository +public interface FacilityLoginRepo extends CrudRepository { + + // Get user's facility IDs from m_UserServiceRoleMapping (for ANY user) + @Query(value = "SELECT DISTINCT usrm.FacilityID " + + "FROM m_UserServiceRoleMapping usrm " + + "WHERE usrm.UserID = :userID AND usrm.Deleted = false " + + "AND usrm.FacilityID IS NOT NULL", nativeQuery = true) + List getUserFacilityIDs(@Param("userID") Integer userID); + + // Get facility details with geo names and facilityType + @Query(value = "SELECT DISTINCT f.FacilityID, f.FacilityName, " + + "f.StateID, COALESCE(s.StateName,'') AS stateName, " + + "f.DistrictID, COALESCE(d.DistrictName,'') AS districtName, " + + "f.BlockID, COALESCE(b.BlockName,'') AS blockName, " + + "COALESCE(f.RuralUrban,'') AS ruralUrban, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName " + + "FROM m_facility f " + + "LEFT JOIN m_state s ON s.StateID = f.StateID " + + "LEFT JOIN m_district d ON d.DistrictID = f.DistrictID " + + "LEFT JOIN m_districtblock b ON b.BlockID = f.BlockID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE f.FacilityID IN :facilityIDs AND f.Deleted = false", nativeQuery = true) + List getFacilityDetails(@Param("facilityIDs") List facilityIDs); + + // ASHA login: get supervisor details + @Query(value = "SELECT asm.supervisorUserID, u.FirstName, u.LastName, u.ContactNo, " + + "COALESCE(u.EmployeeID,'') AS employeeID " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.supervisorUserID " + + "WHERE asm.ashaUserID = :ashaUserID AND asm.deleted = false " + + "AND u.Deleted = false LIMIT 1", nativeQuery = true) + List getSupervisorForAsha(@Param("ashaUserID") Integer ashaUserID); + + @Query(value = "SELECT GenderName FROM m_gender WHERE GenderID = :genderID", nativeQuery = true) + String getGenderName(@Param("genderID") Integer genderID); + + // Villages mapped to facilities + @Query(value = "SELECT fvm.FacilityID, fvm.DistrictBranchID, dbm.VillageName " + + "FROM facility_village_mapping fvm " + + "JOIN m_DistrictBranchMapping dbm ON dbm.DistrictBranchID = fvm.DistrictBranchID " + + "WHERE fvm.FacilityID IN :facilityIDs AND fvm.Deleted = false", nativeQuery = true) + List getVillagesForFacilities(@Param("facilityIDs") List facilityIDs); + + // ASHA login: get peers at same facility (ANM, CHO, etc.) + @Query(value = "SELECT DISTINCT usrm.UserID, u.FirstName, u.LastName, r.RoleName, " + + "COALESCE(u.EmployeeID,'') AS employeeID, " + + "COALESCE(u.ContactNo,'') AS mobile " + + "FROM m_UserServiceRoleMapping usrm " + + "JOIN m_User u ON u.UserID = usrm.UserID " + + "JOIN m_Role r ON r.RoleID = usrm.RoleID " + + "WHERE usrm.FacilityID IN :facilityIDs " + + "AND usrm.UserID != :currentUserID " + + "AND usrm.Deleted = false AND u.Deleted = false", nativeQuery = true) + List getPeersAtFacility(@Param("facilityIDs") List facilityIDs, + @Param("currentUserID") Integer currentUserID); + + // Supervisor: get mapped ASHAs with facility details + @Query(value = "SELECT DISTINCT u.UserID, u.FirstName, u.LastName, " + + "COALESCE(u.EmployeeID,'') AS employeeID, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName, " + + "COALESCE(u.ContactNo,'') AS mobile " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID " + + "JOIN m_facility f ON f.FacilityID = asm.facilityID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false AND u.Deleted = false AND f.Deleted = false", nativeQuery = true) + List getMappedAshasBySupervisor(@Param("supervisorUserID") Integer supervisorUserID); + + // CHO/ANM: get ASHAs at same facilities + @Query(value = "SELECT DISTINCT u.UserID, u.FirstName, u.LastName, " + + "COALESCE(u.EmployeeID,'') AS employeeID, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName, " + + "COALESCE(u.ContactNo,'') AS mobile " + + "FROM m_UserServiceRoleMapping usrm " + + "JOIN m_User u ON u.UserID = usrm.UserID " + + "JOIN m_Role r ON r.RoleID = usrm.RoleID " + + "JOIN m_facility f ON f.FacilityID = usrm.FacilityID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE usrm.FacilityID IN :facilityIDs " + + "AND r.RoleName = 'ASHA' " + + "AND usrm.Deleted = false AND u.Deleted = false AND f.Deleted = false", nativeQuery = true) + List getAshaListByFacilities(@Param("facilityIDs") List facilityIDs); +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/FilariasisCampaignRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FilariasisCampaignRepo.java new file mode 100644 index 00000000..1fe0d3e2 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/FilariasisCampaignRepo.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.FilariasisCampaign; +import com.iemr.flw.domain.iemr.PulsePolioCampaign; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface FilariasisCampaignRepo extends JpaRepository { + Page findByUserId(Integer userId, Pageable pageable); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java new file mode 100644 index 00000000..66672c16 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/FormResponseRepo.java @@ -0,0 +1,72 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.FormResponse; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.sql.Timestamp; +import java.util.List; + +/** + * Repository for form-level responses. + * + * @author Piramal Swasthya + */ +@Repository +public interface FormResponseRepo extends JpaRepository { + + List findByBeneficiaryIdAndFormId(Long beneficiaryId, Long formId); + + @Query("SELECT r.beneficiaryId FROM FormResponse r WHERE r.formId = :formId AND r.status = :status") + List findBeneficiaryIdsByFormIdAndStatus(@Param("formId") Long formId, @Param("status") String status); + + @Query("SELECT r.beneficiaryId FROM FormResponse r WHERE r.formId = :formId AND r.status = :status " + + "AND r.beneficiaryId IN (SELECT b.beneficiaryID FROM BenFlowStatus b WHERE b.deleted = false " + + "AND (:villageId IS NULL OR b.villageID = :villageId) " + + "AND (:providerServiceMapId IS NULL OR b.providerServiceMapId = :providerServiceMapId))") + List findBeneficiaryIdsByFormIdAndStatusFiltered(@Param("formId") Long formId, + @Param("status") String status, + @Param("villageId") Integer villageId, + @Param("providerServiceMapId") Integer providerServiceMapId); + + @Query("SELECT r.beneficiaryId FROM FormResponse r " + + "WHERE r.beneficiaryId IN :benIds " + + "AND r.formId = :formId " + + "AND r.status = :status") + List findCounselledBenIds(@Param("benIds") List benIds, + @Param("formId") Long formId, + @Param("status") String status); + + @Query("SELECT r FROM FormResponse r " + + "WHERE r.formId IN :formIds " + + "AND r.status = 'SUBMITTED' " + + "AND r.lastFollowUpAt >= :windowStart " + + "AND r.lastFollowUpAt < :windowEnd") + List findPendingFollowUps( + @Param("formIds") List formIds, + @Param("windowStart") Timestamp windowStart, + @Param("windowEnd") Timestamp windowEnd); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/FormSectionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FormSectionRepo.java new file mode 100644 index 00000000..b4064395 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/FormSectionRepo.java @@ -0,0 +1,38 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.FormSection; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * Repository for form sections. + * Each section belongs to one FormVersion via the version_id FK. + */ +@Repository +public interface FormSectionRepo extends JpaRepository { + + List findByFormVersion_VersionIdOrderByDisplayOrderAsc(Long versionId); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/FormVersionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/FormVersionRepo.java new file mode 100644 index 00000000..1d8583ae --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/FormVersionRepo.java @@ -0,0 +1,46 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.FormVersion; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +/** + * Repository for form versions. + */ +@Repository +public interface FormVersionRepo extends JpaRepository { + + Optional findByDynamicForm_FormIdAndIsLatest(Long formId, Boolean isLatest); + + Optional findByDynamicForm_FormIdAndVersionNumber(Long formId, Integer versionNumber); + + Optional findTopByDynamicForm_FormIdOrderByVersionNumberDesc(Long formId); + + List findByDynamicForm_FormIdOrderByVersionNumberAsc(Long formId); + + Optional findByDynamicForm_FormUuidAndIsLatest(String formUuid, boolean b); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java index 655c0547..cbc7f568 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/HbncVisitRepo.java @@ -1,6 +1,8 @@ package com.iemr.flw.repo.iemr; import com.iemr.flw.domain.iemr.HbncVisit; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -20,6 +22,5 @@ public interface HbncVisitRepo extends JpaRepository { HbncVisit findByBeneficiaryIdAndVisit_day(@Param("beneficiaryId") Long beneficiaryId, @Param("visitDay") String visitDay); - List findByAshaId(Integer ashaId); - + Page findByAshaId(Integer ashaId, Pageable pageable); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IFAFormSubmissionRepository.java b/src/main/java/com/iemr/flw/repo/iemr/IFAFormSubmissionRepository.java index 40cbd60b..0b1b5ff7 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IFAFormSubmissionRepository.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IFAFormSubmissionRepository.java @@ -2,6 +2,8 @@ import com.iemr.flw.domain.iemr.IFAFormSubmissionData; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; @@ -9,4 +11,10 @@ public interface IFAFormSubmissionRepository extends JpaRepository { List findByUserId(Integer userName); + @Query("SELECT i FROM IFAFormSubmissionData i " + + "WHERE i.userId = :userId " + + "AND i.visitDate = :visitDate") + List findTodayData( + @Param("userId") Integer userId, + @Param("visitDate") String visitDate); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveActivityLangMappingRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveActivityLangMappingRepo.java index f9807010..4ba40dc6 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveActivityLangMappingRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveActivityLangMappingRepo.java @@ -3,9 +3,12 @@ import com.iemr.flw.domain.iemr.IncentiveActivityLangMapping; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Collection; import java.util.List; import java.util.Optional; public interface IncentiveActivityLangMappingRepo extends JpaRepository { IncentiveActivityLangMapping findByIdAndName(Long activityId,String activityName); + List findAllByIdIn(List ids); + } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentivePendingActivityRepository.java b/src/main/java/com/iemr/flw/repo/iemr/IncentivePendingActivityRepository.java new file mode 100644 index 00000000..295d447b --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentivePendingActivityRepository.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import java.util.Optional; +import com.iemr.flw.domain.iemr.IncentivePendingActivity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + + +@Repository +public interface IncentivePendingActivityRepository extends JpaRepository { + + Optional findByMincentiveIdAndActivityId(Long mIncentiveId,Long activityId); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java index 6b8db13e..8c21f0e9 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentiveRecordRepo.java @@ -2,43 +2,213 @@ import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import jakarta.persistence.Column; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import java.sql.Timestamp; import java.util.List; +import java.util.Optional; @Repository public interface IncentiveRecordRepo extends JpaRepository { - @Query("select record from IncentiveActivityRecord record where record.activityId = :id and record.createdDate = :createdDate and record.benId = :benId") - IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId(@Param("id") Long id, @Param("createdDate") Timestamp createdDate, @Param("benId") Long benId); + @Query(value = """ + SELECT * + FROM db_iemr.incentive_activity_record r + WHERE r.activity_id = :id + AND r.ben_id = :benId + AND r.asha_id = :ashaId + AND MONTH(r.start_date) = MONTH(:createdDate) + AND YEAR(r.start_date) = YEAR(:createdDate) + LIMIT 1 + """, nativeQuery = true) + IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId( + @Param("id") Long id, + @Param("createdDate") Timestamp createdDate, + @Param("benId") Long benId, + @Param("ashaId") Integer ashaId); - @Query("select record from IncentiveActivityRecord record where record.activityId = :id and record.createdDate = :createdDate and record.benId = :benId and record.ashaId = :ashaId") - IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId(@Param("id") Long id, @Param("createdDate") Timestamp createdDate, @Param("benId") Long benId,@Param("ashaId") Integer ashaId); + Optional findById(Long id); - @Query("SELECT record FROM IncentiveActivityRecord record " + - "WHERE record.activityId = :id " + - "AND record.createdDate BETWEEN :startDate AND :endDate " + - "AND record.benId = :benId " + // ← space added here - "AND record.ashaId = :ashaId") + @Query(value = """ + SELECT * + FROM incentive_activity_record + WHERE activity_id = :activityId + AND ben_id = :benId + AND asha_id = :ashaId + AND created_date >= :startOfMonth + AND created_date < :startOfNextMonth + ORDER BY created_date DESC + LIMIT 1 + """, nativeQuery = true) IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId( - @Param("id") Long id, - @Param("startDate") Timestamp startDate, - @Param("endDate") Timestamp endDate, + @Param("activityId") Long activityId, @Param("benId") Long benId, - @Param("ashaId") Integer ashaId + @Param("ashaId") Integer ashaId, + @Param("startOfMonth") Timestamp startOfMonth, + @Param("startOfNextMonth") Timestamp startOfNextMonth ); @Query("select record from IncentiveActivityRecord record where record.ashaId = :ashaId and record.startDate >= :fromDate and record.startDate <= :toDate and record.endDate >= :fromDate and record.endDate <= :toDate ") - List findRecordsByAsha(@Param("ashaId") Integer ashaId, @Param("fromDate") Timestamp fromDate,@Param("toDate") Timestamp toDate); + List findRecordsByAsha(@Param("ashaId") Integer ashaId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query("SELECT DISTINCT record FROM IncentiveActivityRecord record WHERE record.ashaId = :ashaId") + Page findRecordsByAsha(@Param("ashaId") Integer ashaId, Pageable pageable); - @Query("select record from IncentiveActivityRecord record where record.ashaId = :ashaId") + @Query("SELECT DISTINCT record FROM IncentiveActivityRecord record WHERE record.ashaId = :ashaId") List findRecordsByAsha(@Param("ashaId") Integer ashaId); + + @Query("SELECT " + + "SUM(CASE WHEN record.approvalStatus = 101 THEN 1 ELSE 0 END), " + + "SUM(CASE WHEN record.approvalStatus = 102 THEN 1 ELSE 0 END), " + + "SUM(CASE WHEN record.approvalStatus = 103 THEN 1 ELSE 0 END) " + + "FROM IncentiveActivityRecord record " + + "WHERE record.ashaId = :ashaId " + + "AND record.isClaimed = true " + + "AND record.createdDate >= :startDate " + + "AND record.createdDate < :endDate") + List getStatusCountByAshaId( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + + @Query("SELECT COALESCE(SUM(record.amount), 0) " + + "FROM IncentiveActivityRecord record " + + "JOIN IncentiveActivity master ON record.activityId = master.id " + + "WHERE record.ashaId = :ashaId " + + "AND master.state = :stateCode " + + "AND record.isClaimed = true " + + "AND record.startDate >= :fromDate " + + "AND record.endDate <= :toDate " + + "AND (:approvalStatus = 0 OR record.approvalStatus = :approvalStatus)") + Long getTotalAmountByAsha( + @Param("ashaId") Integer ashaId, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate, + @Param("approvalStatus") Integer approvalStatus, + @Param("stateCode") Integer stateCode); + + + @Query("SELECT record " + + "FROM IncentiveActivityRecord record " + + "WHERE record.ashaId = :ashaId " + + "AND record.isClaimed = true " + + "AND record.startDate <= :toDate " + + "AND record.endDate >= :fromDate") + List getRecordsByAsha( + @Param("ashaId") Integer ashaId, + @Param("fromDate") Timestamp fromDate, + @Param("toDate") Timestamp toDate); + + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.approvalStatus = :approvalStatus, " + + "iar.verifiedByUserId = :ashaSupervisorUserId, " + + "iar.reason = NULL, " + + "iar.otherReason = NULL, " + + "iar.approvalDate = :approvalDate, " + + "iar.verifiedByUserName = :ashaSupervisorUserName " + + "WHERE iar.ashaId = :ashaId " + + "AND iar.isClaimed = true " + + "AND iar.createdDate >= :startDate " + + "AND iar.createdDate < :endDate") + int updateApprovalStatusByAshaAndDateRange( + @Param("ashaId") Integer ashaId, + @Param("approvalStatus") Integer approvalStatus, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate, + @Param("approvalDate") Timestamp approvalDate, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName); + + + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.approvalStatus = :status, " + + "iar.verifiedByUserId = :ashaSupervisorUserId, " + + "iar.reason = :reason, " + + "iar.otherReason = :otherReason, " + + "iar.approvalDate = :approvalDate, " + + "iar.verifiedByUserName = :ashaSupervisorUserName " + + "WHERE iar.isClaimed = true") + int updateApprovalStatusById( + @Param("status") Integer status, + @Param("ashaSupervisorUserId") Integer ashaSupervisorUserId, + @Param("ashaSupervisorUserName") String ashaSupervisorUserName, + @Param("reason") String reason, + @Param("approvalDate") Timestamp approvalDate, + @Param("otherReason") String otherReason + ); + + @Modifying + @Transactional + @Query("UPDATE IncentiveActivityRecord iar " + + "SET iar.isClaimed = :isClaimed, " + + "iar.calimedDate = :calimedDate, " + + "iar.approvalStatus = 102 " + + "WHERE iar.ashaId = :ashaId " + + "AND iar.createdDate >= :startDate " + + "AND iar.createdDate < :endDate") + int updateClaimStatusByAshaAndDateRange( + @Param("ashaId") Integer ashaId, + @Param("isClaimed") Boolean isClaimed, + @Param("calimedDate") Timestamp calimedDate, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate + ); + + @Query("SELECT DISTINCT iar.ashaId FROM IncentiveActivityRecord iar " + + "WHERE iar.calimedDate >= :startDate " + + "AND iar.calimedDate < :endDate " + + "AND iar.isClaimed = true " + + "AND iar.approvalStatus = 101") + List findDistinctAshaIdsByDateRange( + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate + ); + + @Query("SELECT iar FROM IncentiveActivityRecord iar " + + "WHERE iar.ashaId = :ashaId " + + "AND iar.calimedDate >= :startDate " + + "AND iar.calimedDate < :endDate " + + "AND iar.isClaimed = true " + + "AND iar.approvalStatus = 101") + List findClaimedApprovedRecordsByAshaAndDateRange( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate + ); + + // RecordRepo — existing records batch mein fetch karo + @Query("SELECT r FROM IncentiveActivityRecord r " + + "WHERE r.activityId = :activityId " + + "AND r.benId IN :benIds " + + "AND r.ashaId = :ashaId") + List findExistingRecords( + @Param("activityId") Long activityId, + @Param("benIds") List benIds, + @Param("ashaId") Integer ashaId + ); + + @Query("SELECT r FROM IncentiveActivityRecord r WHERE r.ashaId = :ashaId " + + "AND r.calimedDate >= :startDate AND r.calimedDate < :endDate " + + "AND (:approvalStatus = 0 OR r.approvalStatus = :approvalStatus)") + List getRecordsBySuperVisor( + @Param("ashaId") Integer ashaId, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate, + @Param("approvalStatus") Integer approvalStatus); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/IncentivesRepo.java b/src/main/java/com/iemr/flw/repo/iemr/IncentivesRepo.java index 112f74ef..d1cbc7f8 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/IncentivesRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/IncentivesRepo.java @@ -9,7 +9,9 @@ import org.springframework.stereotype.Repository; import java.sql.Timestamp; +import java.util.Collection; import java.util.List; +import java.util.Set; @Repository public interface IncentivesRepo extends JpaRepository { @@ -28,4 +30,28 @@ IncentiveActivity findIncentiveMasterById( @Query("select record from IncentiveActivityRecord record where record.activityId = :id and record.createdDate = :createdDate and record.benId = :benId") IncentiveActivityRecord findRecordByActivityIdCreatedDateBenId(@Param("id") Long id, @Param("createdDate") Timestamp createdDate, @Param("benId") Long benId); -} + + @Query(value = "SELECT " + + "SUM(CASE WHEN i.approval_status = 101 THEN 1 ELSE 0 END) as pendingCount, " + + "SUM(CASE WHEN i.approval_status = 102 THEN 1 ELSE 0 END) as approvalCount, " + + "SUM(CASE WHEN i.approval_status = 103 THEN 1 ELSE 0 END) as rejectCount " + + "FROM m_incentive_activity i " + + "WHERE i.asha_id = :ashaId " + + "AND i.is_deleted = false", + nativeQuery = true) + Object[] getStatusCountByAshaId(@Param("ashaId") Integer ashaId); + + List findByGroupAndIsDeleted(String group, Boolean isDeleted); + + List findByGroupNotAndIsDeleted(String group, Boolean isDeleted); + + // IncentivesRepo — replaces N calls to findIncentiveMasterById() + @Query("SELECT i.id FROM IncentiveActivity i WHERE i.id IN :ids AND i.isDeleted = false AND " + + "(:isCG = true AND i.group = 'ACTIVITY' OR :isCG = false AND i.group != 'ACTIVITY')") + Set findValidActivityIds(@Param("ids") List ids, @Param("isCG") boolean isCG); + + @Query("SELECT i FROM IncentiveActivity i WHERE i.name IN :names AND i.group = :groupName") + List findIncentiveMasterByNameAndGroup( + @Param("names") List names, + @Param("groupName") String groupName + );} diff --git a/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java b/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java index 4227fb3a..a2b38f55 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java +++ b/src/main/java/com/iemr/flw/repo/iemr/LeprosyFollowUpRepository.java @@ -12,7 +12,7 @@ @Repository public interface LeprosyFollowUpRepository extends JpaRepository { - Optional findByBenId(Long benId); + List findByBenId(Long benId); // Custom queries can be added here if needed @Query("SELECT s FROM LeprosyFollowUp s WHERE s.createdBy = :createdBy") diff --git a/src/main/java/com/iemr/flw/repo/iemr/MdsrRepo.java b/src/main/java/com/iemr/flw/repo/iemr/MdsrRepo.java index 532a62c9..127954c6 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/MdsrRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/MdsrRepo.java @@ -14,7 +14,6 @@ public interface MdsrRepo extends JpaRepository { MDSR findMDSRByBenId(Long benId); - @Query(" SELECT m FROM MDSR m WHERE m.createdBy = :userId and m.createdDate >= :fromDate and m.createdDate <= :toDate") - List getAllMdsrByAshaId(@Param("userId") String userId, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + List findByCreatedBy(String userName); + } diff --git a/src/main/java/com/iemr/flw/repo/iemr/OptionConditionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/OptionConditionRepo.java new file mode 100644 index 00000000..63341889 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/OptionConditionRepo.java @@ -0,0 +1,55 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.OptionCondition; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; + +/** + * Repository for option conditions. + */ +@Repository +public interface OptionConditionRepo extends JpaRepository { + + List findByQuestionOption_OptionId(Long optionId); + + @Query("SELECT oc.targetQuestion.questionId FROM OptionCondition oc " + + "WHERE oc.questionOption.sectionQuestion.formSection.formVersion.versionId = :versionId " + + "AND oc.targetQuestion IS NOT NULL") + List findTargetQuestionIdsByVersionId(@Param("versionId") Long versionId); + + /** + * Loads all conditions for a set of options in one query. + * JOIN FETCH ensures questionOption, targetQuestion, and targetSection are hydrated + * so callers can group and resolve references without extra queries. + */ + @Query("SELECT c FROM OptionCondition c JOIN FETCH c.questionOption " + + "LEFT JOIN FETCH c.targetQuestion LEFT JOIN FETCH c.targetSection " + + "WHERE c.questionOption.optionId IN :optionIds") + List findByOptionIds(@Param("optionIds") Collection optionIds); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/OrsCampaignRepo.java b/src/main/java/com/iemr/flw/repo/iemr/OrsCampaignRepo.java new file mode 100644 index 00000000..fbbe380b --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/OrsCampaignRepo.java @@ -0,0 +1,17 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.CampaignOrs; +import com.iemr.flw.dto.iemr.OrsCampaignDTO; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface OrsCampaignRepo extends JpaRepository { + Page findByUserId(Integer userId, Pageable pageable); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/PNCVisitRepo.java b/src/main/java/com/iemr/flw/repo/iemr/PNCVisitRepo.java index 063a0795..39da97da 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/PNCVisitRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/PNCVisitRepo.java @@ -12,9 +12,10 @@ @Repository public interface PNCVisitRepo extends JpaRepository { - @Query(value = "SELECT pnc FROM PNCVisit pnc WHERE pnc.createdBy = :userId and pnc.isActive = true and pnc.createdDate >= :fromDate and pnc.createdDate <= :toDate") - List getPNCForPW(@Param("userId") String userId, - @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query(value = "SELECT pnc FROM PNCVisit pnc WHERE pnc.createdBy = :userId and pnc.isActive = true") + List getPNCForPW(@Param("userId") String userId); PNCVisit findPNCVisitByBenIdAndPncPeriodAndIsActive(Long benId, Integer pncVisit, Boolean isActive); + + List findByBenId(Long benId); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/PhyGeneralExaminationRepo.java b/src/main/java/com/iemr/flw/repo/iemr/PhyGeneralExaminationRepo.java new file mode 100644 index 00000000..abd73b0b --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/PhyGeneralExaminationRepo.java @@ -0,0 +1,9 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.PhyGeneralExamination; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PhyGeneralExaminationRepo extends JpaRepository { +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/PrescribedDrugDetailRepo.java b/src/main/java/com/iemr/flw/repo/iemr/PrescribedDrugDetailRepo.java new file mode 100644 index 00000000..bcdd8ab5 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/PrescribedDrugDetailRepo.java @@ -0,0 +1,9 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.PrescribedDrugDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PrescribedDrugDetailRepo extends JpaRepository { +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/PrescriptionDetailRepo.java b/src/main/java/com/iemr/flw/repo/iemr/PrescriptionDetailRepo.java new file mode 100644 index 00000000..c0d425ec --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/PrescriptionDetailRepo.java @@ -0,0 +1,9 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.PrescriptionDetail; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PrescriptionDetailRepo extends JpaRepository { +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/PulsePolioCampaignRepo.java b/src/main/java/com/iemr/flw/repo/iemr/PulsePolioCampaignRepo.java new file mode 100644 index 00000000..c2cded97 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/PulsePolioCampaignRepo.java @@ -0,0 +1,13 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.CampaignOrs; +import com.iemr.flw.domain.iemr.PulsePolioCampaign; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PulsePolioCampaignRepo extends JpaRepository { + Page findByUserId(Integer userId, Pageable pageable); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java new file mode 100644 index 00000000..f7512055 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/QuestionOptionRepo.java @@ -0,0 +1,48 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.QuestionOption; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; + +/** + * Repository for question options. + */ +@Repository +public interface QuestionOptionRepo extends JpaRepository { + + List findBySectionQuestion_QuestionIdOrderByDisplayOrderAsc(Long questionId); + + /** + * Loads all options for a set of questions in one query. + * JOIN FETCH ensures sectionQuestion is hydrated so callers can group by questionId without extra queries. + */ + @Query("SELECT o FROM QuestionOption o JOIN FETCH o.sectionQuestion " + + "WHERE o.sectionQuestion.questionId IN :questionIds ORDER BY o.displayOrder ASC") + List findByQuestionIdsOrderByDisplayOrderAsc(@Param("questionIds") Collection questionIds); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/QuestionResponseRepo.java b/src/main/java/com/iemr/flw/repo/iemr/QuestionResponseRepo.java new file mode 100644 index 00000000..7dee9795 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/QuestionResponseRepo.java @@ -0,0 +1,46 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.QuestionResponse; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; + +/** + * Repository for question-level answers. + * + * @author Piramal Swasthya + */ +@Repository +public interface QuestionResponseRepo extends JpaRepository { + + List findBySectionResponseId(Long sectionResponseId); + + List findBySectionResponseIdIn(Collection sectionResponseIds); + + void deleteByQuestionIdAndSectionResponseId(Long questionId, Long sectionResponseId); + + void deleteBySectionResponseIdIn(Collection sectionResponseIds); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/QuestionValidationRepo.java b/src/main/java/com/iemr/flw/repo/iemr/QuestionValidationRepo.java new file mode 100644 index 00000000..d1cf4187 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/QuestionValidationRepo.java @@ -0,0 +1,48 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.QuestionValidation; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; + +/** + * Repository for question validation rules. + */ +@Repository +public interface QuestionValidationRepo extends JpaRepository { + + List findBySectionQuestion_QuestionId(Long questionId); + + /** + * Loads all validations for a set of questions in one query. + * JOIN FETCH ensures sectionQuestion is hydrated so callers can group by questionId without extra queries. + */ + @Query("SELECT v FROM QuestionValidation v JOIN FETCH v.sectionQuestion " + + "WHERE v.sectionQuestion.questionId IN :questionIds") + List findByQuestionIds(@Param("questionIds") Collection questionIds); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/SectionQuestionRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SectionQuestionRepo.java new file mode 100644 index 00000000..6a117e96 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/SectionQuestionRepo.java @@ -0,0 +1,48 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.SectionQuestion; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; + +/** + * Repository for section questions. + */ +@Repository +public interface SectionQuestionRepo extends JpaRepository { + + List findByFormSection_SectionIdOrderByDisplayOrderAsc(Long sectionId); + + /** + * Loads all questions for a set of sections in one query. + * JOIN FETCH ensures formSection is hydrated so callers can group by sectionId without extra queries. + */ + @Query("SELECT q FROM SectionQuestion q JOIN FETCH q.formSection " + + "WHERE q.formSection.sectionId IN :sectionIds ORDER BY q.displayOrder ASC") + List findBySectionIdsOrderByDisplayOrderAsc(@Param("sectionIds") Collection sectionIds); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/SectionResponseRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SectionResponseRepo.java new file mode 100644 index 00000000..b83ad8e9 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/SectionResponseRepo.java @@ -0,0 +1,47 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.SectionResponse; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +/** + * Repository for section-level responses. + * + * @author Piramal Swasthya + */ +@Repository +public interface SectionResponseRepo extends JpaRepository { + + List findByResponseId(Long responseId); + + Optional findByResponseIdAndSectionId(Long responseId, Long sectionId); + + List findByResponseIdIn(Collection responseIds); + + void deleteByResponseId(Long responseId); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/StopTBDiagnosticsRepo.java b/src/main/java/com/iemr/flw/repo/iemr/StopTBDiagnosticsRepo.java new file mode 100644 index 00000000..de3fa909 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/StopTBDiagnosticsRepo.java @@ -0,0 +1,31 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.StopTBDiagnostics; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Repository +public interface StopTBDiagnosticsRepo extends JpaRepository { + + @Query("SELECT d FROM StopTBDiagnostics d WHERE d.benRegID = :benRegID AND d.deleted = false") + StopTBDiagnostics findByBenRegID(@Param("benRegID") Long benRegID); + + @Query("SELECT d FROM StopTBDiagnostics d WHERE d.providerServiceMapID = :psmId AND d.deleted = false ORDER BY d.visitDate DESC") + List findAllByProviderServiceMapID(@Param("psmId") Integer psmId); + + @Query("SELECT d FROM StopTBDiagnostics d WHERE d.benRegID IN " + + "(SELECT b.beneficiaryRegID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId) " + + "AND d.deleted = false ORDER BY d.visitDate DESC") + List findAllByProviderServiceMapIDAndVillageID(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); + + @Transactional + @Modifying + @Query("UPDATE StopTBDiagnostics t SET t.vanSerialNo = t.id WHERE t.id = :id") + void updateVanSerialNo(@Param("id") Long id); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralExaminationRepo.java b/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralExaminationRepo.java new file mode 100644 index 00000000..944e99a6 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralExaminationRepo.java @@ -0,0 +1,44 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.StopTBGeneralExamination; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Repository +public interface StopTBGeneralExaminationRepo extends JpaRepository { + + @Query("SELECT e FROM StopTBGeneralExamination e WHERE e.beneficiaryRegID = :beneficiaryRegID AND e.deleted = false") + StopTBGeneralExamination findByBeneficiaryRegID(@Param("beneficiaryRegID") Long beneficiaryRegID); + + // Read-side fix: a beneficiary can now have one row per visit, so the old single-result + // finder above throws NonUniqueResultException once a 2nd visit exists. Used by read/worklist + // endpoints that want "current" status — pass PageRequest.of(0, 1) to get just the latest. + @Query("SELECT e FROM StopTBGeneralExamination e WHERE e.beneficiaryRegID = :beneficiaryRegID " + + "AND e.deleted = false ORDER BY e.createdDate DESC") + List findLatestByBeneficiaryRegID(@Param("beneficiaryRegID") Long beneficiaryRegID, Pageable pageable); + + @Query("SELECT e FROM StopTBGeneralExamination e WHERE e.beneficiaryRegID = :beneficiaryRegID " + + "AND e.visitCode = :visitCode AND e.deleted = false") + StopTBGeneralExamination findByBeneficiaryRegIDAndVisitCode(@Param("beneficiaryRegID") Long beneficiaryRegID, + @Param("visitCode") Long visitCode); + + @Query("SELECT e FROM StopTBGeneralExamination e WHERE e.providerServiceMapID = :psmId AND e.deleted = false ORDER BY e.createdDate DESC") + List findAllByProviderServiceMapID(@Param("psmId") Integer psmId); + + @Query("SELECT e FROM StopTBGeneralExamination e WHERE e.beneficiaryRegID IN " + + "(SELECT b.beneficiaryRegID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId) " + + "AND e.deleted = false ORDER BY e.createdDate DESC") + List findAllByProviderServiceMapIDAndVillageID(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); + + @Transactional + @Modifying + @Query("UPDATE StopTBGeneralExamination t SET t.vanSerialNo = t.id WHERE t.id = :id") + void updateVanSerialNo(@Param("id") Long id); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralOpdRepo.java b/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralOpdRepo.java new file mode 100644 index 00000000..3cb8868f --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/StopTBGeneralOpdRepo.java @@ -0,0 +1,42 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.StopTBGeneralOpd; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Repository +public interface StopTBGeneralOpdRepo extends JpaRepository { + + @Query("SELECT o FROM StopTBGeneralOpd o WHERE o.benRegID = :benRegID AND o.deleted = false") + StopTBGeneralOpd findByBenRegID(@Param("benRegID") Long benRegID); + + // Read-side fix: same NonUniqueResultException risk once a beneficiary has more than one + // visit. Pass PageRequest.of(0, 1) for the latest only. + @Query("SELECT o FROM StopTBGeneralOpd o WHERE o.benRegID = :benRegID " + + "AND o.deleted = false ORDER BY o.createdDate DESC") + List findLatestByBenRegID(@Param("benRegID") Long benRegID, Pageable pageable); + + @Query("SELECT o FROM StopTBGeneralOpd o WHERE o.benRegID = :benRegID " + + "AND o.visitCode = :visitCode AND o.deleted = false") + StopTBGeneralOpd findByBenRegIDAndVisitCode(@Param("benRegID") Long benRegID, @Param("visitCode") Long visitCode); + + @Query("SELECT o FROM StopTBGeneralOpd o WHERE o.providerServiceMapID = :psmId AND o.deleted = false ORDER BY o.createdDate DESC") + List findAllByProviderServiceMapID(@Param("psmId") Integer psmId); + + @Query("SELECT o FROM StopTBGeneralOpd o WHERE o.benRegID IN " + + "(SELECT b.beneficiaryRegID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId) " + + "AND o.deleted = false ORDER BY o.createdDate DESC") + List findAllByProviderServiceMapIDAndVillageID(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); + + @Transactional + @Modifying + @Query("UPDATE StopTBGeneralOpd t SET t.vanSerialNo = t.id WHERE t.id = :id") + void updateVanSerialNo(@Param("id") Long id); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java new file mode 100644 index 00000000..a5658777 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/SupervisorDashboardRepo.java @@ -0,0 +1,111 @@ +package com.iemr.flw.repo.iemr; + +import java.sql.Timestamp; +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; + +@Repository +public interface SupervisorDashboardRepo extends JpaRepository { + + // Get all ASHA userIDs mapped to a supervisor + @Query(value = "SELECT DISTINCT asm.ashaUserID " + + "FROM asha_supervisor_mapping asm " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false", nativeQuery = true) + List getAshaIdsBySupervisor(@Param("supervisorUserID") Integer supervisorUserID); + + // Get ASHAs with facility info for a supervisor + @Query(value = "SELECT DISTINCT asm.ashaUserID, u.FirstName, u.LastName, " + + "f.FacilityID, f.FacilityName, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM asha_supervisor_mapping asm " + + "JOIN m_User u ON u.UserID = asm.ashaUserID AND u.Deleted = false " + + "JOIN m_facility f ON f.FacilityID = asm.facilityID AND f.Deleted = false " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + + "WHERE asm.supervisorUserID = :supervisorUserID " + + "AND asm.deleted = false", nativeQuery = true) + List getAshasWithFacilityInfo(@Param("supervisorUserID") Integer supervisorUserID); + + // Unclaimed incentive count per ASHA + @Query(value = "SELECT iar.asha_id, " + + "COUNT(*) AS unclaimedCount " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN (:ashaIds) " + + "AND iar.created_date >= :startDate " + + "AND iar.created_date < :endDate " + + "AND (iar.is_claimed = false OR iar.is_claimed IS NULL) " + + "GROUP BY iar.asha_id", + nativeQuery = true) + List getUnclaimedCountByAshaIds( + @Param("ashaIds") List ashaIds, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + // Get facility details with geo names + @Query(value = "SELECT DISTINCT f.FacilityID, f.FacilityName, " + + "COALESCE(s.StateName,'') AS stateName, " + + "COALESCE(d.DistrictName,'') AS districtName, " + + "COALESCE(b.BlockName,'') AS blockName, " + + "COALESCE(f.RuralUrban,'') AS ruralUrban, " + + "COALESCE(ft.FacilityTypeName,'') AS facilityTypeName " + + "FROM m_facility f " + + "LEFT JOIN m_state s ON s.StateID = f.StateID " + + "LEFT JOIN m_district d ON d.DistrictID = f.DistrictID " + + "LEFT JOIN m_districtblock b ON b.BlockID = f.BlockID " + + "LEFT JOIN m_facilitytype ft ON ft.FacilityTypeID = f.FacilityTypeID " + + "WHERE f.FacilityID IN :facilityIDs AND f.Deleted = false", nativeQuery = true) + List getFacilityDetails(@Param("facilityIDs") List facilityIDs); + + // Villages mapped to facilities + @Query(value = "SELECT fvm.FacilityID, fvm.DistrictBranchID, dbm.VillageName " + + "FROM facility_village_mapping fvm " + + "JOIN m_DistrictBranchMapping dbm ON dbm.DistrictBranchID = fvm.DistrictBranchID " + + "WHERE fvm.FacilityID IN :facilityIDs AND fvm.Deleted = false", nativeQuery = true) + List getVillagesForFacilities(@Param("facilityIDs") List facilityIDs); + + // Incentive status counts per ASHA: verified, rejected, pending, total amount + @Query(value = "SELECT iar.asha_id, " + + "COUNT(*) AS totalRecords, " + + "SUM(CASE WHEN iar.approval_status = 101 THEN 1 ELSE 0 END) AS verified, " + + "SUM(CASE WHEN iar.approval_status = 103 THEN 1 ELSE 0 END) AS rejected, " + + "SUM(CASE WHEN iar.approval_status = 102 THEN 1 ELSE 0 END) AS pending " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN (:ashaIds) " + + "AND iar.created_date >= :startDate " + + "AND iar.is_claimed = true " + + "AND iar.created_date < :endDate " + + "GROUP BY iar.asha_id", + nativeQuery = true) + List getIncentiveStatusByAshaIds( + @Param("ashaIds") List ashaIds, + @Param("startDate") Timestamp startDate, + @Param("endDate") Timestamp endDate); + + // Incentive activity history per ASHA (recent records) + @Query(value = "SELECT iar.asha_id, iar.name AS activityName, " + + "iar.amount, iar.is_eligible, iar.created_date " + + "FROM incentive_activity_record iar " + + "WHERE iar.asha_id IN :ashaIds " + + "ORDER BY iar.created_date DESC", nativeQuery = true) + List getIncentiveHistoryByAshaIds(@Param("ashaIds") List ashaIds); + + // Supervisor user details + @Query(value = "SELECT u.UserID, u.FirstName, u.LastName, " + + "COALESCE(u.AgentID,'') AS agentID, " + + "COALESCE(u.EmergencyContactNo,'') AS mobile, " + + "COALESCE(g.GenderName,'') AS gender " + + "FROM m_User u " + + "LEFT JOIN m_gender g ON g.GenderID = u.GenderID " + + "WHERE u.UserID = :userId AND u.Deleted = false", nativeQuery = true) + List getSupervisorUserDetails(@Param("userId") Integer userId); +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/repo/iemr/TBConfirmedTreatmentRepository.java b/src/main/java/com/iemr/flw/repo/iemr/TBConfirmedTreatmentRepository.java new file mode 100644 index 00000000..122890e3 --- /dev/null +++ b/src/main/java/com/iemr/flw/repo/iemr/TBConfirmedTreatmentRepository.java @@ -0,0 +1,30 @@ +package com.iemr.flw.repo.iemr; + +import com.iemr.flw.domain.iemr.TBConfirmedCase; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface TBConfirmedTreatmentRepository + extends JpaRepository { + + List findByBenId(Long benId); + List findByUserId(Integer benId); + List findByBenIdAndVisitCode(Long benId, Long visitCode); + + @Query("SELECT tc FROM TBConfirmedCase tc WHERE tc.benId IN " + + "(SELECT b.beneficiaryID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId)") + List getByProviderServiceMapIdAndVillageId(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); + + @Transactional + @Modifying + @Query("UPDATE TBConfirmedCase t SET t.vanSerialNo = t.id WHERE t.id = :id") + void updateVanSerialNo(@Param("id") Integer id); +} diff --git a/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java b/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java index e2f7fed0..f656dc91 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/TBScreeningRepo.java @@ -1,10 +1,13 @@ package com.iemr.flw.repo.iemr; import com.iemr.flw.domain.iemr.TBScreening; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import java.sql.Timestamp; import java.util.List; @@ -15,6 +18,32 @@ public interface TBScreeningRepo extends JpaRepository { @Query(value = "SELECT tbs FROM TBScreening tbs WHERE tbs.benId = :benId and tbs.userId = :userId") TBScreening getByUserIdAndBenId(@Param("benId") Long benId, @Param("userId") Integer userId); - @Query(value = "SELECT tbs FROM TBScreening tbs WHERE tbs.userId = :userId and tbs.visitDate >= :fromDate and tbs.visitDate <= :toDate") - List getByUserId(@Param("userId") Integer userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + @Query(value = "SELECT tbs FROM TBScreening tbs WHERE tbs.userId = :userId") + List getByUserId(@Param("userId") Integer userId); + + @Query("SELECT tbs FROM TBScreening tbs WHERE tbs.benRegID = :benRegID AND tbs.deleted = false") + TBScreening findByBenRegID(@Param("benRegID") Long benRegID); + + // Read-side fix: same NonUniqueResultException risk as StopTBGeneralExaminationRepo once a + // beneficiary has more than one visit. Pass PageRequest.of(0, 1) for the latest only. + @Query("SELECT tbs FROM TBScreening tbs WHERE tbs.benRegID = :benRegID " + + "AND tbs.deleted = false ORDER BY tbs.visitDate DESC") + List findLatestByBenRegID(@Param("benRegID") Long benRegID, Pageable pageable); + + @Query("SELECT tbs FROM TBScreening tbs WHERE tbs.benRegID = :benRegID " + + "AND tbs.visitCode = :visitCode AND tbs.deleted = false") + TBScreening findByBenRegIDAndVisitCode(@Param("benRegID") Long benRegID, @Param("visitCode") Long visitCode); + + @Query("SELECT tbs FROM TBScreening tbs WHERE tbs.providerServiceMapID = :psmId AND tbs.deleted = false ORDER BY tbs.visitDate DESC") + List findAllByProviderServiceMapID(@Param("psmId") Integer psmId); + + @Query("SELECT tbs FROM TBScreening tbs WHERE tbs.benRegID IN " + + "(SELECT b.beneficiaryRegID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId) " + + "AND tbs.deleted = false ORDER BY tbs.visitDate DESC") + List findAllByProviderServiceMapIDAndVillageID(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); + + @Transactional + @Modifying + @Query("UPDATE TBScreening t SET t.vanSerialNo = t.id WHERE t.id = :id") + void updateVanSerialNo(@Param("id") Long id); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/TBSuspectedRepo.java b/src/main/java/com/iemr/flw/repo/iemr/TBSuspectedRepo.java index 995ca760..e559bdfb 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/TBSuspectedRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/TBSuspectedRepo.java @@ -2,9 +2,11 @@ import com.iemr.flw.domain.iemr.TBSuspected; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import java.sql.Timestamp; import java.util.List; @@ -18,6 +20,19 @@ public interface TBSuspectedRepo extends JpaRepository { @Query("SELECT tbs FROM TBSuspected tbs WHERE tbs.benId = :benId and tbs.userId = :userId") TBSuspected getByUserIdAndBenId(@Param("benId") Long benId, @Param("userId") Integer userId); + @Query("SELECT tbs FROM TBSuspected tbs WHERE tbs.benId = :benId and tbs.userId = :userId and tbs.visitCode = :visitCode") + TBSuspected getByUserIdAndBenIdAndVisitCode(@Param("benId") Long benId, @Param("userId") Integer userId, + @Param("visitCode") Long visitCode); + @Query("SELECT tbs FROM TBSuspected tbs WHERE tbs.userId = :userId and tbs.visitDate >= :fromDate and tbs.visitDate <= :toDate") List getByUserId(@Param("userId") Integer userId, @Param("fromDate") Timestamp fromDate, @Param("toDate") Timestamp toDate); + + @Query("SELECT tbs FROM TBSuspected tbs WHERE tbs.benId IN " + + "(SELECT b.beneficiaryID FROM BenFlowStatus b WHERE b.providerServiceMapId = :psmId AND b.villageID = :villageId)") + List getByProviderServiceMapIdAndVillageId(@Param("psmId") Integer psmId, @Param("villageId") Integer villageId); + + @Transactional + @Modifying + @Query("UPDATE TBSuspected t SET t.vanSerialNo = t.id WHERE t.id = :id") + void updateVanSerialNo(@Param("id") Long id); } diff --git a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java index 899a7ffd..b94550a2 100644 --- a/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java +++ b/src/main/java/com/iemr/flw/repo/iemr/UserServiceRoleRepo.java @@ -18,10 +18,60 @@ public interface UserServiceRoleRepo extends JpaRepository getUserRole(@Param("userId") Integer userId); - @Query("select u.userId from UserServiceRole u where u.userName = :userName and u.userServciceRoleDeleted = false") + @Query(value = """ + SELECT UserID + FROM db_iemr.v_userservicerolemapping + WHERE UserName = :userName + AND UserServciceRoleDeleted = 0 + LIMIT 1 + """, nativeQuery = true) Integer getUserIdByName(@Param("userName") String userName); - @Query("select u.userName from UserServiceRole u where u.userId = :userId and u.userServciceRoleDeleted = false") - String getUserNamedByUserId(@Param("userId") Integer userId); + @Query(value = """ + SELECT UserName + FROM db_iemr.v_userservicerolemapping + WHERE UserID = :userId + AND UserServciceRoleDeleted = 0 + LIMIT 1 + """, nativeQuery = true) + String getUserNamedByUserId(@Param("userId") Integer userId); + + @Query(value = "SELECT d.DistrictID, d.DistrictName FROM m_districtblock db " + + "JOIN m_district d ON d.DistrictID = db.DistrictID " + + "WHERE db.BlockID = :blockId LIMIT 1", nativeQuery = true) + List getDistrictByBlockId(@Param("blockId") Integer blockId); + + // Stop TB / Nikshay — additive only. Reads m_userservicerolemapping directly + // (NOT the shared v_userservicerolemapping view) so the view stays untouched + // and no other service line's query is affected. Returns nothing for any + // user whose rows don't have NikshayTUID set (i.e. every non-Stop-TB user). + // NikshayTUID/NikshayFacilityID are TEXT columns holding a comma-joined list + // of IDs (e.g. "12,45,78"), not a single ID. Name resolution against + // m_nikshay_tu/m_nikshay_facility is done in Java (see UserServiceImpl) via + // an indexed IN(...) lookup on their primary keys, instead of joining here + // with FIND_IN_SET — FIND_IN_SET can't use an index on either side, so it + // forces a full scan of the master table per call (measured: ~60s against + // m_nikshay_facility's 300k+ rows for a user with ~100 mapped facilities). + @Query(value = "SELECT usrm.NikshayTUID, usrm.NikshayFacilityID, usrm.DistrictID " + + "FROM m_userservicerolemapping usrm " + + "WHERE usrm.UserID = :userId AND usrm.ProviderServiceMapID = :providerServiceMapId " + + "AND usrm.Deleted = false AND usrm.NikshayTUID IS NOT NULL", + nativeQuery = true) + List getNikshayMappingRows(@Param("userId") Integer userId, + @Param("providerServiceMapId") Integer providerServiceMapId); + + @Query(value = "SELECT NikshayTUID, TUName FROM m_nikshay_tu WHERE NikshayTUID IN (:ids)", nativeQuery = true) + List findNikshayTuNames(@Param("ids") java.util.Collection ids); + + @Query(value = "SELECT NikshayFacilityID, FacilityName FROM m_nikshay_facility WHERE NikshayFacilityID IN (:ids)", nativeQuery = true) + List findNikshayFacilityNames(@Param("ids") java.util.Collection ids); + + // DistrictID on m_userservicerolemapping is a Nikshay district ID, not an + // AMRIT one (see setWorkLocationObject in Admin-UI) - resolving its name + // against m_nikshay_district (the same ID space) is safe, unlike joining it + // against AMRIT's own m_district, which would silently match whatever AMRIT + // district happens to share that same numeric ID by coincidence. + @Query(value = "SELECT DistrictName FROM m_nikshay_district WHERE NikshayDistrictID = :id", nativeQuery = true) + String findNikshayDistrictName(@Param("id") Integer id); } diff --git a/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java new file mode 100644 index 00000000..4fdd3a2d --- /dev/null +++ b/src/main/java/com/iemr/flw/seeder/TbCounsellingFormSeeder.java @@ -0,0 +1,325 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.seeder; + +import com.iemr.flw.dto.iemr.DynamicFormDTO; +import com.iemr.flw.dto.iemr.FormSectionDTO; +import com.iemr.flw.dto.iemr.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.masterEnum.FormType; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.masterEnum.ValidationType; +import com.iemr.flw.repo.iemr.DynamicFormRepo; +import com.iemr.flw.service.DynamicFormDefinitionService; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +/** + * Seeds the TB Counselling form definition on application startup if it does not already exist. + * Idempotent: skips creation if the form UUID is already present in the database. + * + * @author Piramal Swasthya + */ +@Component +@RequiredArgsConstructor +public class TbCounsellingFormSeeder { + + private static final Logger log = LoggerFactory.getLogger(TbCounsellingFormSeeder.class); + + public static final String FORM_UUID = "TB_COUNSELLING"; + + private final DynamicFormDefinitionService formService; + private final DynamicFormRepo formRepo; + + @PostConstruct + public void seed() { + if (formRepo.findByFormUuid(FORM_UUID).isPresent()) { + log.info("TbCounsellingFormSeeder: form '{}' already exists — skipping seed.", FORM_UUID); + return; + } + log.info("TbCounsellingFormSeeder: seeding TB Counselling form..."); + formService.createForm(buildFormDto()); + log.info("TbCounsellingFormSeeder: seed complete."); + } + + // ── Form Definition ────────────────────────────────────────────────────────── + + private DynamicFormDTO buildFormDto() { + DynamicFormDTO dto = new DynamicFormDTO(); + dto.setFormUuid(FORM_UUID); + dto.setFormName("TB Counselling"); + dto.setFormType(FormType.TB_COUNSELLING); + dto.setIsActive(true); + dto.setFollowUpDelayDays(15); + + List sections = new ArrayList<>(); + sections.add(buildSectionA()); + sections.add(buildSectionB()); + sections.add(buildSectionC()); + sections.add(buildSectionD()); + sections.add(buildSectionE()); +// sections.add(buildSectionF()); + dto.setSections(sections); + return dto; + } + + // ── Section A: Disease Awareness ───────────────────────────────────────────── + + private FormSectionDTO buildSectionA() { + FormSectionDTO s = section("TB_SEC_A", "Disease Awareness", "बीमारी के बारे में जागरूकता", "PRE_SUBMIT", 1, true, false); + List qs = new ArrayList<>(); + qs.add(yesNoRadio("TB_A_Q1", "TB disease explained to patient", "मरीज़ को टीबी बीमारी के बारे में समझाया गया।", 1, true)); + qs.add(yesNoRadio("TB_A_Q2", "Transmission route explained", "ट्रांसमिशन के तरीके के बारे में जानकारी", 2, true)); + qs.add(yesNoRadio("TB_A_Q3", "Symptoms explained", "लक्षणों की जानकारी", 3, true)); + qs.add(yesNoRadio("TB_A_Q4", "Treatment duration explained", "इलाज की अवधि के बारे में जानकारी", 4, true)); + qs.add(textQuestion("TB_A_REMARKS", "Disease awareness notes", "बीमारी के बारे में जानकारी देने वाले नोट्स", 5, false, 500, true)); + s.setQuestions(qs); + return s; + } + + // ── Section B: Do's and Don'ts ─────────────────────────────────────────────── + + private FormSectionDTO buildSectionB() { + FormSectionDTO s = section("TB_SEC_B", "Do's and Don'ts", "करो और ना करो", "PRE_SUBMIT", 2, true, false); + List qs = new ArrayList<>(); + qs.add(yesNoRadio("TB_B_Q1", "Cover mouth while coughing — advised", "खांसते समय मुंह ढकने की सलाह दी जाती है।", 1, true)); + qs.add(yesNoRadio("TB_B_Q2", "Complete full treatment course — advised", "इलाज का पूरा कोर्स पूरा करने की सलाह दी जाती है।", 2, true)); + qs.add(yesNoRadio("TB_B_Q3", "Regular follow-up attendance — advised", "इलाज का पूरा कोर्स पूरा करने की सलाह दी जाती है।", 3, true)); + qs.add(yesNoRadio("TB_B_Q4", "Nutritional guidance provided", "पोषण संबंधी मार्गदर्शन प्रदान किया गया", 4, true)); + qs.add(yesNoRadio("TB_B_Q5", "No smoking / alcohol — advised", "धूम्रपान / शराब न लेने की सलाह दी जाती है।", 5, true)); + qs.add(yesNoRadio("TB_B_Q6", "Isolation precautions explained", "अलगाव सावधानियों के बारे में बताया गया", 6, true)); + qs.add(textQuestion("TB_B_REMARKS", "Do's & Don'ts notes", "क्या करें और क्या न करें - नोट्स", 7, false, 500, true)); + s.setQuestions(qs); + return s; + } + + // ── Section C: Government Schemes ──────────────────────────────────────────── + + private FormSectionDTO buildSectionC() { + FormSectionDTO s = section("TB_SEC_C", "Government Schemes", "सरकारी योजनाएं", "PRE_SUBMIT", 3, false, false); + List qs = new ArrayList<>(); + qs.add(yesNoRadio("TB_C_Q1", "Nikshay Poshan Yojana (NPY) eligibility explained", "निक्षय पोषण योजना (एनपीवाई) पात्रता के बारे में बताया गया", 1, true)); + qs.add(yesNoRadio("TB_C_Q2", "DOTS free treatment explained", "DOTS मुफ़्त इलाज के बारे में जानकारी", 2, true)); + qs.add(textQuestion("TB_C_REMARKS", "Schemes notes", "योजनाओं के नोट्स", 3, false, 300, true)); + s.setQuestions(qs); + return s; + } + + // ── Section D: Treatment Regimen ───────────────────────────────────────────── + + private FormSectionDTO buildSectionD() { + FormSectionDTO s = section("TB_SEC_D", "Treatment Regimen", "इलाज का तरीका", "PRE_SUBMIT", 4, true, false); + List qs = new ArrayList<>(); + qs.add(yesNoRadio("TB_D_Q1", "Regimen explained to patient", "मरीज़ को इलाज का तरीका समझाया गया।", 1, true)); + qs.add(yesNoRadio("TB_D_Q2", "Medication names explained", "दवाओं के नामों की जानकारी", 2, true)); + qs.add(yesNoRadio("TB_D_Q3", "Side effects explained", "साइड इफ़ेक्ट्स के बारे में जानकारी", 3, true)); + qs.add(yesNoRadio("TB_D_Q4", "Importance of adherence explained", "निर्देशों का पालन करने का महत्व समझाया गया", 4, true)); + qs.add(textQuestion("TB_D_REMARKS", "Treatment regimen notes", "इलाज के तरीके से जुड़े नोट्स", 5, false, 300, true)); + s.setQuestions(qs); + return s; + } + + // ── Section E: Counselling Completion ──────────────────────────────────────── + + private FormSectionDTO buildSectionE() { + FormSectionDTO s = section("TB_SEC_E", "Counselling Completion", "काउंसलिंग पूरी होना", "PRE_SUBMIT", 5, true, true); + List qs = new ArrayList<>(); + + // Counselling completion status — RADIO: Complete | Refused + SectionQuestionDTO statusQ = new SectionQuestionDTO(); + statusQ.setQuestionUuid("TB_E_Q1"); + statusQ.setQuestionText("Counselling completion status"); + statusQ.setQuestionTextHindi("काउंसलिंग पूरी होने की स्थिति"); + statusQ.setQuestionType(QuestionType.RADIO); + statusQ.setIsMandatory(true); + statusQ.setDisplayOrder(1); + statusQ.setVisibleByDefault(true); + + // "Complete" option — no conditions + QuestionOptionDTO completeOpt = option("Complete", "सम्पूर्ण","COMPLETE", "सम्पूर्ण", 1, List.of()); + + // "Refused" option — 5 conditions: disable sections A-D + show refusal text box + List refusedConditions = new ArrayList<>(); + refusedConditions.add(disableSectionValidation("TB_SEC_A")); + refusedConditions.add(disableSectionValidation("TB_SEC_B")); + refusedConditions.add(disableSectionValidation("TB_SEC_C")); + refusedConditions.add(disableSectionValidation("TB_SEC_D")); + refusedConditions.add(showQuestion("TB_E_REFUSAL")); + QuestionOptionDTO refusedOpt = option("Refused", "अस्वीकार करना", "REFUSED", "अस्वीकार करना", 2, refusedConditions); + + List statusOptions = new ArrayList<>(); + statusOptions.add(completeOpt); + statusOptions.add(refusedOpt); + statusQ.setOptions(statusOptions); + statusQ.setValidations(List.of()); + qs.add(statusQ); + + // Reason for refusal — hidden by default, max 300 chars + qs.add(textQuestion("TB_E_REFUSAL", "Reason for refusal", "इनकार का कारण",2, true, 300, false)); + + // Counsellor remarks — optional, max 500 chars + qs.add(textQuestion("TB_E_REMARKS", "Counsellor remarks", "काउंसलर की टिप्पणी", 3, false, 500, true)); + + s.setQuestions(qs); + return s; + } + + // ── Section F: Follow Up to TU ─────────────────────────────────────────────── + + private FormSectionDTO buildSectionF() { + FormSectionDTO s = section("TB_SEC_F", "Follow Up to TU", "TU के बाद की कार्रवाई", "POST_SUBMIT", 6, true, true); + List qs = new ArrayList<>(); + + // "Has the patient started TB treatment?" — RADIO: Yes | No + SectionQuestionDTO startedQ = new SectionQuestionDTO(); + startedQ.setQuestionUuid("TB_F_Q1"); + startedQ.setQuestionText("Has the patient started the prescribed TB treatment regimen?"); + startedQ.setQuestionTextHindi("क्या मरीज़ ने टीबी के लिए बताया गया इलाज शुरू कर दिया है?"); + startedQ.setQuestionType(QuestionType.RADIO); + startedQ.setIsMandatory(true); + startedQ.setDisplayOrder(1); + startedQ.setVisibleByDefault(true); + + QuestionOptionDTO yesOpt = option("Yes", "हाँ", "YES", "हाँ", 1, List.of()); + + List noConditions = new ArrayList<>(); + noConditions.add(showQuestion("TB_F_NO_REASON")); + QuestionOptionDTO noOpt = option("No", "नहीं", "NO", "नहीं", 2, noConditions); + + List startedOptions = new ArrayList<>(); + startedOptions.add(yesOpt); + startedOptions.add(noOpt); + startedQ.setOptions(startedOptions); + startedQ.setValidations(List.of()); + qs.add(startedQ); + + // Reason for not starting — hidden by default, max 500 chars + qs.add(textQuestion("TB_F_NO_REASON", + "Reason for not starting the prescribed TB treatment regimen", + "टीबी के लिए तय इलाज का तरीका शुरू न करने का कारण", + 2, false, 500, false)); + + // DOTS centre visit + qs.add(yesNoRadio("TB_F_Q2", + "Has the patient visited the DOTS centre / referred health facility for treatment collection?", + "क्या मरीज़ इलाज लेने के लिए DOTS सेंटर या रेफर किए गए स्वास्थ्य केंद्र गया है?", + 3, true)); + + // Side effects reported + qs.add(yesNoRadio("TB_F_Q3", + "Has the patient reported side effects to the treating doctor or DOTS centre?", + "क्या मरीज़ ने इलाज करने वाले डॉक्टर या DOTS सेंटर को साइड इफ़ेक्ट्स के बारे में बताया है?", + 4, true)); + + s.setQuestions(qs); + return s; + } + + // ── Builder Helpers ─────────────────────────────────────────────────────────── + + private FormSectionDTO section(String uuid, String name, String nameHindi, String phase, + int order, boolean required, boolean hasSubmitButton) { + FormSectionDTO s = new FormSectionDTO(); + s.setSectionUuid(uuid); + s.setSectionName(name); + s.setSectionNameHindi(nameHindi); + s.setSectionPhase(phase); + s.setDisplayOrder(order); + s.setIsRequired(required); + s.setHasSubmitButton(hasSubmitButton); + s.setQuestions(new ArrayList<>()); + return s; + } + + private SectionQuestionDTO yesNoRadio(String uuid, String text, String textHindi, int order, boolean mandatory) { + SectionQuestionDTO q = new SectionQuestionDTO(); + q.setQuestionUuid(uuid); + q.setQuestionText(text); + q.setQuestionTextHindi(textHindi); + q.setQuestionType(QuestionType.RADIO); + q.setIsMandatory(mandatory); + q.setDisplayOrder(order); + q.setVisibleByDefault(true); + + List opts = new ArrayList<>(); + opts.add(option("Yes", "हाँ","YES","हाँ", 1, List.of())); + opts.add(option("No", "नहीं","NO", "नहीं", 2, List.of())); + q.setOptions(opts); + q.setValidations(List.of()); + return q; + } + + private SectionQuestionDTO textQuestion(String uuid, String text, String textHindi, int order, + boolean mandatory, int maxLength, boolean visible) { + SectionQuestionDTO q = new SectionQuestionDTO(); + q.setQuestionUuid(uuid); + q.setQuestionText(text); + q.setQuestionTextHindi(textHindi); + q.setQuestionType(QuestionType.TEXT); + q.setIsMandatory(mandatory); + q.setDisplayOrder(order); + q.setMaxLength(maxLength); + q.setVisibleByDefault(visible); + q.setOptions(List.of()); + + QuestionValidationDTO v = new QuestionValidationDTO(); + v.setValidationType(ValidationType.MAX_LENGTH); + v.setValidationParam(String.valueOf(maxLength)); + v.setErrorMessage("Must be " + maxLength + " characters or fewer"); + q.setValidations(List.of(v)); + return q; + } + + private QuestionOptionDTO option(String label, String labelHindi, String value, String valueHindi, int order, + List conditions) { + QuestionOptionDTO o = new QuestionOptionDTO(); + o.setOptionLabel(label); + o.setOptionLabelHindi(labelHindi); + o.setOptionValue(value); + o.setOptionValueHindi(valueHindi); + o.setDisplayOrder(order); + o.setConditions(conditions); + return o; + } + + private OptionConditionDTO showQuestion(String targetQuestionUuid) { + OptionConditionDTO c = new OptionConditionDTO(); + c.setActionType("SHOW_QUESTION"); + c.setTargetQuestionUuid(targetQuestionUuid); + return c; + } + + private OptionConditionDTO disableSectionValidation(String targetSectionUuid) { + OptionConditionDTO c = new OptionConditionDTO(); + c.setActionType("DISABLE_SECTION_VALIDATION"); + c.setTargetSectionUuid(targetSectionUuid); + return c; + } +} diff --git a/src/main/java/com/iemr/flw/service/AbhaBeneficiaryService.java b/src/main/java/com/iemr/flw/service/AbhaBeneficiaryService.java new file mode 100644 index 00000000..02a1281b --- /dev/null +++ b/src/main/java/com/iemr/flw/service/AbhaBeneficiaryService.java @@ -0,0 +1,12 @@ +package com.iemr.flw.service; + +import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; +import com.iemr.flw.dto.iemr.AbhaRequestDTO; +import org.springframework.stereotype.Service; + +import java.util.List; + +public interface AbhaBeneficiaryService { + + Object getBeneficiaryByAbha(AbhaRequestDTO request); +} diff --git a/src/main/java/com/iemr/flw/service/AbhaTokenService.java b/src/main/java/com/iemr/flw/service/AbhaTokenService.java new file mode 100644 index 00000000..dc0affae --- /dev/null +++ b/src/main/java/com/iemr/flw/service/AbhaTokenService.java @@ -0,0 +1,7 @@ +package com.iemr.flw.service; + +import java.util.Map; + +public interface AbhaTokenService { + Map getAbhaToken() throws Exception; +} diff --git a/src/main/java/com/iemr/flw/service/BeneficiaryService.java b/src/main/java/com/iemr/flw/service/BeneficiaryService.java index 1db3026b..e69bc887 100644 --- a/src/main/java/com/iemr/flw/service/BeneficiaryService.java +++ b/src/main/java/com/iemr/flw/service/BeneficiaryService.java @@ -10,7 +10,7 @@ public interface BeneficiaryService { String getBenData(GetBenRequestHandler requestDTO, String authorisation) throws Exception; - String saveEyeCheckupVsit(List eyeCheckupRequestDTOS); + String saveEyeCheckupVsit(List eyeCheckupRequestDTOS,String token); - List getEyeCheckUpVisit(GetBenRequestHandler request); + List getEyeCheckUpVisit(GetBenRequestHandler request,String token); } diff --git a/src/main/java/com/iemr/flw/service/CampConfigService.java b/src/main/java/com/iemr/flw/service/CampConfigService.java new file mode 100644 index 00000000..a8c8ad35 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/CampConfigService.java @@ -0,0 +1,59 @@ +package com.iemr.flw.service; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.stereotype.Service; + +@Service +public class CampConfigService { + + private static final Logger logger = LoggerFactory.getLogger(CampConfigService.class); + private static final String VAN_ID_KEY = "camp:vanID"; + private static final String PARKING_PLACE_ID_KEY = "camp:parkingPlaceID"; + + @Autowired + private LettuceConnectionFactory connectionFactory; + + // When true, saves fail loudly if camp is not configured instead of silently storing vanID=NULL + @Value("${stoptb.enforce.vanid:false}") + private boolean enforceVanID; + + public Integer getVanID() { + String val = read(VAN_ID_KEY); + if (val == null || val.isBlank()) { + if (enforceVanID) { + throw new IllegalStateException( + "Camp not configured: vanID missing. Please select van/service point in MMU before saving Stop TB data."); + } + return null; + } + return Integer.parseInt(val); + } + + public Integer getParkingPlaceID() { + String val = read(PARKING_PLACE_ID_KEY); + if (val == null || val.isBlank()) return 0; + return Integer.parseInt(val); + } + + public boolean isCampConfigured() { + String val = read(VAN_ID_KEY); + return val != null && !val.isBlank(); + } + + private String read(String key) { + try { + RedisConnection conn = connectionFactory.getConnection(); + byte[] data = conn.get(key.getBytes()); + conn.close(); + return data != null ? new String(data) : null; + } catch (Exception e) { + logger.error("Redis read error for key {}: {}", key, e.getMessage()); + return null; + } + } +} diff --git a/src/main/java/com/iemr/flw/service/CampaignService.java b/src/main/java/com/iemr/flw/service/CampaignService.java new file mode 100644 index 00000000..26c67a6a --- /dev/null +++ b/src/main/java/com/iemr/flw/service/CampaignService.java @@ -0,0 +1,24 @@ +package com.iemr.flw.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.iemr.flw.domain.iemr.CampaignOrs; +import com.iemr.flw.domain.iemr.FilariasisCampaign; +import com.iemr.flw.domain.iemr.PulsePolioCampaign; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.utils.exception.IEMRException; + +import java.util.List; + +public interface CampaignService { + List saveOrsCampaign(List orsCampaignDTO, String token) throws IEMRException, JsonProcessingException; + + List savePolioCampaign(List polioCampaignDTOS, String token) throws IEMRException, JsonProcessingException; + + List getOrsCampaign(String token) throws IEMRException; + + List getPolioCampaign(String token) throws IEMRException; + + List saveFilariasisCampaign(List filariasisCampaignDTOS, String token) throws IEMRException, JsonProcessingException; + + List getAllFilariasisCampaign(String token) throws IEMRException; +} diff --git a/src/main/java/com/iemr/flw/service/ChildCareService.java b/src/main/java/com/iemr/flw/service/ChildCareService.java index bbd5c96f..c78de3fd 100644 --- a/src/main/java/com/iemr/flw/service/ChildCareService.java +++ b/src/main/java/com/iemr/flw/service/ChildCareService.java @@ -15,7 +15,7 @@ public interface ChildCareService { List getHBNCDetails(GetBenRequestHandler dto); - String saveHBNCDetails(List hbncRequestDTOs); + String saveHBNCDetails(List hbncRequestDTOs,Integer userId); List getChildVaccinationDetails(GetBenRequestHandler dto); @@ -23,7 +23,7 @@ public interface ChildCareService { List getAllChildVaccines(String category); - String saveSamDetails(List samRequest); + String saveSamDetails(List samRequest,Integer userId,String userName); List getSamVisitsByBeneficiary(GetBenRequestHandler dto); @@ -31,7 +31,7 @@ public interface ChildCareService { List getOrdDistrubtion(GetBenRequestHandler request); - List saveAllIfa(List dtoList); + List saveAllIfa(List dtoList,Integer userId); List getByBeneficiaryId(GetBenRequestHandler request); diff --git a/src/main/java/com/iemr/flw/service/DiseaseControlService.java b/src/main/java/com/iemr/flw/service/DiseaseControlService.java index 92accf4a..65e315dc 100644 --- a/src/main/java/com/iemr/flw/service/DiseaseControlService.java +++ b/src/main/java/com/iemr/flw/service/DiseaseControlService.java @@ -24,7 +24,9 @@ */ package com.iemr.flw.service; +import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.utils.exception.IEMRException; import java.util.List; @@ -44,4 +46,7 @@ public interface DiseaseControlService { public String saveLeprosyFollowUp(LeprosyFollowUpDTO leprosyDTO); List getAllLeprosyFollowUpData(String createdBy); + List saveChronicDiseaseVisit(List requestList,String token) throws IEMRException; + + List getCdtfVisits(GetBenRequestHandler getBenRequestHandler); } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java b/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java new file mode 100644 index 00000000..c7aae24d --- /dev/null +++ b/src/main/java/com/iemr/flw/service/DynamicFormDefinitionService.java @@ -0,0 +1,59 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.service; + +import com.iemr.flw.dto.iemr.DynamicFormDTO; +import com.iemr.flw.dto.iemr.FormSectionDTO; +import com.iemr.flw.dto.iemr.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; + +import java.util.List; + +/** + * Service for managing dynamic form definitions (structure only — not responses). + */ +public interface DynamicFormDefinitionService { + + /** Creates a full form definition (form + v1 + sections + questions + options + validations). */ + DynamicFormDTO createForm(DynamicFormDTO formDTO); + + /** Replaces the form structure with a new version, bumping versionNumber. */ + DynamicFormDTO updateForm(Long formId, DynamicFormDTO formDTO); + + /** Returns the latest version's full definition tree, Redis-cached by formId. */ + DynamicFormDTO getFormDefinition(Long formId); + + /** Returns a specific version's full definition tree (no cache). */ + DynamicFormDTO getFormDefinitionByVersion(Long formId, Integer versionNumber); + + /** Returns metadata for all active forms (without full tree). */ + List getAllForms(); + + /** Sets the form's isActive flag to true. */ + void activateForm(Long formId); + + /** Sets the form's isActive flag to false and invalidates cache. */ + void deactivateForm(Long formId); + +} diff --git a/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java new file mode 100644 index 00000000..cca29e2e --- /dev/null +++ b/src/main/java/com/iemr/flw/service/DynamicFormResponseService.java @@ -0,0 +1,66 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.service; + +import com.iemr.flw.dto.iemr.FormResponseDTO; +import com.iemr.flw.dto.iemr.FormResponseRequest; +import com.iemr.flw.masterEnum.FormType; +import com.iemr.flw.utils.exception.IEMRException; + +import java.util.List; + +/** + * Contract for saving and retrieving dynamic form responses. + * + * @author Piramal Swasthya + */ +public interface DynamicFormResponseService { + + /** Save PRE_SUBMIT section answers and advance status to SUBMITTED. */ + FormResponseDTO submitForm(FormResponseRequest request); + + /** Save POST_SUBMIT section answers and advance status to COMPLETE. */ + FormResponseDTO completeForm(FormResponseRequest request, String jwtToken) throws IEMRException; + + /** All responses for a beneficiary filtered by form UUID. */ + List getResponsesByBeneficiary(Long beneficiaryId, String formUuid); + + /** Single response with all nested section and question answers. */ + FormResponseDTO getResponseById(Long responseId); + + /** + * Submit multiple form responses in one bulk transaction. + * All FormResponse rows are batch-inserted via saveAll() so responseIds are available + * before section/question processing begins. All-or-nothing: any failure rolls back all. + */ + List submitBulk(List requests, String jwtToken); + + /** + * Returns SUBMITTED responses for the given form IDs whose {@code lastFollowUpAt} + * falls within the 24-hour window that started exactly {@code delayDays} days ago. + * Used by the follow-up notification scheduler. + */ + List findPendingFollowUps(List formIds, int delayDays); + + /** Returns beneficiary IDs with COMPLETE status for the given form type, optionally filtered by village and/or provider service map. */ + List getCompletedBeneficiaries(FormType formType, Integer villageId, Integer providerServiceMapId); +} diff --git a/src/main/java/com/iemr/flw/service/EmployeeMasterInter.java b/src/main/java/com/iemr/flw/service/EmployeeMasterInter.java index 1c4369da..4e81445c 100644 --- a/src/main/java/com/iemr/flw/service/EmployeeMasterInter.java +++ b/src/main/java/com/iemr/flw/service/EmployeeMasterInter.java @@ -1,13 +1,13 @@ package com.iemr.flw.service; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; import org.springframework.stereotype.Service; import java.util.List; @Service public interface EmployeeMasterInter { - public M_User getUserDetails(Integer userID); + public User getUserDetails(Integer userID); - List getAllUsers(); + List getAllUsers(); } diff --git a/src/main/java/com/iemr/flw/service/IFAFormSubmissionService.java b/src/main/java/com/iemr/flw/service/IFAFormSubmissionService.java index 1ecd338d..d94fbd68 100644 --- a/src/main/java/com/iemr/flw/service/IFAFormSubmissionService.java +++ b/src/main/java/com/iemr/flw/service/IFAFormSubmissionService.java @@ -9,6 +9,6 @@ import java.util.List; @Service public interface IFAFormSubmissionService { - String saveFormData(List requests); + String saveFormData(List requests,Integer userId); List getFormData(GetBenRequestHandler getBenRequestHandler); } diff --git a/src/main/java/com/iemr/flw/service/IRSRoundService.java b/src/main/java/com/iemr/flw/service/IRSRoundService.java index d45cd621..438702d5 100644 --- a/src/main/java/com/iemr/flw/service/IRSRoundService.java +++ b/src/main/java/com/iemr/flw/service/IRSRoundService.java @@ -8,7 +8,7 @@ @Service public interface IRSRoundService { - List addRounds(List dtos); + List addRounds(List dtos,Integer userId,String userName); List getRounds(Long householdId); } diff --git a/src/main/java/com/iemr/flw/service/IncentiveLogicService.java b/src/main/java/com/iemr/flw/service/IncentiveLogicService.java new file mode 100644 index 00000000..8becce19 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/IncentiveLogicService.java @@ -0,0 +1,35 @@ +package com.iemr.flw.service; + +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.util.Date; + +public interface IncentiveLogicService { + public IncentiveActivityRecord incentiveForLeprosyPaucibacillaryConfirmed(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + public IncentiveActivityRecord incentiveForIdentificationLeprosy(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + public IncentiveActivityRecord incentiveForLeprosyMultibacillaryConfirmed(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + + public IncentiveActivityRecord incentiveForVhndMeeting(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + + public IncentiveActivityRecord incentiveForClusterMeeting(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + public IncentiveActivityRecord incentiveForAttendingVhsnc(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForChildBirthGap(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForSecondChildGap(Long benId, Timestamp secondChildDob, Timestamp secondChildDob1, Integer userId); + + IncentiveActivityRecord incentiveForEyeSurgeyReferGovtHospital(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + IncentiveActivityRecord incentiveForEyeSurgeyReferPrivateHospital(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForMalariaFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForTbFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForTbFollowUpIsDrTb(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForGiveingIFA(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); + + IncentiveActivityRecord incentiveForTbSuspected(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId); +} diff --git a/src/main/java/com/iemr/flw/service/IncentiveService.java b/src/main/java/com/iemr/flw/service/IncentiveService.java index ab49a0cd..8b2e4600 100644 --- a/src/main/java/com/iemr/flw/service/IncentiveService.java +++ b/src/main/java/com/iemr/flw/service/IncentiveService.java @@ -3,6 +3,7 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.IncentiveActivityDTO; import com.iemr.flw.dto.iemr.IncentiveRequestDTO; +import com.iemr.flw.dto.iemr.PendingActivityDTO; import java.util.List; @@ -13,4 +14,12 @@ public interface IncentiveService { String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO); String getAllIncentivesByUserId(GetBenRequestHandler requestDTO); -} + String getAllIncentivesGroupedSummary(GetBenRequestHandler requestDTO); + String getAllIncentivesGroupedActivity(GetBenRequestHandler requestDTO); + + String updateIncentive(PendingActivityDTO pendingActivityDTO); + public String updateClaimStatus(Integer ashaId, + Integer month, + Integer year, + Boolean isClaimed, + String token);} diff --git a/src/main/java/com/iemr/flw/service/MaaMeetingService.java b/src/main/java/com/iemr/flw/service/MaaMeetingService.java index d5f4c5bd..cfe6aa20 100644 --- a/src/main/java/com/iemr/flw/service/MaaMeetingService.java +++ b/src/main/java/com/iemr/flw/service/MaaMeetingService.java @@ -3,28 +3,20 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import com.iemr.flw.domain.iemr.IncentiveActivity; -import com.iemr.flw.domain.iemr.IncentiveActivityRecord; -import com.iemr.flw.domain.iemr.MaaMeeting; -import com.iemr.flw.domain.iemr.UwinSession; +import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.MaaMeetingRequestDTO; import com.iemr.flw.dto.iemr.MaaMeetingResponseDTO; import com.iemr.flw.masterEnum.GroupName; -import com.iemr.flw.repo.iemr.IncentiveRecordRepo; -import com.iemr.flw.repo.iemr.IncentivesRepo; -import com.iemr.flw.repo.iemr.MaaMeetingRepository; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import com.iemr.flw.repo.iemr.*; +import jakarta.persistence.EntityNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; @Service @@ -40,6 +32,9 @@ public class MaaMeetingService { private final MaaMeetingRepository repository; private final ObjectMapper objectMapper; + @Autowired + private IncentivePendingActivityRepository incentivePendingActivityRepository; + public MaaMeetingService(MaaMeetingRepository repository, ObjectMapper objectMapper) { this.repository = repository; this.objectMapper = objectMapper; @@ -51,6 +46,11 @@ public MaaMeeting saveMeeting(MaaMeetingRequestDTO req) throws Exception { meeting.setPlace(req.getPlace()); meeting.setParticipants(req.getParticipants()); meeting.setAshaId(req.getAshaId()); + meeting.setNoOfLactingMother(req.getNoOfLactingMother()); + meeting.setNoOfPragnentWomen(req.getNoOfPragnentWomen()); + meeting.setVillageName(req.getVillageName()); + meeting.setMitaninActivityCheckList(req.getMitaninActivityCheckList()); + meeting.setCreatedBy(req.getCreatedBY()); // Convert meeting images to Base64 JSON @@ -69,12 +69,93 @@ public MaaMeeting saveMeeting(MaaMeetingRequestDTO req) throws Exception { String imagesJson = objectMapper.writeValueAsString(base64Images); meeting.setMeetingImagesJson(imagesJson); } + checkAndAddIncentive(meeting); return repository.save(meeting); } + public MaaMeeting updateMeeting(MaaMeetingRequestDTO req) throws JsonProcessingException { + MaaMeeting existingMeeting = repository.findById(req.getId()) + .orElseThrow(() -> new EntityNotFoundException("Meeting not found: " + req.getId())); + + // ✅ NULL CHECK + if (req.getMeetingDate() != null) { + existingMeeting.setMeetingDate(req.getMeetingDate()); + } + if (req.getPlace() != null) { + existingMeeting.setPlace(req.getPlace()); + } + if (req.getParticipants() != null) { + existingMeeting.setParticipants(req.getParticipants()); + } + if (req.getAshaId() != null) { + existingMeeting.setAshaId(req.getAshaId()); + } + if (req.getCreatedBY() != null) { // ✅ Typo fixed: CreatedBY → CreatedBy + existingMeeting.setCreatedBy(req.getCreatedBY()); + } + + // Images - only if provided + if (req.getMeetingImages() != null && req.getMeetingImages().length > 0) { + List base64Images = Arrays.stream(req.getMeetingImages()) + .filter(file -> file != null && !file.isEmpty()) + .map(this::convertToBase64) + .collect(Collectors.toList()); + existingMeeting.setMeetingImagesJson(objectMapper.writeValueAsString(base64Images)); + } + + checkAndAddIncentive(existingMeeting); + + return repository.save(existingMeeting); + } + + public MaaMeeting updateMeetingFromFileUpload(MaaMeetingRequestDTO req, Long incentiveRecordId) throws JsonProcessingException { + MaaMeeting existingMeeting = repository.findById(req.getId()) + .orElseThrow(() -> new EntityNotFoundException("Meeting not found: " + req.getId())); + + // ✅ NULL CHECK + if (req.getMeetingDate() != null) { + existingMeeting.setMeetingDate(req.getMeetingDate()); + } + if (req.getPlace() != null) { + existingMeeting.setPlace(req.getPlace()); + } + if (req.getParticipants() != null) { + existingMeeting.setParticipants(req.getParticipants()); + } + if (req.getAshaId() != null) { + existingMeeting.setAshaId(req.getAshaId()); + } + if (req.getCreatedBY() != null) { // ✅ Typo fixed: CreatedBY → CreatedBy + existingMeeting.setCreatedBy(req.getCreatedBY()); + } + + // Images - only if provided + if (req.getMeetingImages() != null && req.getMeetingImages().length > 0) { + List base64Images = Arrays.stream(req.getMeetingImages()) + .filter(file -> file != null && !file.isEmpty()) + .map(this::convertToBase64) + .collect(Collectors.toList()); + existingMeeting.setMeetingImagesJson(objectMapper.writeValueAsString(base64Images)); + } + + if (existingMeeting.getMeetingImagesJson() != null) { + checkAndUpdateIncentive(incentiveRecordId); + + } + return repository.save(existingMeeting); + } + + + private String convertToBase64(MultipartFile file) { + try { + return Base64.getEncoder().encodeToString(file.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Failed to convert image to Base64: " + file.getOriginalFilename(), e); + } + } public List getAllMeetings(GetBenRequestHandler getBenRequestHandler) throws Exception { @@ -87,13 +168,18 @@ public List getAllMeetings(GetBenRequestHandler getBenReq dto.setPlace(meeting.getPlace()); dto.setParticipants(meeting.getParticipants()); dto.setAshaId(meeting.getAshaId()); + dto.setVillageName(meeting.getVillageName()); + dto.setNoOfLactingMother(String.valueOf(meeting.getNoOfLactingMother())); + dto.setNoOfPragnentWomen(String.valueOf(meeting.getNoOfPragnentWomen())); + dto.setMitaninActivityCheckList(meeting.getMitaninActivityCheckList()); dto.setCreatedBy(meeting.getCreatedBy()); try { if (meeting.getMeetingImagesJson() != null) { List base64Images = objectMapper.readValue( meeting.getMeetingImagesJson(), - new TypeReference>() {} + new TypeReference>() { + } ); dto.setMeetingImages(base64Images); @@ -107,22 +193,39 @@ public List getAllMeetings(GetBenRequestHandler getBenReq return dto; }).collect(Collectors.toList()); } + + private void updatePendingActivity(Integer userId, Long recordId, Long activityId, Long mIncentiveId) { + IncentivePendingActivity incentivePendingActivity = new IncentivePendingActivity(); + incentivePendingActivity.setActivityId(activityId); + incentivePendingActivity.setRecordId(recordId); + incentivePendingActivity.setUserId(userId); + incentivePendingActivity.setMincentiveId(mIncentiveId); + if (incentivePendingActivity != null) { + incentivePendingActivityRepository.save(incentivePendingActivity); + } + + } + + private void checkAndUpdateIncentive(Long incentiveId) { + updateIncentive(incentiveId); + } + private void checkAndAddIncentive(MaaMeeting meeting) { IncentiveActivity incentiveActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MAA_QUARTERLY_MEETING", GroupName.CHILD_HEALTH.getDisplayName()); IncentiveActivity incentiveActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("MAA_QUARTERLY_MEETING", GroupName.ACTIVITY.getDisplayName()); - if(incentiveActivityAM!=null){ - addIncentive(incentiveActivityAM,meeting); - } - if(incentiveActivityCH!=null){ - addIncentive(incentiveActivityCH,meeting); + if (incentiveActivityAM != null) { + addIncentive(incentiveActivityAM, meeting); + } + if (incentiveActivityCH != null) { + addIncentive(incentiveActivityCH, meeting); - } + } } - private void addIncentive(IncentiveActivity incentiveActivity,MaaMeeting meeting){ + private void addIncentive(IncentiveActivity incentiveActivity, MaaMeeting meeting) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), Timestamp.valueOf(meeting.getMeetingDate().atStartOfDay()), 0L,meeting.getAshaId()); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), Timestamp.valueOf(meeting.getMeetingDate().atStartOfDay()), 0L, meeting.getAshaId()); if (record == null) { record = new IncentiveActivityRecord(); @@ -136,9 +239,37 @@ record = new IncentiveActivityRecord(); record.setBenId(0L); record.setAshaId(meeting.getAshaId()); record.setAmount(Long.valueOf(incentiveActivity.getRate())); + record.setIsEligible(true); recordRepo.save(record); + + +// if (meeting.getMeetingImagesJson() != null) { +// record.setIsEligible(true); +// recordRepo.save(record); +// +// } else { +// record.setIsEligible(false); +// IncentiveActivityRecord activityRecord = recordRepo.save(record); +// if (activityRecord != null) { +// updatePendingActivity(meeting.getAshaId(), meeting.getId(), activityRecord.getId(), incentiveActivity.getId()); +// +// } +// +// } } } + private void updateIncentive(Long id) { + + Optional optionalRecord = recordRepo.findById(id); + + if (optionalRecord.isPresent()) { + IncentiveActivityRecord record = optionalRecord.get(); + record.setIsEligible(true); + recordRepo.save(record); + } + } + + } diff --git a/src/main/java/com/iemr/flw/service/MalariaFollowUpService.java b/src/main/java/com/iemr/flw/service/MalariaFollowUpService.java index eb979318..324c6cd6 100644 --- a/src/main/java/com/iemr/flw/service/MalariaFollowUpService.java +++ b/src/main/java/com/iemr/flw/service/MalariaFollowUpService.java @@ -9,7 +9,7 @@ public interface MalariaFollowUpService { - public Boolean saveFollowUp(MalariaFollowUpDTO dto) ; + public Boolean saveFollowUp(MalariaFollowUpDTO dto,String token) ; List getByUserId(Integer userId); diff --git a/src/main/java/com/iemr/flw/service/MaternalHealthService.java b/src/main/java/com/iemr/flw/service/MaternalHealthService.java index c4af2768..5e4e9b61 100644 --- a/src/main/java/com/iemr/flw/service/MaternalHealthService.java +++ b/src/main/java/com/iemr/flw/service/MaternalHealthService.java @@ -2,6 +2,7 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.utils.exception.IEMRException; import org.springframework.stereotype.Component; import java.util.List; @@ -15,7 +16,7 @@ public interface MaternalHealthService { List getANCVisits(GetBenRequestHandler dto); - String saveANCVisit(List ancVisitDTOs); + String saveANCVisit(List ancVisitDTOs,Integer useId ); List getPmsmaRecords(GetBenRequestHandler dto); @@ -25,4 +26,7 @@ public interface MaternalHealthService { String savePNCVisit(List pncVisitDTOs); + String saveANCVisitQuestions(List ancVisitQuestionsDTOS, String authorization) throws IEMRException; + + List getANCCounselling(GetBenRequestHandler requestDTO); } diff --git a/src/main/java/com/iemr/flw/service/StopTBService.java b/src/main/java/com/iemr/flw/service/StopTBService.java new file mode 100644 index 00000000..e549daa6 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/StopTBService.java @@ -0,0 +1,22 @@ +package com.iemr.flw.service; + +import java.util.List; +import java.util.Map; + +public interface StopTBService { + // Nurse — General Examination + List> saveGeneralExamination(List> dataList) throws Exception; + Map getAllGeneralExaminations(Integer providerServiceMapID, Integer villageID) throws Exception; + + // Nurse — TB Screening + List> saveNurseTBScreening(List> dataList) throws Exception; + Map getAllNurseTBScreenings(Integer providerServiceMapID, Integer villageID) throws Exception; + + // Nurse — General OPD + List> saveGeneralOpd(List> dataList) throws Exception; + Map getAllGeneralOpd(Integer providerServiceMapID, Integer villageID) throws Exception; + + // Nurse — Diagnostics + List> saveDiagnostics(List> dataList) throws Exception; + Map getAllDiagnostics(Integer providerServiceMapID, Integer villageID) throws Exception; +} diff --git a/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java b/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java new file mode 100644 index 00000000..bc580a26 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/SupervisorDashboardService.java @@ -0,0 +1,20 @@ +package com.iemr.flw.service; + +import java.util.List; +import java.util.Map; + +public interface SupervisorDashboardService { + + String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year); + + Map getAshasAtFacility(Integer supervisorId, Integer facilityId, Integer month, Integer year, Integer approvalStatusID); + + public int updateApprovalStatus(Integer ashaId, + Integer month, + Integer year, + Integer approvalStatus, + String incentiveIds, + String reason, + String otherReason, + String token); +} diff --git a/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java new file mode 100644 index 00000000..6471f799 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/TBConfirmedCaseService.java @@ -0,0 +1,18 @@ +package com.iemr.flw.service; + +import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public interface TBConfirmedCaseService { + + String save(List tbConfirmedCaseDTO, String token) throws Exception; + + String getByBenId(Long benId, String authorisation) throws Exception; + + String getByUserId(String authorisation) throws Exception; + + String getByProviderServiceMapId(Integer providerServiceMapID, Integer villageID) throws Exception; +} diff --git a/src/main/java/com/iemr/flw/service/TBStopVisitService.java b/src/main/java/com/iemr/flw/service/TBStopVisitService.java new file mode 100644 index 00000000..0e15fd9b --- /dev/null +++ b/src/main/java/com/iemr/flw/service/TBStopVisitService.java @@ -0,0 +1,9 @@ +package com.iemr.flw.service; + +import com.iemr.flw.domain.iemr.BenVisitDetail; + +public interface TBStopVisitService { + + BenVisitDetail getOrCreateVisitForToday(Long beneficiaryRegID, Integer providerServiceMapID, + String createdBy, Integer vanID, Integer parkingPlaceID); +} diff --git a/src/main/java/com/iemr/flw/service/UwinSessionService.java b/src/main/java/com/iemr/flw/service/UwinSessionService.java index 3f6ddf0a..ce4185c3 100644 --- a/src/main/java/com/iemr/flw/service/UwinSessionService.java +++ b/src/main/java/com/iemr/flw/service/UwinSessionService.java @@ -1,5 +1,6 @@ package com.iemr.flw.service; +import com.iemr.flw.domain.iemr.UwinSession; import com.iemr.flw.dto.iemr.UwinSessionRequestDTO; import com.iemr.flw.dto.iemr.UwinSessionResponseDTO; @@ -7,5 +8,6 @@ public interface UwinSessionService { UwinSessionResponseDTO saveSession(UwinSessionRequestDTO req) throws Exception; + UwinSession updateSession(UwinSessionRequestDTO req, Long recordId,Long activityId) throws Exception; List getSessionsByAsha(Integer ashaId) throws Exception; } diff --git a/src/main/java/com/iemr/flw/service/health/HealthService.java b/src/main/java/com/iemr/flw/service/health/HealthService.java new file mode 100644 index 00000000..084ffe5e --- /dev/null +++ b/src/main/java/com/iemr/flw/service/health/HealthService.java @@ -0,0 +1,517 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ + +package com.iemr.flw.service.health; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.time.Instant; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; +import jakarta.annotation.PreDestroy; +import javax.sql.DataSource; +import com.zaxxer.hikari.HikariDataSource; +import com.zaxxer.hikari.HikariPoolMXBean; +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +@Service +public class HealthService { + + private static final Logger logger = LoggerFactory.getLogger(HealthService.class); + + private static final String STATUS_KEY = "status"; + private static final String STATUS_UP = "UP"; + private static final String STATUS_DOWN = "DOWN"; + private static final String STATUS_DEGRADED = "DEGRADED"; + private static final String SEVERITY_KEY = "severity"; + private static final String SEVERITY_OK = "OK"; + private static final String SEVERITY_WARNING = "WARNING"; + private static final String SEVERITY_CRITICAL = "CRITICAL"; + private static final String ERROR_KEY = "error"; + private static final String MESSAGE_KEY = "message"; + private static final String RESPONSE_TIME_KEY = "responseTimeMs"; + private static final long MYSQL_TIMEOUT_SECONDS = 3; + private static final long REDIS_TIMEOUT_SECONDS = 3; + + private static final long ADVANCED_CHECKS_THROTTLE_SECONDS = 30; + private static final long RESPONSE_TIME_THRESHOLD_MS = 2000; + + private static final String DIAGNOSTIC_LOCK_WAIT = "MYSQL_LOCK_WAIT"; + private static final String DIAGNOSTIC_SLOW_QUERIES = "MYSQL_SLOW_QUERIES"; + private static final String DIAGNOSTIC_POOL_EXHAUSTED = "MYSQL_POOL_EXHAUSTED"; + private static final String DIAGNOSTIC_LOG_TEMPLATE = "Diagnostic: {}"; + + private final DataSource dataSource; + private final RedisTemplate redisTemplate; + private final ExecutorService executorService; + + private volatile long lastAdvancedCheckTime = 0; + private volatile AdvancedCheckResult cachedAdvancedCheckResult = null; + private final ReentrantReadWriteLock advancedCheckLock = new ReentrantReadWriteLock(); + private final AtomicBoolean advancedCheckInProgress = new AtomicBoolean(false); + + private static final boolean ADVANCED_HEALTH_CHECKS_ENABLED = true; + + public HealthService(DataSource dataSource, + @Autowired(required = false) RedisTemplate redisTemplate) { + this.dataSource = dataSource; + this.redisTemplate = redisTemplate; + this.executorService = Executors.newFixedThreadPool(6); + } + + @PreDestroy + public void shutdown() { + if (executorService != null && !executorService.isShutdown()) { + try { + executorService.shutdown(); + if (!executorService.awaitTermination(5, TimeUnit.SECONDS)) { + executorService.shutdownNow(); + logger.warn("ExecutorService did not terminate gracefully"); + } + } catch (InterruptedException e) { + executorService.shutdownNow(); + Thread.currentThread().interrupt(); + logger.warn("ExecutorService shutdown interrupted", e); + } + } + } + + public Map checkHealth() { + Map response = new LinkedHashMap<>(); + response.put("timestamp", Instant.now().toString()); + + Map mysqlStatus = new ConcurrentHashMap<>(); + Map redisStatus = new ConcurrentHashMap<>(); + + if (!executorService.isShutdown()) { + performHealthChecks(mysqlStatus, redisStatus); + } + + ensurePopulated(mysqlStatus, "MySQL"); + ensurePopulated(redisStatus, "Redis"); + + Map> components = new LinkedHashMap<>(); + components.put("mysql", mysqlStatus); + components.put("redis", redisStatus); + + response.put("components", components); + response.put(STATUS_KEY, computeOverallStatus(components)); + + return response; + } + + private void performHealthChecks(Map mysqlStatus, Map redisStatus) { + Future mysqlFuture = null; + Future redisFuture = null; + try { + mysqlFuture = executorService.submit( + () -> performHealthCheck("MySQL", mysqlStatus, this::checkMySQLHealthSync)); + redisFuture = executorService.submit( + () -> performHealthCheck("Redis", redisStatus, this::checkRedisHealthSync)); + + awaitHealthChecks(mysqlFuture, redisFuture); + } catch (TimeoutException e) { + logger.warn("Health check aggregate timeout after {} seconds", getMaxTimeout()); + cancelFutures(mysqlFuture, redisFuture); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + logger.warn("Health check was interrupted"); + cancelFutures(mysqlFuture, redisFuture); + } catch (Exception e) { + logger.warn("Health check execution error: {}", e.getMessage()); + cancelFutures(mysqlFuture, redisFuture); + } + } + + private void awaitHealthChecks(Future mysqlFuture, Future redisFuture) throws TimeoutException, InterruptedException, ExecutionException { + long maxTimeout = getMaxTimeout(); + long deadlineNs = System.nanoTime() + TimeUnit.SECONDS.toNanos(maxTimeout); + + mysqlFuture.get(maxTimeout, TimeUnit.SECONDS); + long remainingNs = deadlineNs - System.nanoTime(); + + if (remainingNs > 0) { + redisFuture.get(remainingNs, TimeUnit.NANOSECONDS); + } else { + redisFuture.cancel(true); + } + } + + private long getMaxTimeout() { + return Math.max(MYSQL_TIMEOUT_SECONDS, REDIS_TIMEOUT_SECONDS) + 1; + } + + private void cancelFutures(Future mysqlFuture, Future redisFuture) { + if (mysqlFuture != null) mysqlFuture.cancel(true); + if (redisFuture != null) redisFuture.cancel(true); + } + + private void ensurePopulated(Map status, String componentName) { + if (!status.containsKey(STATUS_KEY)) { + status.put(STATUS_KEY, STATUS_DOWN); + status.put(SEVERITY_KEY, SEVERITY_CRITICAL); + status.put(ERROR_KEY, componentName + " health check did not complete in time"); + } + } + + private HealthCheckResult checkMySQLHealthSync() { + try (Connection connection = dataSource.getConnection(); + PreparedStatement stmt = connection.prepareStatement("SELECT 1 as health_check")) { + + stmt.setQueryTimeout((int) MYSQL_TIMEOUT_SECONDS); + + try (ResultSet rs = stmt.executeQuery()) { + if (!rs.next()) { + return new HealthCheckResult(false, "No result from health check query", false); + } + } + } catch (Exception e) { + logger.warn("MySQL health check failed: {}", e.getMessage(), e); + return new HealthCheckResult(false, "MySQL connection failed", false); + } + boolean isDegraded = performAdvancedMySQLChecksWithThrottle(); + return new HealthCheckResult(true, null, isDegraded); + } + + private HealthCheckResult checkRedisHealthSync() { + if (redisTemplate == null) { + return new HealthCheckResult(true, "Redis not configured — skipped", false); + } + + try { + String pong = redisTemplate.execute((org.springframework.data.redis.core.RedisCallback) (connection) -> connection.ping()); + + if ("PONG".equals(pong)) { + return new HealthCheckResult(true, null, false); + } + + return new HealthCheckResult(false, "Redis PING failed", false); + + } catch (Exception e) { + logger.warn("Redis health check failed: {}", e.getMessage(), e); + return new HealthCheckResult(false, "Redis connection failed", false); + } + } + + private Map performHealthCheck(String componentName, + Map status, + Supplier checker) { + long startTime = System.currentTimeMillis(); + + try { + HealthCheckResult result = checker.get(); + long responseTime = System.currentTimeMillis() - startTime; + + String componentStatus; + if (!result.isHealthy) { + componentStatus = STATUS_DOWN; + } else if (result.isDegraded) { + componentStatus = STATUS_DEGRADED; + } else { + componentStatus = STATUS_UP; + } + status.put(STATUS_KEY, componentStatus); + + status.put(RESPONSE_TIME_KEY, responseTime); + + String severity = determineSeverity(result.isHealthy, responseTime, result.isDegraded); + status.put(SEVERITY_KEY, severity); + + if (result.error != null) { + String fieldKey = result.isHealthy ? MESSAGE_KEY : ERROR_KEY; + status.put(fieldKey, result.error); + } + + return status; + + } catch (Exception e) { + long responseTime = System.currentTimeMillis() - startTime; + logger.error("{} health check failed with exception: {}", componentName, e.getMessage(), e); + + status.put(STATUS_KEY, STATUS_DOWN); + status.put(RESPONSE_TIME_KEY, responseTime); + status.put(SEVERITY_KEY, SEVERITY_CRITICAL); + status.put(ERROR_KEY, "Health check failed with an unexpected error"); + + return status; + } + } + + private String determineSeverity(boolean isHealthy, long responseTimeMs, boolean isDegraded) { + if (!isHealthy) { + return SEVERITY_CRITICAL; + } + + if (isDegraded) { + return SEVERITY_WARNING; + } + + if (responseTimeMs > RESPONSE_TIME_THRESHOLD_MS) { + return SEVERITY_WARNING; + } + + return SEVERITY_OK; + } + + private String computeOverallStatus(Map> components) { + boolean hasCritical = false; + boolean hasDegraded = false; + + for (Map componentStatus : components.values()) { + String status = (String) componentStatus.get(STATUS_KEY); + String severity = (String) componentStatus.get(SEVERITY_KEY); + + if (STATUS_DOWN.equals(status) || SEVERITY_CRITICAL.equals(severity)) { + hasCritical = true; + } + + if (STATUS_DEGRADED.equals(status)) { + hasDegraded = true; + } + + if (SEVERITY_WARNING.equals(severity)) { + hasDegraded = true; + } + } + + if (hasCritical) { + return STATUS_DOWN; + } + + if (hasDegraded) { + return STATUS_DEGRADED; + } + + return STATUS_UP; + } + + private boolean performAdvancedMySQLChecksWithThrottle() { + if (!ADVANCED_HEALTH_CHECKS_ENABLED) { + return false; + } + + long currentTime = System.currentTimeMillis(); + + advancedCheckLock.readLock().lock(); + try { + if (cachedAdvancedCheckResult != null && + (currentTime - lastAdvancedCheckTime) < ADVANCED_CHECKS_THROTTLE_SECONDS * 1000) { + return cachedAdvancedCheckResult.isDegraded; + } + } finally { + advancedCheckLock.readLock().unlock(); + } + + // Only one thread may submit; others fall back to the (stale) cache + if (!advancedCheckInProgress.compareAndSet(false, true)) { + advancedCheckLock.readLock().lock(); + try { + return cachedAdvancedCheckResult != null && cachedAdvancedCheckResult.isDegraded; + } finally { + advancedCheckLock.readLock().unlock(); + } + } + + try { + // Perform DB I/O outside the write lock to avoid lock contention + AdvancedCheckResult result; + try (Connection connection = dataSource.getConnection()) { + result = performAdvancedMySQLChecks(connection); + } catch (Exception e) { + if (e.getCause() instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + logger.debug("Failed to get connection for advanced checks: {}", e.getMessage()); + result = new AdvancedCheckResult(false); + } + + // Re-acquire write lock only to update the cache atomically + advancedCheckLock.writeLock().lock(); + try { + lastAdvancedCheckTime = currentTime; + cachedAdvancedCheckResult = result; + return result.isDegraded; + } finally { + advancedCheckLock.writeLock().unlock(); + } + } finally { + advancedCheckInProgress.set(false); + } + } + + private AdvancedCheckResult performAdvancedMySQLChecks(Connection connection) { + try { + boolean hasIssues = false; + + if (hasLockWaits(connection)) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_LOCK_WAIT); + hasIssues = true; + } + + if (hasSlowQueries(connection)) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_SLOW_QUERIES); + hasIssues = true; + } + + if (hasConnectionPoolExhaustion()) { + logger.warn(DIAGNOSTIC_LOG_TEMPLATE, DIAGNOSTIC_POOL_EXHAUSTED); + hasIssues = true; + } + + return new AdvancedCheckResult(hasIssues); + } catch (Exception e) { + logger.debug("Advanced MySQL checks encountered exception, marking degraded"); + return new AdvancedCheckResult(true); + } + } + + private boolean hasLockWaits(Connection connection) { + try (PreparedStatement stmt = connection.prepareStatement( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST " + + "WHERE (state = 'Waiting for table metadata lock' " + + " OR state = 'Waiting for row lock' " + + " OR state = 'Waiting for lock') " + + "AND user = SUBSTRING_INDEX(USER(), '@', 1)")) { + stmt.setQueryTimeout(2); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + int lockCount = rs.getInt(1); + return lockCount > 0; + } + } + } catch (Exception e) { + logger.debug("Could not check for lock waits"); + } + return false; + } + + + private boolean hasSlowQueries(Connection connection) { + try (PreparedStatement stmt = connection.prepareStatement( + "SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST " + + "WHERE command != 'Sleep' AND time > ? AND user = SUBSTRING_INDEX(USER(), '@', 1)")) { + stmt.setQueryTimeout(2); + stmt.setInt(1, 10); + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + int slowQueryCount = rs.getInt(1); + return slowQueryCount > 3; + } + } + } catch (Exception e) { + logger.debug("Could not check for slow queries"); + } + return false; + } + + private boolean hasConnectionPoolExhaustion() { + if (dataSource instanceof HikariDataSource hikariDataSource) { + try { + HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean(); + + if (poolMXBean != null) { + int activeConnections = poolMXBean.getActiveConnections(); + int maxPoolSize = hikariDataSource.getMaximumPoolSize(); + + int threshold = (int) (maxPoolSize * 0.8); + return activeConnections > threshold; + } + } catch (Exception e) { + logger.debug("Could not retrieve HikariCP pool metrics"); + } + } + + return checkPoolMetricsViaJMX(); + } + + private boolean checkPoolMetricsViaJMX() { + try { + MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + ObjectName objectName = new ObjectName("com.zaxxer.hikari:type=Pool (*)"); + var mBeans = mBeanServer.queryMBeans(objectName, null); + + for (var mBean : mBeans) { + if (evaluatePoolMetrics(mBeanServer, mBean.getObjectName())) { + return true; + } + } + } catch (Exception e) { + logger.debug("Could not access HikariCP pool metrics via JMX"); + } + + logger.debug("Pool exhaustion check disabled: HikariCP metrics unavailable"); + return false; + } + + private boolean evaluatePoolMetrics(MBeanServer mBeanServer, ObjectName objectName) { + try { + Integer activeConnections = (Integer) mBeanServer.getAttribute(objectName, "ActiveConnections"); + Integer maximumPoolSize = (Integer) mBeanServer.getAttribute(objectName, "MaximumPoolSize"); + + if (activeConnections != null && maximumPoolSize != null) { + int threshold = (int) (maximumPoolSize * 0.8); + return activeConnections > threshold; + } + } catch (Exception e) { + // Continue to next MBean + } + return false; + } + + private static class AdvancedCheckResult { + final boolean isDegraded; + + AdvancedCheckResult(boolean isDegraded) { + this.isDegraded = isDegraded; + } + } + + private static class HealthCheckResult { + final boolean isHealthy; + final String error; + final boolean isDegraded; + + HealthCheckResult(boolean isHealthy, String error, boolean isDegraded) { + this.isHealthy = isHealthy; + this.error = error; + this.isDegraded = isDegraded; + } + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java new file mode 100644 index 00000000..f9098c39 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/AbhaBeneficiaryServiceImpl.java @@ -0,0 +1,202 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.controller.AbhaBeneficiaryController; +import com.iemr.flw.domain.iemr.AbhaApiResponse; +import com.iemr.flw.domain.identity.RMNCHMBeneficiarymapping; +import com.iemr.flw.dto.abhaBeneficiary.AbhaBeneficiaryDTO; +import com.iemr.flw.dto.iemr.AbhaRequestDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.identity.HouseHoldRepo; +import com.iemr.flw.service.AbhaBeneficiaryService; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class AbhaBeneficiaryServiceImpl implements AbhaBeneficiaryService { + + private final org.slf4j.Logger logger = LoggerFactory.getLogger(AbhaBeneficiaryService.class); + + + @Autowired + private BeneficiaryRepo beneficiaryRepo; + + + + @Value("${govthealth.user.details.url}") + private String getUserDetailsUrl; + + @Value("${govthealth.user.id}") + private String govthealthUserId; + + @Value("${govthealth.password}") + private String govthealthPassword; + + @Autowired + private HouseHoldRepo houseHoldRepo; + + @Override + public Object getBeneficiaryByAbha(AbhaRequestDTO request) { + + try { + Long benRedId = null; + BigInteger benDetailsdId = null; + String familyId =null; + if(request.getHouseHoldId()!=null){ + benRedId = beneficiaryRepo.findByHouseoldId(request.getHouseHoldId()).get(0).getBenRegId(); + if(benRedId!=null){ + List mappings = beneficiaryRepo.findByBenRegIdFromMapping(BigInteger.valueOf(benRedId)); + if (!mappings.isEmpty()) { + benDetailsdId = mappings.get(0).getBenDetailsId(); + } + + } + if(benDetailsdId!=null){ + familyId = beneficiaryRepo.findByBeneficiaryDetailsId(benDetailsdId).getFamilyId(); + + } + } + + Object[] benHealthIdNumber = beneficiaryRepo.getHealthIdNumber(request.getCardNo()); + if (benHealthIdNumber != null && benHealthIdNumber.length > 0) { + Object[] healthData = (Object[]) benHealthIdNumber[0]; + String healthIdNumber = healthData[0] != null ? healthData[0].toString() : null; + String healthId = healthData[1] != null ? healthData[1].toString() : null; + logger.info("healthIdNumber:"+healthIdNumber); + logger.info("healthId:"+healthId); + if (request.getCardNo().equals(healthIdNumber)) { + + Map response = new HashMap<>(); + response.put("statusCode", 5000); + response.put("message", + "This ABHA No already exists"); + + return response; + } + } + + AbhaApiResponse abhaApiResponse = + getAbhaResponse(request.getCardNo()).getBody(); + + if (abhaApiResponse == null || abhaApiResponse.getData() == null) { + + Map response = new HashMap<>(); + response.put("statusCode", 5001); + response.put("message", "No data found"); + + return response; + } + + + for (AbhaBeneficiaryDTO dto : abhaApiResponse.getData()) { + + // Check if ABHA already exists in system + benHealthIdNumber = beneficiaryRepo.getHealthIdNumber(dto.getAbhaId()); + if (benHealthIdNumber != null && benHealthIdNumber.length > 0) { + Object[] healthData = (Object[]) benHealthIdNumber[0]; + String healthIdNumber = healthData[0] != null ? healthData[0].toString() : null; + String healthId = healthData[1] != null ? healthData[1].toString() : null; + logger.info("healthIdNumber:"+healthIdNumber); + logger.info("healthId:"+healthId); + if (dto.getAbhaId().equals(healthIdNumber)) { + + Map response = new HashMap<>(); + response.put("statusCode", 5000); + response.put("message", + "Beneficiary is already exists"); + + return response; + } + } + if(familyId!=null){ + if(!dto.getFamilyid().toString().equals(familyId)){ + Map response = new HashMap<>(); + response.put("statusCode", 5000); + response.put("message", + "Beneficiary is not associated with this family."); + + return response; + } + } + + + + + // Split name into firstName and lastName + String personName = dto.getPersonName(); + + if (personName != null + && !personName.trim().isEmpty()) { + + String[] names = + personName.trim().split("\\s+", 2); + + dto.setFirstName(names[0]); + + if (names.length > 1) { + dto.setLastName(names[1]); + } else { + dto.setLastName(""); + } + } + } + + + logger.info("ABHA Response Status : {}", + abhaApiResponse.getStatusCode()); + + logger.info("ABHA Response : {}", + new Gson().toJson(abhaApiResponse)); + + return abhaApiResponse; + + } catch (Exception e) { + + logger.error("Error while fetching beneficiary by ABHA", e); + + Map response = new HashMap<>(); + response.put("statusCode", 5000); + response.put("message", "Internal Server Error"); + + return response; + } + } + + public ResponseEntity getAbhaResponse(String requestId) { + RestTemplate restTemplate = new RestTemplate(); + + Map body = new HashMap<>(); + body.put("userId",govthealthUserId); + body.put("password", govthealthPassword); + body.put("cardNo", requestId); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + HttpEntity request = new HttpEntity<>(body, headers); + + ResponseEntity response = restTemplate.exchange( + getUserDetailsUrl, + HttpMethod.POST, + request, + AbhaApiResponse.class + ); + + System.out.println("Status = " + response.getStatusCode()); + System.out.println("Body = " + response.getBody()); + + return response; + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/AbhaTokenServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AbhaTokenServiceImpl.java new file mode 100644 index 00000000..eef104e8 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/AbhaTokenServiceImpl.java @@ -0,0 +1,103 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.iemr.flw.service.AbhaTokenService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +@Service +public class AbhaTokenServiceImpl implements AbhaTokenService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + private static Map ABHA_TOKEN_RESPONSE; + private static Long ABHA_TOKEN_EXP; + + @Value("${abha.client.id}") + private String clientId; + + @Value("${abha.client.secret}") + private String clientSecret; + + @Value("${abha.token.url}") + private String abhaTokenUrl; + + @Value("${abha.xcmid:sbx}") + private String xCmId; + + @Override + public synchronized Map getAbhaToken() throws Exception { + try { + if (ABHA_TOKEN_RESPONSE == null || ABHA_TOKEN_EXP == null + || ABHA_TOKEN_EXP < System.currentTimeMillis()) { + generateAbhaToken(); + logger.info("ABHA token generated successfully"); + } + } catch (Exception e) { + logger.error("Error generating ABHA token: " + e.getMessage()); + throw new Exception("Failed to generate ABHA token: " + e.getMessage()); + } + return ABHA_TOKEN_RESPONSE; + } + + private void generateAbhaToken() throws Exception { + RestTemplate restTemplate = new RestTemplate(); + + Map requestBody = new HashMap<>(); + requestBody.put("clientId", clientId); + requestBody.put("clientSecret", clientSecret); + requestBody.put("grantType", "client_credentials"); + + String requestJson = new Gson().toJson(requestBody); + + MultiValueMap headers = new LinkedMultiValueMap<>(); + headers.add("Content-Type", MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8"); + headers.add("REQUEST-ID", UUID.randomUUID().toString()); + + TimeZone tz = TimeZone.getTimeZone("UTC"); + DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + df.setTimeZone(tz); + headers.add("TIMESTAMP", df.format(new Date())); + headers.add("X-CM-ID", xCmId); + + HttpEntity httpEntity = new HttpEntity<>(requestJson, headers); + ResponseEntity responseEntity = restTemplate.exchange( + abhaTokenUrl, HttpMethod.POST, httpEntity, String.class); + + String responseBody = responseEntity.getBody(); + if (responseBody != null) { + JsonObject jsonResponse = JsonParser.parseString(responseBody).getAsJsonObject(); + + Map tokenResponse = new HashMap<>(); + tokenResponse.put("accessToken", jsonResponse.get("accessToken").getAsString()); + tokenResponse.put("expiresIn", jsonResponse.get("expiresIn").getAsInt()); + tokenResponse.put("refreshExpiresIn", jsonResponse.get("refreshExpiresIn").getAsInt()); + tokenResponse.put("refreshToken", jsonResponse.get("refreshToken").getAsString()); + tokenResponse.put("tokenType", jsonResponse.get("tokenType").getAsString()); + + Integer expiresIn = jsonResponse.get("expiresIn").getAsInt(); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.SECOND, expiresIn); + ABHA_TOKEN_EXP = calendar.getTimeInMillis(); + + ABHA_TOKEN_RESPONSE = tokenResponse; + } else { + throw new Exception("Empty response from ABDM token API"); + } + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java index 43986a8c..8be992af 100644 --- a/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/AdolescentHealthServiceImpl.java @@ -126,7 +126,7 @@ private void checkAndAddIncentives(AdolescentHealth adolescentHealth) { if (sellingSanitaryActivity != null) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(sellingSanitaryActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(sellingSanitaryActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue(),adolescentHealth.getUserId()); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(sellingSanitaryActivity.getId()); @@ -151,7 +151,7 @@ record = new IncentiveActivityRecord(); if (mobilizingADHActivity != null) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(mobilizingADHActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(mobilizingADHActivity.getId(), adolescentHealth.getCreatedDate(), adolescentHealth.getBenId().longValue(),adolescentHealth.getUserId()); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(mobilizingADHActivity.getId()); diff --git a/src/main/java/com/iemr/flw/service/impl/AshaProfileImpl.java b/src/main/java/com/iemr/flw/service/impl/AshaProfileImpl.java index 29ca30da..fe7b04db 100644 --- a/src/main/java/com/iemr/flw/service/impl/AshaProfileImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/AshaProfileImpl.java @@ -1,19 +1,17 @@ package com.iemr.flw.service.impl; import com.iemr.flw.domain.iemr.AshaWorker; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; +import com.iemr.flw.dto.iemr.UserServiceRoleDTO; import com.iemr.flw.repo.iemr.AshaProfileRepo; import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.AshaProfileService; import com.iemr.flw.service.EmployeeMasterInter; import com.iemr.flw.repo.iemr.EmployeeMasterRepo; -import com.iemr.flw.service.AshaProfileService; -import com.iemr.flw.service.EmployeeMasterInter; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtAuthenticationUtil; import com.iemr.flw.utils.JwtUtil; -import com.iemr.flw.utils.exception.IEMRException; -import io.jsonwebtoken.Claims; import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,12 +20,9 @@ import java.time.LocalDate; import java.util.Objects; +import java.util.Optional; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.util.Objects; -import java.util.concurrent.TimeUnit; @Service public class AshaProfileImpl implements AshaProfileService { @@ -45,6 +40,9 @@ public class AshaProfileImpl implements AshaProfileService { JwtAuthenticationUtil jwtAuthenticationUtil; @Autowired private UserServiceRoleRepo userServiceRoleRepo; + + @Autowired + private UserService userService; private final Logger logger = LoggerFactory.getLogger(AshaProfileImpl.class); @Transactional @@ -53,16 +51,17 @@ public AshaWorker saveEditData(AshaWorker request) { try { Objects.requireNonNull(request, "ASHA worker request must not be null"); - Long id = request.getId(); + Optional ashaWorker = ashaProfileRepo.findByEmployeeId(request.getEmployeeId()); // ---------- CREATE Case ---------- - if (id == null || id == 0) { - // treat id=0 as null (frontend mistake) - if (id != null && id == 0) { - request.setId(null); - } + if (!ashaWorker.isPresent()) { + request.setId(null); - AshaWorker saved = ashaProfileRepo.save(request); + UserServiceRoleDTO userServiceRoleDTO= userService.getUserDetail(request.getEmployeeId()); + if(userServiceRoleDTO!=null){ + request.setName(userServiceRoleDTO.getName()); + } + AshaWorker saved = saveProfile(request); logger.info("Created ASHA Worker: {}", saved.getId()); return saved; } @@ -96,22 +95,15 @@ public AshaWorker getProfileData(Integer userId) { private AshaWorker getDetails(Integer userID) { try { - M_User m_user = Objects.requireNonNull(employeeMasterInter.getUserDetails(userID), "User details not found for ID: " + userID); + User m_user = Objects.requireNonNull(employeeMasterInter.getUserDetails(userID), "User details not found for ID: " + userID); AshaWorker ashaWorker = new AshaWorker(); ashaWorker.setEmployeeId(m_user.getUserID()); - // Convert DOB (Timestamp) to LocalDate - java.sql.Timestamp dobTimestamp = m_user.getDOB(); - LocalDate dob = dobTimestamp != null ? dobTimestamp.toLocalDateTime().toLocalDate() : null; - ashaWorker.setDob(dob); - // Convert DOJ (Timestamp) to LocalDate - java.sql.Timestamp dojTimestamp = m_user.getDOJ(); - LocalDate doj = dojTimestamp != null ? dojTimestamp.toLocalDateTime().toLocalDate() : LocalDate.now(); - ashaWorker.setDateOfJoining(doj); + ashaWorker.setName(String.format("%s %s", Objects.toString(m_user.getFirstName(), ""), Objects.toString(m_user.getLastName(), "")).trim()); ashaWorker.setMobileNumber(m_user.getContactNo()); ashaWorker.setAlternateMobileNumber(m_user.getEmergencyContactNo()); ashaWorker.setProviderServiceMapID(m_user.getServiceProviderID()); - ashaWorker.setProfileImage(""); + ashaWorker.setProfileImage(null); ashaWorker.setSupervisorName(""); ashaWorker.setAwwName(""); ashaWorker.setVillage(""); @@ -140,8 +132,104 @@ private AshaWorker getDetails(Integer userID) { throw new RuntimeException("Failed to create ASHA worker profile from user details", e); } } + @Transactional + public AshaWorker saveProfile(AshaWorker request) { + logger.info("Saving ASHA Profile for EmployeeId: {}", request.getEmployeeId()); + + logger.info("Received DOB: {}", request.getDob()); + logger.info("Received Date Of Joining: {}", request.getDateOfJoining()); + + AshaWorker existing = ashaProfileRepo + .findByEmployeeId(request.getEmployeeId()) + .orElse(new AshaWorker()); + + if (isValid(request.getName())) + existing.setName(request.getName()); + + if (isValid(request.getVillage())) + existing.setVillage(request.getVillage()); + + if (request.getEmployeeId() != null) + existing.setEmployeeId(request.getEmployeeId()); + + // Save even if null + existing.setDob(request.getDob()); + + if (isValid(request.getMobileNumber())) + existing.setMobileNumber(request.getMobileNumber()); + + if (isValid(request.getAlternateMobileNumber())) + existing.setAlternateMobileNumber(request.getAlternateMobileNumber()); + + if (isValid(request.getFatherOrSpouseName())) + existing.setFatherOrSpouseName(request.getFatherOrSpouseName()); + + // Save even if null + existing.setDateOfJoining(request.getDateOfJoining()); + + if (isValid(request.getBankAccount())) + existing.setBankAccount(request.getBankAccount()); + + if (isValid(request.getIfsc())) + existing.setIfsc(request.getIfsc()); + + if (request.getPopulationCovered() != null) + existing.setPopulationCovered(request.getPopulationCovered()); + + if (isValid(request.getChoName())) + existing.setChoName(request.getChoName()); + + if (isValid(request.getChoMobile())) + existing.setChoMobile(request.getChoMobile()); + + if (isValid(request.getAwwName())) + existing.setAwwName(request.getAwwName()); + + if (isValid(request.getAwwMobile())) + existing.setAwwMobile(request.getAwwMobile()); + + if (isValid(request.getAnm1Name())) + existing.setAnm1Name(request.getAnm1Name()); + + if (isValid(request.getAnm1Mobile())) + existing.setAnm1Mobile(request.getAnm1Mobile()); + + if (isValid(request.getAnm2Name())) + existing.setAnm2Name(request.getAnm2Name()); + + if (isValid(request.getAnm2Mobile())) + existing.setAnm2Mobile(request.getAnm2Mobile()); + + if (isValid(request.getAbhaNumber())) + existing.setAbhaNumber(request.getAbhaNumber()); + + if (isValid(request.getAshaHouseholdRegistration())) + existing.setAshaHouseholdRegistration(request.getAshaHouseholdRegistration()); + + if (isValid(request.getAshaFamilyMember())) + existing.setAshaFamilyMember(request.getAshaFamilyMember()); + + if (request.getProviderServiceMapID() != null) + existing.setProviderServiceMapID(request.getProviderServiceMapID()); + + if (request.getProfileImage() != null && request.getProfileImage().length > 0) + existing.setProfileImage(request.getProfileImage()); + + if (request.getIsFatherOrSpouse() != null) + existing.setIsFatherOrSpouse(request.getIsFatherOrSpouse()); + + if (isValid(request.getSupervisorName())) + existing.setSupervisorName(request.getSupervisorName()); + + if (isValid(request.getSupervisorMobile())) + existing.setSupervisorMobile(request.getSupervisorMobile()); + + return ashaProfileRepo.save(existing); + } + - public AshaWorker updateProfile(AshaWorker request) { + + public AshaWorker updateProfile(AshaWorker request) { AshaWorker existing = ashaProfileRepo.findByEmployeeId(request.getEmployeeId()).orElseThrow(() -> new RuntimeException("ASHA worker not found")); if (isValid(request.getAbhaNumber())) existing.setAbhaNumber(request.getAbhaNumber()); if (request.getEmployeeId() != null) existing.setEmployeeId(request.getEmployeeId()); @@ -169,16 +257,20 @@ public AshaWorker updateProfile(AshaWorker request) { if (isValid(request.getAwwMobile())) existing.setAwwMobile(request.getAwwMobile()); if (request.getProviderServiceMapID() != null) existing.setProviderServiceMapID(request.getProviderServiceMapID()); - if (isValid(request.getProfileImage())) existing.setProfileImage(request.getProfileImage()); + if (isValidImage(request.getProfileImage())) existing.setProfileImage(request.getProfileImage()); if (request.getIsFatherOrSpouse() != null) existing.setIsFatherOrSpouse(request.getIsFatherOrSpouse()); if (isValid(request.getSupervisorName())) existing.setSupervisorName(request.getSupervisorName()); if (isValid(request.getSupervisorMobile())) existing.setSupervisorMobile(request.getSupervisorMobile()); - return existing; + return ashaProfileRepo.save(existing); } private boolean isValid(String value) { return value != null && !value.trim().isEmpty() && !"null".equalsIgnoreCase(value.trim()); } + private boolean isValidImage(byte[] value) { + return value != null && value.length > 0; + } + } diff --git a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java index 510d4b53..b70ce80e 100644 --- a/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/BeneficiaryServiceImpl.java @@ -1,24 +1,31 @@ package com.iemr.flw.service.impl; +import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Date; +import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.Period; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.iemr.flw.domain.iemr.EyeCheckupVisit; import com.iemr.flw.domain.iemr.IncentiveActivity; import com.iemr.flw.dto.iemr.EyeCheckupListDTO; import com.iemr.flw.dto.iemr.EyeCheckupRequestDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.domain.iemr.BenFlowStatus; import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,11 +56,16 @@ import com.iemr.flw.domain.identity.RMNCHMBeneficiarymapping; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.mapper.InputMapper; +import com.iemr.flw.domain.iemr.BenAnthropometryDetail; +import com.iemr.flw.domain.iemr.BenPhysicalVitalDetail; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.identity.HouseHoldRepo; +import com.iemr.flw.repo.iemr.BenAnthropometryRepo; +import com.iemr.flw.repo.iemr.BenPhysicalVitalRepo; import com.iemr.flw.service.BeneficiaryService; import com.iemr.flw.utils.config.ConfigProperties; import com.iemr.flw.utils.http.HttpUtils; +import org.springframework.transaction.annotation.Transactional; @Service @Qualifier("rmnchServiceImpl") @@ -89,57 +101,115 @@ public class BeneficiaryServiceImpl implements BeneficiaryService { @Autowired private JwtUtil jwtUtil; + @Autowired + private UserService userService; + + @Autowired + private IncentiveLogicService incentiveLogicService; + + @Autowired + private BenFlowStatusRepo benFlowStatusRepo; + @Autowired private UserServiceRoleRepo userRepo; - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + @Autowired + private BenAnthropometryRepo benAnthropometryRepo; + @Autowired + private BenPhysicalVitalRepo benPhysicalVitalRepo; + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); @Override public String getBenData(GetBenRequestHandler request, String authorisation) throws Exception { - String outputResponse = null; - int totalPage = 0; - try { - if (request != null && request.getAshaId() != null) { - List resultSet; - Integer pageSize = Integer.valueOf(door_to_door_page_size); - if (request.getPageNo() != null) { - String userName = beneficiaryRepo.getUserName(request.getAshaId()); - if (userName == null || userName.isEmpty()) - throw new Exception("Asha details not found, please contact administrator"); - - request.setUserName(userName); - - PageRequest pr = PageRequest.of(request.getPageNo(), pageSize); - if (request.getFromDate() != null && request.getToDate() != null) { - Page p = beneficiaryRepo.getBenDataWithinDates( - request.getUserName(), request.getFromDate(), request.getToDate(), pr); - resultSet = p.getContent(); - totalPage = p.getTotalPages(); - } else { - Page p = beneficiaryRepo.getBenDataByUser(request.getUserName(), - pr); - resultSet = p.getContent(); - totalPage = p.getTotalPages(); - } - if (resultSet != null && resultSet.size() > 0) { - outputResponse = getMappingsForAddressIDs(resultSet, totalPage, authorisation); - } - } else { - // page no not invalid - throw new Exception("Invalid page no"); - } - } else - throw new Exception("Invalid/missing village details"); - } catch (Exception e) { - throw new Exception(e.getMessage()); + if (request == null) { + throw new Exception("Invalid request"); + } + + if (request.getPageNo() == null || request.getPageNo() < 0) { + throw new Exception("Invalid page number"); + } + + int pageSize = Integer.parseInt(door_to_door_page_size); + + // Stop TB path: filter by providerServiceMapID + villageID + if (request.getProviderServiceMapID() != null && request.getVillageID() != null) { + List flows = benFlowStatusRepo.getRegistrarWorklist( + request.getProviderServiceMapID(), request.getVillageID()); + + if (flows == null || flows.isEmpty()) return null; + + List allAddresses = new ArrayList<>(); + for (BenFlowStatus flow : flows) { + if (flow.getBeneficiaryRegID() == null) continue; + List mappings = beneficiaryRepo.findByBenRegIdFromMapping( + BigInteger.valueOf(flow.getBeneficiaryRegID())); + if (mappings.isEmpty()) continue; + RMNCHMBeneficiarymapping mapping = mappings.get(0); + if (mapping.getBenAddressId() == null) continue; + RMNCHMBeneficiaryaddress address = beneficiaryRepo.getAddressById(mapping.getBenAddressId()); + if (address != null) allAddresses.add(address); + } + + if (allAddresses.isEmpty()) return null; + + int totalPage = (int) Math.ceil((double) allAddresses.size() / pageSize); + int start = request.getPageNo() * pageSize; + int end = Math.min(start + pageSize, allAddresses.size()); + if (start >= allAddresses.size()) return null; + + return getMappingsForAddressIDs(allAddresses.subList(start, end), totalPage, authorisation); + } + + // Normal FLW/ASHA path + if (request.getAshaId() == null) { + throw new Exception("Invalid/missing asha details"); + } + + String userName = beneficiaryRepo.getUserName(request.getAshaId()); + + if (userName == null || userName.isEmpty()) { + throw new Exception("Asha details not found, please contact administrator"); } - return outputResponse; + request.setUserName(userName); + + PageRequest pageRequest = PageRequest.of(request.getPageNo(), pageSize); + + Page pageResult; + + if (request.getFromDate() != null && request.getToDate() != null) { + + if (request.getFromDate().after(request.getToDate())) { + throw new Exception("Invalid date range"); + } + + pageResult = beneficiaryRepo.getBenDataWithinDates( + userName, + request.getFromDate(), + request.getToDate(), + pageRequest + ); + + } else { + pageResult = beneficiaryRepo.getBenDataByUser(userName, pageRequest); + } + + if (!pageResult.hasContent()) { + return null; + } + + return getMappingsForAddressIDs( + pageResult.getContent(), + pageResult.getTotalPages(), + authorisation + ); } + private String getMappingsForAddressIDs(List addressList, int totalPage, String authorisation) { RMNCHHouseHoldDetails benHouseHoldRMNCH_ROBJ; @@ -158,276 +228,393 @@ private String getMappingsForAddressIDs(List addressLi for (RMNCHMBeneficiaryaddress a : addressList) { // exception by-passing try { - RMNCHMBeneficiarymapping m = beneficiaryRepo.getByAddressID(a.getId()); - if (m != null) { - benHouseHoldRMNCH_ROBJ = new RMNCHHouseHoldDetails(); - benDetailsRMNCH_OBJ = new RMNCHBeneficiaryDetailsRmnch(); - benBotnBirthRMNCH_ROBJ = new RMNCHBornBirthDetails(); - - benDetailsOBJ = new RMNCHMBeneficiarydetail(); - benAccountOBJ = new RMNCHMBeneficiaryAccount(); - benImageOBJ = new RMNCHMBeneficiaryImage(); - benAddressOBJ = new RMNCHMBeneficiaryaddress(); - benContactOBJ = new RMNCHMBeneficiarycontact(); - Map healthDetails = getBenHealthDetails(m.getBenRegId()); - if (m.getBenDetailsId() != null) { - benDetailsOBJ = beneficiaryRepo.getDetailsById(m.getBenDetailsId()); - } - if (m.getBenAccountID() != null) { - benAccountOBJ = beneficiaryRepo.getAccountById(m.getBenAccountID()); - } - if (m.getBenImageId() != null) { - benImageOBJ = beneficiaryRepo.getImageById(m.getBenImageId().longValue()); - } - if (m.getBenAddressId() != null) { - benAddressOBJ = beneficiaryRepo.getAddressById(m.getBenAddressId()); - } - if (m.getBenContactsId() != null) { - benContactOBJ = beneficiaryRepo.getContactById(m.getBenContactsId()); - } + if(!beneficiaryRepo.getByAddressID(a.getId()).isEmpty()){ + RMNCHMBeneficiarymapping m = beneficiaryRepo.getByAddressID(a.getId()).get(0); + if (m != null) { + benHouseHoldRMNCH_ROBJ = new RMNCHHouseHoldDetails(); + benDetailsRMNCH_OBJ = new RMNCHBeneficiaryDetailsRmnch(); + benBotnBirthRMNCH_ROBJ = new RMNCHBornBirthDetails(); + + benDetailsOBJ = new RMNCHMBeneficiarydetail(); + benAccountOBJ = new RMNCHMBeneficiaryAccount(); + benImageOBJ = new RMNCHMBeneficiaryImage(); + benAddressOBJ = new RMNCHMBeneficiaryaddress(); + benContactOBJ = new RMNCHMBeneficiarycontact(); + Map healthDetails = getBenHealthDetails(m.getBenRegId()); + if (m.getBenDetailsId() != null) { + benDetailsOBJ = beneficiaryRepo.getDetailsById(m.getBenDetailsId()); + } + if (m.getBenAccountID() != null) { + benAccountOBJ = beneficiaryRepo.getAccountById(m.getBenAccountID()); + } + if (m.getBenImageId() != null) { + benImageOBJ = beneficiaryRepo.getImageById(m.getBenImageId().longValue()); + } + if (m.getBenAddressId() != null) { + benAddressOBJ = beneficiaryRepo.getAddressById(m.getBenAddressId()); + } + if (m.getBenContactsId() != null) { + benContactOBJ = beneficiaryRepo.getContactById(m.getBenContactsId()); + } - BigInteger benID = null; - if (m.getBenRegId() != null) - benID = beneficiaryRepo.getBenIdFromRegID(m.getBenRegId().longValue()); + BigInteger benID = null; + if (m.getBenRegId() != null) + benID = beneficiaryRepo.getBenIdFromRegID(m.getBenRegId().longValue()); - if (m.getBenRegId() != null) { - benDetailsRMNCH_OBJ = beneficiaryRepo - .getDetailsByRegID((m.getBenRegId()).longValue()); - benBotnBirthRMNCH_ROBJ = beneficiaryRepo.getBornBirthByRegID((m.getBenRegId()).longValue()); + if (m.getBenRegId() != null) { + if(!beneficiaryRepo + .getDetailsByRegID((m.getBenRegId()).longValue()).isEmpty()){ + benDetailsRMNCH_OBJ = beneficiaryRepo + .getDetailsByRegID((m.getBenRegId()).longValue()).get(0); + } + benBotnBirthRMNCH_ROBJ = beneficiaryRepo.getBornBirthByRegID((m.getBenRegId()).longValue()); - if (benDetailsRMNCH_OBJ != null && benDetailsRMNCH_OBJ.getHouseoldId() != null) - benHouseHoldRMNCH_ROBJ = houseHoldRepo - .getByHouseHoldID(benDetailsRMNCH_OBJ.getHouseoldId()); + if (benDetailsRMNCH_OBJ != null && benDetailsRMNCH_OBJ.getHouseoldId() != null) + if(!houseHoldRepo + .getByHouseHoldID(benDetailsRMNCH_OBJ.getHouseoldId()).isEmpty()){ + benHouseHoldRMNCH_ROBJ = houseHoldRepo + .getByHouseHoldID(benDetailsRMNCH_OBJ.getHouseoldId()).get(0); + } - } - if (benDetailsRMNCH_OBJ == null) - benDetailsRMNCH_OBJ = new RMNCHBeneficiaryDetailsRmnch(); - // new mapping 30-06-2021 - if (benDetailsOBJ.getMotherName() != null) - benDetailsRMNCH_OBJ.setMotherName(benDetailsOBJ.getMotherName()); - if (benDetailsOBJ.getLiteracyStatus() != null) - benDetailsRMNCH_OBJ.setLiteracyStatus(benDetailsOBJ.getLiteracyStatus()); - - // bank - if (benAccountOBJ.getNameOfBank() != null) - benDetailsRMNCH_OBJ.setNameOfBank(benAccountOBJ.getNameOfBank()); - if (benAccountOBJ.getBranchName() != null) - benDetailsRMNCH_OBJ.setBranchName(benAccountOBJ.getBranchName()); - if (benAccountOBJ.getIfscCode() != null) - benDetailsRMNCH_OBJ.setIfscCode(benAccountOBJ.getIfscCode()); - if (benAccountOBJ.getBankAccount() != null) - benDetailsRMNCH_OBJ.setBankAccount(benAccountOBJ.getBankAccount()); - - // location - if (benAddressOBJ.getCountyid() != null) - benDetailsRMNCH_OBJ.setCountryId(benAddressOBJ.getCountyid()); - if (benAddressOBJ.getPermCountry() != null) - benDetailsRMNCH_OBJ.setCountryName(benAddressOBJ.getPermCountry()); - - if (benAddressOBJ.getStatePerm() != null) - benDetailsRMNCH_OBJ.setStateId(benAddressOBJ.getStatePerm()); - if (benAddressOBJ.getPermState() != null) - benDetailsRMNCH_OBJ.setStateName(benAddressOBJ.getPermState()); - - if (benAddressOBJ.getDistrictidPerm() != null) { - benDetailsRMNCH_OBJ.setDistrictid(benAddressOBJ.getDistrictidPerm()); + } + if (benDetailsRMNCH_OBJ == null) + benDetailsRMNCH_OBJ = new RMNCHBeneficiaryDetailsRmnch(); + + // new mapping 30-06-2021 + if (benDetailsOBJ.getMotherName() != null) + benDetailsRMNCH_OBJ.setMotherName(benDetailsOBJ.getMotherName()); + if (benDetailsOBJ.getLiteracyStatus() != null) + benDetailsRMNCH_OBJ.setLiteracyStatus(benDetailsOBJ.getLiteracyStatus()); + + // bank + if (benAccountOBJ.getNameOfBank() != null) + benDetailsRMNCH_OBJ.setNameOfBank(benAccountOBJ.getNameOfBank()); + if (benAccountOBJ.getBranchName() != null) + benDetailsRMNCH_OBJ.setBranchName(benAccountOBJ.getBranchName()); + if (benAccountOBJ.getIfscCode() != null) + benDetailsRMNCH_OBJ.setIfscCode(benAccountOBJ.getIfscCode()); + if (benAccountOBJ.getBankAccount() != null) + benDetailsRMNCH_OBJ.setBankAccount(benAccountOBJ.getBankAccount()); + + // location + if (benAddressOBJ.getCountyid() != null) + benDetailsRMNCH_OBJ.setCountryId(benAddressOBJ.getCountyid()); + if (benAddressOBJ.getPermCountry() != null) + benDetailsRMNCH_OBJ.setCountryName(benAddressOBJ.getPermCountry()); + + if (benAddressOBJ.getStatePerm() != null) + benDetailsRMNCH_OBJ.setStateId(benAddressOBJ.getStatePerm()); + if (benAddressOBJ.getPermState() != null) + benDetailsRMNCH_OBJ.setStateName(benAddressOBJ.getPermState()); + + if (benAddressOBJ.getDistrictidPerm() != null) { + benDetailsRMNCH_OBJ.setDistrictid(benAddressOBJ.getDistrictidPerm()); - } - if (benAddressOBJ.getDistrictnamePerm() != null) { - benDetailsRMNCH_OBJ.setDistrictname(benAddressOBJ.getDistrictnamePerm()); + } + if (benAddressOBJ.getDistrictnamePerm() != null) { + benDetailsRMNCH_OBJ.setDistrictname(benAddressOBJ.getDistrictnamePerm()); - } + } + + if (benAddressOBJ.getPermSubDistrictId() != null) + benDetailsRMNCH_OBJ.setBlockId(benAddressOBJ.getPermSubDistrictId()); + if (benAddressOBJ.getPermSubDistrict() != null) + benDetailsRMNCH_OBJ.setBlockName(benAddressOBJ.getPermSubDistrict()); + + if (benAddressOBJ.getVillageidPerm() != null) + benDetailsRMNCH_OBJ.setVillageId(benAddressOBJ.getVillageidPerm()); + if (benAddressOBJ.getVillagenamePerm() != null) + benDetailsRMNCH_OBJ.setVillageName(benAddressOBJ.getVillagenamePerm()); + + if (benAddressOBJ.getPermServicePointId() != null) + benDetailsRMNCH_OBJ.setServicePointID(benAddressOBJ.getPermServicePointId()); + if (benAddressOBJ.getPermServicePoint() != null) + benDetailsRMNCH_OBJ.setServicePointName(benAddressOBJ.getPermServicePoint()); + + if (benAddressOBJ.getPermZoneID() != null) + benDetailsRMNCH_OBJ.setZoneID(benAddressOBJ.getPermZoneID()); + if (benAddressOBJ.getPermZone() != null) + benDetailsRMNCH_OBJ.setZoneName(benAddressOBJ.getPermZone()); + + if (benAddressOBJ.getPermAddrLine1() != null) + benDetailsRMNCH_OBJ.setAddressLine1(benAddressOBJ.getPermAddrLine1()); + if (benAddressOBJ.getPermAddrLine2() != null) + benDetailsRMNCH_OBJ.setAddressLine2(benAddressOBJ.getPermAddrLine2()); + if (benAddressOBJ.getPermAddrLine3() != null) + benDetailsRMNCH_OBJ.setAddressLine3(benAddressOBJ.getPermAddrLine3()); + if (benAddressOBJ.getPermPinCode() != null) + benDetailsRMNCH_OBJ.setPinCode(benAddressOBJ.getPermPinCode()); + + // GPS fallback: if not in RMNCH details (syncdatatoamrti not yet called), + // pull from i_beneficiaryaddress (saved during TM-API registration) + if (benDetailsRMNCH_OBJ.getGpsLatitude() == null && benAddressOBJ.getGpsLatitude() != null) + benDetailsRMNCH_OBJ.setGpsLatitude(benAddressOBJ.getGpsLatitude()); + if (benDetailsRMNCH_OBJ.getGpsLongitude() == null && benAddressOBJ.getGpsLongitude() != null) + benDetailsRMNCH_OBJ.setGpsLongitude(benAddressOBJ.getGpsLongitude()); + if (benDetailsRMNCH_OBJ.getDigipin() == null && benAddressOBJ.getDigipin() != null) + benDetailsRMNCH_OBJ.setDigipin(benAddressOBJ.getDigipin()); + if (benDetailsRMNCH_OBJ.getGpsTimestamp() == null && benAddressOBJ.getGpsTimestamp() != null) + benDetailsRMNCH_OBJ.setGpsTimestamp(benAddressOBJ.getGpsTimestamp()); + if (benDetailsRMNCH_OBJ.getIsGpsUnavailable() == null && benAddressOBJ.getIsGpsUnavailable() != null) + benDetailsRMNCH_OBJ.setIsGpsUnavailable(benAddressOBJ.getIsGpsUnavailable()); + if (benDetailsRMNCH_OBJ.getGpsUnavailableReason() == null && benAddressOBJ.getGpsUnavailableReason() != null) + benDetailsRMNCH_OBJ.setGpsUnavailableReason(benAddressOBJ.getGpsUnavailableReason()); + + // Map GPS double fields to the exposed latitude/longitude BigDecimal fields for response + if (benDetailsRMNCH_OBJ.getGpsLatitude() != null) + benDetailsRMNCH_OBJ.setLatitude(BigDecimal.valueOf(benDetailsRMNCH_OBJ.getGpsLatitude())); + if (benDetailsRMNCH_OBJ.getGpsLongitude() != null) + benDetailsRMNCH_OBJ.setLongitude(BigDecimal.valueOf(benDetailsRMNCH_OBJ.getGpsLongitude())); + + // ----------------------------------------------------------------------------- + + // related benids + if (benDetailsRMNCH_OBJ.getRelatedBeneficiaryIdsDB() != null) { + + String[] relatedBenIDsString = benDetailsRMNCH_OBJ.getRelatedBeneficiaryIdsDB().split(","); + Long[] relatedBenIDs = new Long[relatedBenIDsString.length]; + int pointer = 0; + for (String s : relatedBenIDsString) { + relatedBenIDs[pointer] = Long.valueOf(s); + pointer++; + } - if (benAddressOBJ.getPermSubDistrictId() != null) - benDetailsRMNCH_OBJ.setBlockId(benAddressOBJ.getPermSubDistrictId()); - if (benAddressOBJ.getPermSubDistrict() != null) - benDetailsRMNCH_OBJ.setBlockName(benAddressOBJ.getPermSubDistrict()); - - if (benAddressOBJ.getVillageidPerm() != null) - benDetailsRMNCH_OBJ.setVillageId(benAddressOBJ.getVillageidPerm()); - if (benAddressOBJ.getVillagenamePerm() != null) - benDetailsRMNCH_OBJ.setVillageName(benAddressOBJ.getVillagenamePerm()); - - if (benAddressOBJ.getPermServicePointId() != null) - benDetailsRMNCH_OBJ.setServicePointID(benAddressOBJ.getPermServicePointId()); - if (benAddressOBJ.getPermServicePoint() != null) - benDetailsRMNCH_OBJ.setServicePointName(benAddressOBJ.getPermServicePoint()); - - if (benAddressOBJ.getPermZoneID() != null) - benDetailsRMNCH_OBJ.setZoneID(benAddressOBJ.getPermZoneID()); - if (benAddressOBJ.getPermZone() != null) - benDetailsRMNCH_OBJ.setZoneName(benAddressOBJ.getPermZone()); - - if (benAddressOBJ.getPermAddrLine1() != null) - benDetailsRMNCH_OBJ.setAddressLine1(benAddressOBJ.getPermAddrLine1()); - if (benAddressOBJ.getPermAddrLine2() != null) - benDetailsRMNCH_OBJ.setAddressLine2(benAddressOBJ.getPermAddrLine2()); - if (benAddressOBJ.getPermAddrLine3() != null) - benDetailsRMNCH_OBJ.setAddressLine3(benAddressOBJ.getPermAddrLine3()); - - // ----------------------------------------------------------------------------- - - // related benids - if (benDetailsRMNCH_OBJ.getRelatedBeneficiaryIdsDB() != null) { - - String[] relatedBenIDsString = benDetailsRMNCH_OBJ.getRelatedBeneficiaryIdsDB().split(","); - Long[] relatedBenIDs = new Long[relatedBenIDsString.length]; - int pointer = 0; - for (String s : relatedBenIDsString) { - relatedBenIDs[pointer] = Long.valueOf(s); - pointer++; + benDetailsRMNCH_OBJ.setRelatedBeneficiaryIds(relatedBenIDs); } + // ------------------------------------------------------------------------------ - benDetailsRMNCH_OBJ.setRelatedBeneficiaryIds(relatedBenIDs); - } - // ------------------------------------------------------------------------------ - - if (benDetailsOBJ.getCommunity() != null) - benDetailsRMNCH_OBJ.setCommunity(benDetailsOBJ.getCommunity()); - if (benDetailsOBJ.getCommunityId() != null) - benDetailsRMNCH_OBJ.setCommunityId(benDetailsOBJ.getCommunityId()); - if (benContactOBJ.getPreferredPhoneNum() != null) - benDetailsRMNCH_OBJ.setContact_number(benContactOBJ.getPreferredPhoneNum()); - - if (benDetailsOBJ.getDob() != null) - benDetailsRMNCH_OBJ.setDob(benDetailsOBJ.getDob()); - if (benDetailsOBJ.getFatherName() != null) - benDetailsRMNCH_OBJ.setFatherName(benDetailsOBJ.getFatherName()); - if (benDetailsOBJ.getFirstName() != null) - benDetailsRMNCH_OBJ.setFirstName(benDetailsOBJ.getFirstName()); - if (benDetailsOBJ.getGender() != null) - benDetailsRMNCH_OBJ.setGender(benDetailsOBJ.getGender()); - if (benDetailsOBJ.getGenderId() != null) - benDetailsRMNCH_OBJ.setGenderId(benDetailsOBJ.getGenderId()); - - if (benDetailsOBJ.getMaritalstatus() != null) - benDetailsRMNCH_OBJ.setMaritalstatus(benDetailsOBJ.getMaritalstatus()); - if (benDetailsOBJ.getMaritalstatusId() != null) - benDetailsRMNCH_OBJ.setMaritalstatusId(benDetailsOBJ.getMaritalstatusId()); - if (benDetailsOBJ.getMarriageDate() != null) - benDetailsRMNCH_OBJ.setMarriageDate(benDetailsOBJ.getMarriageDate()); - - if (benDetailsOBJ.getReligion() != null) - benDetailsRMNCH_OBJ.setReligion(benDetailsOBJ.getReligion()); - if (benDetailsOBJ.getReligionID() != null) - benDetailsRMNCH_OBJ.setReligionID(benDetailsOBJ.getReligionID()); - if (benDetailsOBJ.getSpousename() != null) - benDetailsRMNCH_OBJ.setSpousename(benDetailsOBJ.getSpousename()); - - if (benImageOBJ != null && benImageOBJ.getUser_image() != null) - benDetailsRMNCH_OBJ.setUser_image(benImageOBJ.getUser_image()); - - // new fields + if (benDetailsOBJ.getCommunity() != null) + benDetailsRMNCH_OBJ.setCommunity(benDetailsOBJ.getCommunity()); + if (benDetailsOBJ.getCommunityId() != null) + benDetailsRMNCH_OBJ.setCommunityId(benDetailsOBJ.getCommunityId()); + if (benContactOBJ.getPreferredPhoneNum() != null) + benDetailsRMNCH_OBJ.setContact_number(benContactOBJ.getPreferredPhoneNum()); + + if (benDetailsOBJ.getDob() != null) { + benDetailsRMNCH_OBJ.setDob(benDetailsOBJ.getDob()); + } else { + // i_beneficiarydetails.dob is null for Stop TB mobile registrations + // (Identity-API mapper commented out) — fall back to i_ben_flow_outreach.ben_dob + List flows = benFlowStatusRepo.findByBeneficiaryRegID(m.getBenRegId().longValue()); + if (!flows.isEmpty() && flows.get(0).getDob() != null) + benDetailsRMNCH_OBJ.setDob(flows.get(0).getDob()); + } + if (benDetailsOBJ.getFatherName() != null) + benDetailsRMNCH_OBJ.setFatherName(benDetailsOBJ.getFatherName()); + if (benDetailsOBJ.getFirstName() != null) + benDetailsRMNCH_OBJ.setFirstName(benDetailsOBJ.getFirstName()); + if (benDetailsOBJ.getGender() != null) + benDetailsRMNCH_OBJ.setGender(benDetailsOBJ.getGender()); + if (benDetailsOBJ.getGenderId() != null) + benDetailsRMNCH_OBJ.setGenderId(benDetailsOBJ.getGenderId()); + + if (benDetailsOBJ.getMaritalstatus() != null) + benDetailsRMNCH_OBJ.setMaritalstatus(benDetailsOBJ.getMaritalstatus()); + if (benDetailsOBJ.getMaritalstatusId() != null) + benDetailsRMNCH_OBJ.setMaritalstatusId(benDetailsOBJ.getMaritalstatusId()); + if (benDetailsOBJ.getMarriageDate() != null) + benDetailsRMNCH_OBJ.setMarriageDate(benDetailsOBJ.getMarriageDate()); + + if (benDetailsOBJ.getReligion() != null) + benDetailsRMNCH_OBJ.setReligion(benDetailsOBJ.getReligion()); + if (benDetailsOBJ.getReligionID() != null) + benDetailsRMNCH_OBJ.setReligionID(benDetailsOBJ.getReligionID()); + if (benDetailsOBJ.getSpousename() != null) + benDetailsRMNCH_OBJ.setSpousename(benDetailsOBJ.getSpousename()); + + if (benImageOBJ != null && benImageOBJ.getUser_image() != null) + benDetailsRMNCH_OBJ.setUser_image(benImageOBJ.getUser_image()); + + // new fields // benDetailsRMNCH_OBJ.setRegistrationDate(benDetailsOBJ.getCreatedDate()); - if (benID != null) - benDetailsRMNCH_OBJ.setBenficieryid(benID.longValue()); + if (benID != null) + benDetailsRMNCH_OBJ.setBenficieryid(benID.longValue()); - if (benDetailsOBJ.getLastName() != null) - benDetailsRMNCH_OBJ.setLastName(benDetailsOBJ.getLastName()); + if (benDetailsOBJ.getLastName() != null) + benDetailsRMNCH_OBJ.setLastName(benDetailsOBJ.getLastName()); - if (benDetailsRMNCH_OBJ.getCreatedBy() == null) - if (benDetailsOBJ.getCreatedBy() != null) - benDetailsRMNCH_OBJ.setCreatedBy(benDetailsOBJ.getCreatedBy()); + if (benDetailsRMNCH_OBJ.getCreatedBy() == null) + if (benDetailsOBJ.getCreatedBy() != null) + benDetailsRMNCH_OBJ.setCreatedBy(benDetailsOBJ.getCreatedBy()); - // age calculation - String ageDetails = ""; - int age_val = 0; - String ageUnit = null; - if (benDetailsOBJ.getDob() != null) { + // age calculation + String ageDetails = ""; + int age_val = 0; + String ageUnit = null; + if (benDetailsRMNCH_OBJ.getDob() != null) { - Date date = new Date(benDetailsOBJ.getDob().getTime()); - Calendar cal = Calendar.getInstance(); + Date date = new Date(benDetailsRMNCH_OBJ.getDob().getTime()); + Calendar cal = Calendar.getInstance(); - cal.setTime(date); + cal.setTime(date); - int year = cal.get(Calendar.YEAR); - int month = cal.get(Calendar.MONTH) + 1; - int day = cal.get(Calendar.DAY_OF_MONTH); + int year = cal.get(Calendar.YEAR); + int month = cal.get(Calendar.MONTH) + 1; + int day = cal.get(Calendar.DAY_OF_MONTH); - java.time.LocalDate todayDate = java.time.LocalDate.now(); - java.time.LocalDate birthdate = java.time.LocalDate.of(year, month, day); - Period p = Period.between(birthdate, todayDate); + java.time.LocalDate todayDate = java.time.LocalDate.now(); + java.time.LocalDate birthdate = java.time.LocalDate.of(year, month, day); + Period p = Period.between(birthdate, todayDate); - int d = p.getDays(); - int mo = p.getMonths(); - int y = p.getYears(); + int d = p.getDays(); + int mo = p.getMonths(); + int y = p.getYears(); - if (y > 0) { - ageDetails = y + " years - " + mo + " months"; - age_val = y; - ageUnit = (age_val > 1) ? "Years" : "Year"; - } else { - if (mo > 0) { - ageDetails = mo + " months - " + d + " days"; - age_val = mo; - ageUnit = (age_val > 1) ? "Months" : "Month"; + if (y > 0) { + ageDetails = y + " years - " + mo + " months"; + age_val = y; + ageUnit = (age_val > 1) ? "Years" : "Year"; } else { - ageDetails = d + " days"; - age_val = d; - ageUnit = (age_val > 1) ? "Days" : "Day"; + if (mo > 0) { + ageDetails = mo + " months - " + d + " days"; + age_val = mo; + ageUnit = (age_val > 1) ? "Months" : "Month"; + } else { + ageDetails = d + " days"; + age_val = d; + ageUnit = (age_val > 1) ? "Days" : "Day"; + } } + } - } + benDetailsRMNCH_OBJ.setAgeFull(ageDetails); + benDetailsRMNCH_OBJ.setAge(age_val); + if (ageUnit != null) + benDetailsRMNCH_OBJ.setAge_unit(ageUnit); + + resultMap = new HashMap<>(); + if (benHouseHoldRMNCH_ROBJ != null) + resultMap.put("householdDetails", benHouseHoldRMNCH_ROBJ); + else + resultMap.put("householdDetails", new HashMap()); + + if (benBotnBirthRMNCH_ROBJ != null) + resultMap.put("bornbirthDeatils", benBotnBirthRMNCH_ROBJ); + else + resultMap.put("bornbirthDeatils", new HashMap()); + + resultMap.put("beneficiaryDetails", benDetailsRMNCH_OBJ); + resultMap.put("abhaHealthDetails", healthDetails); + resultMap.put("houseoldId", benDetailsRMNCH_OBJ.getHouseoldId()); + resultMap.put("benficieryid", benDetailsRMNCH_OBJ.getBenficieryid()); + resultMap.put("isDeath", benDetailsRMNCH_OBJ.getIsDeath()); + resultMap.put("isDeathValue", benDetailsRMNCH_OBJ.getIsDeathValue()); + resultMap.put("dateOfDeath",benDetailsRMNCH_OBJ.getDateOfDeath()); + resultMap.put("timeOfDeath", benDetailsRMNCH_OBJ.getTimeOfDeath()); + resultMap.put("reasonOfDeath", benDetailsRMNCH_OBJ.getReasonOfDeath()); + resultMap.put("reasonOfDeathId", benDetailsRMNCH_OBJ.getReasonOfDeathId()); + resultMap.put("placeOfDeath", benDetailsRMNCH_OBJ.getPlaceOfDeath()); + resultMap.put("placeOfDeathId", benDetailsRMNCH_OBJ.getPlaceOfDeathId()); + resultMap.put("isSpouseAdded", benDetailsRMNCH_OBJ.getIsSpouseAdded()); + resultMap.put("isChildrenAdded", benDetailsRMNCH_OBJ.getIsChildrenAdded()); + resultMap.put("noOfchildren", benDetailsRMNCH_OBJ.getNoOfchildren()); + resultMap.put("isMarried", benDetailsRMNCH_OBJ.getIsMarried()); + resultMap.put("doYouHavechildren", benDetailsRMNCH_OBJ.getDoYouHavechildren()); + resultMap.put("noofAlivechildren",benDetailsRMNCH_OBJ.getNoofAlivechildren()); + resultMap.put("isDeactivate", benDetailsRMNCH_OBJ.getIsDeactivate() != null + ? benDetailsRMNCH_OBJ.getIsDeactivate() + : false + ); + resultMap.put("economicStatus",benDetailsOBJ.getEconomicStatus()); + resultMap.put("economicStatusId",benDetailsOBJ.getEconomicStatusId()); + resultMap.put("residentialAreaId",benDetailsOBJ.getResidentialAreaId()); + resultMap.put("residentialArea",benDetailsOBJ.getResidentialArea()); + resultMap.put("address",benDetailsOBJ.getAddress()); + resultMap.put("updateDate", benDetailsOBJ.getLastModDate()); + resultMap.put("updatedBy", benDetailsOBJ.getModifiedBy()); + resultMap.put("BenRegId", m.getBenRegId()); + + // occupation from i_beneficiarydetails + if (benDetailsOBJ != null && benDetailsOBJ.getOccupation() != null) + benDetailsRMNCH_OBJ.setOccupation(benDetailsOBJ.getOccupation()); + + // anthropometry from t_phy_anthropometry, vitals from t_phy_vitals + // fallback to otherFields if exam not yet saved for this beneficiary + Long benRegIdLong = m.getBenRegId() != null ? m.getBenRegId().longValue() : null; + if (benRegIdLong != null) { + List anthroList = + benAnthropometryRepo.findByBeneficiaryRegIDOrderByCreatedDateDesc(benRegIdLong); + List vitalList = + benPhysicalVitalRepo.findByBeneficiaryRegIDOrderByCreatedDateDesc(benRegIdLong); + + Map anthropometry = new HashMap<>(); + if (!anthroList.isEmpty()) { + BenAnthropometryDetail anthro = anthroList.get(0); + if (anthro.getHeightCm() != null) anthropometry.put("height", anthro.getHeightCm()); + if (anthro.getWeightKg() != null) anthropometry.put("weight", anthro.getWeightKg()); + if (anthro.getBmi() != null) anthropometry.put("bmi", anthro.getBmi()); + } + if (!vitalList.isEmpty()) { + BenPhysicalVitalDetail vital = vitalList.get(0); + if (vital.getTemperature() != null) anthropometry.put("temperatureValue", vital.getTemperature()); + if (vital.getPulseRate() != null) anthropometry.put("pulseRate", vital.getPulseRate()); + if (vital.getSystolicBP() != null) anthropometry.put("systolicBP", vital.getSystolicBP()); + if (vital.getDiastolicBP() != null) anthropometry.put("diastolicBP", vital.getDiastolicBP()); + if (vital.getBloodGlucoseRandom() != null) anthropometry.put("bloodGlucoseRandom", vital.getBloodGlucoseRandom()); + } - benDetailsRMNCH_OBJ.setAgeFull(ageDetails); - benDetailsRMNCH_OBJ.setAge(age_val); - if (ageUnit != null) - benDetailsRMNCH_OBJ.setAge_unit(ageUnit); - - resultMap = new HashMap<>(); - if (benHouseHoldRMNCH_ROBJ != null) - resultMap.put("householdDetails", benHouseHoldRMNCH_ROBJ); - else - resultMap.put("householdDetails", new HashMap()); - - if (benBotnBirthRMNCH_ROBJ != null) - resultMap.put("bornbirthDeatils", benBotnBirthRMNCH_ROBJ); - else - resultMap.put("bornbirthDeatils", new HashMap()); - - resultMap.put("beneficiaryDetails", benDetailsRMNCH_OBJ); - resultMap.put("abhaHealthDetails", healthDetails); - resultMap.put("houseoldId", benDetailsRMNCH_OBJ.getHouseoldId()); - resultMap.put("benficieryid", benDetailsRMNCH_OBJ.getBenficieryid()); - resultMap.put("isDeath", benDetailsRMNCH_OBJ.getIsDeath()); - resultMap.put("isDeathValue", benDetailsRMNCH_OBJ.getIsDeathValue()); - resultMap.put("dateOfDeath",benDetailsRMNCH_OBJ.getDateOfDeath()); - resultMap.put("timeOfDeath", benDetailsRMNCH_OBJ.getTimeOfDeath()); - resultMap.put("reasonOfDeath", benDetailsRMNCH_OBJ.getReasonOfDeath()); - resultMap.put("reasonOfDeathId", benDetailsRMNCH_OBJ.getReasonOfDeathId()); - resultMap.put("placeOfDeath", benDetailsRMNCH_OBJ.getPlaceOfDeath()); - resultMap.put("placeOfDeathId", benDetailsRMNCH_OBJ.getPlaceOfDeathId()); - resultMap.put("isSpouseAdded", benDetailsRMNCH_OBJ.getIsSpouseAdded()); - resultMap.put("isChildrenAdded", benDetailsRMNCH_OBJ.getIsChildrenAdded()); - resultMap.put("noOfchildren", benDetailsRMNCH_OBJ.getNoOfchildren()); - resultMap.put("isMarried", benDetailsRMNCH_OBJ.getIsMarried()); - resultMap.put("doYouHavechildren", benDetailsRMNCH_OBJ.getDoYouHavechildren()); - resultMap.put("noofAlivechildren ",benDetailsRMNCH_OBJ.getNoofAlivechildren()); - - - - resultMap.put("BenRegId", m.getBenRegId()); - - // adding asha id / created by - user id - if (benAddressOBJ.getCreatedBy() != null) { - Integer userID = beneficiaryRepo.getUserIDByUserName(benAddressOBJ.getCreatedBy()); - if (userID != null && userID > 0) - resultMap.put("ashaId", userID); - } - // get HealthID of ben - if (m.getBenRegId() != null) { - fetchHealthIdByBenRegID(m.getBenRegId().longValue(), authorisation, resultMap); - } + // fallback: if no exam saved yet, read from registration otherFields + if (anthropometry.isEmpty() && benDetailsOBJ != null && benDetailsOBJ.getOtherFields() != null) { + try { + Map extraFields = new Gson().fromJson(benDetailsOBJ.getOtherFields(), Map.class); + if (extraFields.containsKey("weight")) anthropometry.put("weight", extraFields.get("weight")); + if (extraFields.containsKey("height")) anthropometry.put("height", extraFields.get("height")); + if (extraFields.containsKey("bmi")) anthropometry.put("bmi", extraFields.get("bmi")); + if (extraFields.containsKey("temperatureValue")) anthropometry.put("temperatureValue", extraFields.get("temperatureValue")); + } catch (Exception ex) { + logger.warn("Could not parse otherFields for fallback anthropometry: " + benDetailsOBJ.getBeneficiaryDetailsId()); + } + } + if (!anthropometry.isEmpty()) resultMap.put("anthropometry", anthropometry); + } + + // Stop TB fields from ExtraFields + Map stopTBDetails = new HashMap<>(); + if (benDetailsOBJ != null && benDetailsOBJ.getOtherFields() != null) { + try { + Map extraFields = new Gson().fromJson(benDetailsOBJ.getOtherFields(), Map.class); + + if (extraFields.containsKey("personFrom")) stopTBDetails.put("personFrom", extraFields.get("personFrom")); + if (extraFields.containsKey("caseFindingType")) stopTBDetails.put("caseFindingType", extraFields.get("caseFindingType")); + if (extraFields.containsKey("isMobileAvailable")) stopTBDetails.put("isMobileAvailable", extraFields.get("isMobileAvailable")); + if (extraFields.containsKey("tuId")) stopTBDetails.put("tuId", extraFields.get("tuId")); + if (extraFields.containsKey("tuName")) stopTBDetails.put("tuName", extraFields.get("tuName")); + + // economicStatus and residentialArea into beneficiaryDetails + if (extraFields.containsKey("economicStatus")) benDetailsRMNCH_OBJ.setEconomicStatus((String) extraFields.get("economicStatus")); + if (extraFields.containsKey("economicStatusId")) benDetailsRMNCH_OBJ.setEconomicStatusId(((Number) extraFields.get("economicStatusId")).intValue()); + if (extraFields.containsKey("residentialArea")) benDetailsRMNCH_OBJ.setResidentialArea((String) extraFields.get("residentialArea")); + if (extraFields.containsKey("residentialAreaId")) benDetailsRMNCH_OBJ.setResidentialAreaId(((Number) extraFields.get("residentialAreaId")).intValue()); + } catch (Exception ex) { + logger.warn("Could not parse ExtraFields for benDetailsId: " + benDetailsOBJ.getBeneficiaryDetailsId()); + } + } + if (!stopTBDetails.isEmpty()) resultMap.put("stopTBDetails", stopTBDetails); - resultList.add(resultMap); + // adding asha id / created by - user id + if (benAddressOBJ.getCreatedBy() != null) { + Integer userID = beneficiaryRepo.getUserIDByUserName(benAddressOBJ.getCreatedBy()); + if (userID != null && userID > 0) + resultMap.put("ashaId", userID); + } + // get HealthID of ben + if (m.getBenRegId() != null) { + fetchHealthIdByBenRegID(m.getBenRegId().longValue(), authorisation, resultMap); + } - } else { - // mapping not available + resultList.add(resultMap); + + } else { + // mapping not available + } } + } catch (Exception e) { - logger.error("error for addressID :"+e.getMessage() + a.getId() + " and vanID : " + a.getVanID()); + logger.info("Error for ben :"+e.getMessage()); + logger.info("Error for ben :"+e); + logger.error("error for addressID :" + e.getMessage() + a.getId() + " and vanID : " + a.getVanID()); } } @@ -440,33 +627,33 @@ private String getMappingsForAddressIDs(List addressLi } - private Map getBenHealthDetails(BigInteger benRegId) { - Map healthDetails = new HashMap<>(); - if (null != benRegId) { - Object[] benHealthIdNumber = beneficiaryRepo.getBenHealthIdNumber(benRegId); - if (benHealthIdNumber != null && benHealthIdNumber.length > 0) { - Object[] healthData = (Object[]) benHealthIdNumber[0]; - String healthIdNumber = healthData[0] != null ? healthData[0].toString() : null; - String healthId = healthData[1] != null ? healthData[1].toString() : null; - - if (null != healthIdNumber) { - List health = beneficiaryRepo.getBenHealthDetails(healthIdNumber); - if (health != null && !health.isEmpty()) { - for (Object[] objects : health) { - healthDetails.put("HealthID", objects[0]); - healthDetails.put("HealthIdNumber", objects[1]); - healthDetails.put("isNewAbha", objects[2]); - } - } else { - healthDetails.put("HealthIdNumber", healthIdNumber); - healthDetails.put("HealthID", healthId); - healthDetails.put("isNewAbha", null); - } - } - } - } - return healthDetails; - } + private Map getBenHealthDetails(BigInteger benRegId) { + Map healthDetails = new HashMap<>(); + if (null != benRegId) { + Object[] benHealthIdNumber = beneficiaryRepo.getBenHealthIdNumber(benRegId); + if (benHealthIdNumber != null && benHealthIdNumber.length > 0) { + Object[] healthData = (Object[]) benHealthIdNumber[0]; + String healthIdNumber = healthData[0] != null ? healthData[0].toString() : null; + String healthId = healthData[1] != null ? healthData[1].toString() : null; + + if (null != healthIdNumber) { + List health = beneficiaryRepo.getBenHealthDetails(healthIdNumber); + if (health != null && !health.isEmpty()) { + for (Object[] objects : health) { + healthDetails.put("HealthID", objects[0]); + healthDetails.put("HealthIdNumber", objects[1]); + healthDetails.put("isNewAbha", objects[2]); + } + } else { + healthDetails.put("HealthIdNumber", healthIdNumber); + healthDetails.put("HealthID", healthId); + healthDetails.put("isNewAbha", null); + } + } + } + } + return healthDetails; + } private Map getBenBenVisitDetails(BigInteger benRegId) { Map healthDetails = new HashMap<>(); @@ -484,7 +671,7 @@ private Map getBenBenVisitDetails(BigInteger benRegId) { return healthDetails; } - public void fetchHealthIdByBenRegID(Long benRegID, String authorization, Map resultMap) { + public void fetchHealthIdByBenRegID(Long benRegID, String authorization, Map resultMap) { Map requestMap = new HashMap(); requestMap.put("beneficiaryRegID", benRegID); requestMap.put("beneficiaryID", null); @@ -523,7 +710,7 @@ public void fetchHealthIdByBenRegID(Long benRegID, String authorization, Map eyeCheckupRequestDTOS) { + public String saveEyeCheckupVsit(List eyeCheckupRequestDTOS, String token) { try { for (EyeCheckupRequestDTO dto : eyeCheckupRequestDTOS) { @@ -531,41 +718,72 @@ public String saveEyeCheckupVsit(List eyeCheckupRequestDTO visit.setBeneficiaryId(dto.getBeneficiaryId()); visit.setHouseholdId(dto.getHouseHoldId()); - visit.setUserId(userRepo.getUserIdByName(jwtUtil.getUserNameFromStorage())); // cache se lena hai + visit.setUserId(jwtUtil.extractUserId(token)); visit.setCreatedBy(dto.getUserName()); - StringBuilder sb = new StringBuilder(); - - // fields mapping EyeCheckupListDTO f = dto.getFields(); - sb.append(f.getDischarge_summary_upload()); - String longText = sb.toString(); + + visit.setSymptomsObserved(f.getSymptomsAsString()); + + String upload = f.getDischarge_summary_upload(); + visit.setDischargeSummaryUpload( + (upload != null && !upload.equalsIgnoreCase("null")) ? upload : null + ); + visit.setVisitDate(LocalDate.parse(f.getVisit_date(), FORMATTER)); - visit.setSymptomsObserved(f.getSymptoms_observed()); + + visit.setDateOfSurgery(f.getDate_of_surgery()); + + visit.setEyeAffected(f.getEye_affected()); visit.setReferredTo(f.getReferred_to()); - visit.setDischargeSummaryUpload(longText); visit.setFollowUpStatus(f.getFollow_up_status()); - visit.setDateOfSurgery(f.getDate_of_surgery()); - // save/update eyeCheckUpVisitRepo.save(visit); + if (visit.getReferredTo() != null) { + if (visit.getReferredTo().equals("Govt Public Facility")) { + LocalDate localDate = visit.getVisitDate(); + + Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); + incentiveLogicService.incentiveForEyeSurgeyReferGovtHospital(visit.getBeneficiaryId(), visitDate, visitDate, visit.getUserId()); + } + + if (visit.getReferredTo().equals("Private Facility")) { + LocalDate localDate = visit.getVisitDate(); + + Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); + incentiveLogicService.incentiveForEyeSurgeyReferPrivateHospital(visit.getBeneficiaryId(), visitDate, visitDate, visit.getUserId()); + } + } + } + return "Eye checkup data saved successfully."; - } catch (Exception e) { + + } catch (DateTimeParseException e) { e.printStackTrace(); + throw new RuntimeException("Invalid date format. Expected dd-MM-yyyy. " + e.getMessage()); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Failed to save eye checkup data: " + e.getMessage()); } - return null ; } @Override - public List getEyeCheckUpVisit(GetBenRequestHandler request) { - List visits = eyeCheckUpVisitRepo.findByUserId(request.getAshaId()); + public List getEyeCheckUpVisit(GetBenRequestHandler request,String token) { + String createdBy = null; + try { + createdBy = userService.getUserDetail(jwtUtil.extractUserId(token)).getUserName(); + } catch (Exception e) { + logger.error("Error extracting userId from token: " + e.getMessage()); + } + List visits = eyeCheckUpVisitRepo.findByCreatedBy(createdBy); return visits.stream().map(v -> { EyeCheckupRequestDTO dto = new EyeCheckupRequestDTO(); dto.setId(v.getId()); + dto.setEyeSide(v.getEyeAffected()); dto.setBeneficiaryId(v.getBeneficiaryId()); dto.setHouseHoldId(v.getHouseholdId()); dto.setUserName(v.getCreatedBy()); @@ -582,6 +800,22 @@ public List getEyeCheckUpVisit(GetBenRequestHandler reques dto.setFields(fields); + if (v.getReferredTo() != null) { + if (v.getReferredTo().equals("Govt Public Facility")) { + LocalDate localDate = v.getVisitDate(); + + Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); + incentiveLogicService.incentiveForEyeSurgeyReferGovtHospital(v.getBeneficiaryId(), visitDate, visitDate, v.getUserId()); + } + + if (v.getReferredTo().equals("Private Facility")) { + LocalDate localDate = v.getVisitDate(); + + Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); + incentiveLogicService.incentiveForEyeSurgeyReferPrivateHospital(v.getBeneficiaryId(), visitDate, visitDate, v.getUserId()); + } + } + return dto; }).collect(Collectors.toList()); } diff --git a/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java new file mode 100644 index 00000000..f9c07632 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/CampaignServiceImpl.java @@ -0,0 +1,507 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.iemr.*; +import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.CampaignService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collections; +import java.util.List; + +@Service +public class CampaignServiceImpl implements CampaignService { + + @Autowired + private OrsCampaignRepo orsCampaignRepo; + + @Autowired + private PulsePolioCampaignRepo pulsePolioCampaignRepo; + + @Autowired + private FilariasisCampaignRepo filariasisCampaignRepo; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + IncentivesRepo incentivesRepo; + + @Autowired + IncentiveRecordRepo recordRepo; + + @Autowired + private ObjectMapper objectMapper = new ObjectMapper(); + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; + + @Override + @Transactional + public List saveOrsCampaign(List orsCampaignDTO, String token) throws IEMRException, JsonProcessingException { + if (orsCampaignDTO == null || orsCampaignDTO.isEmpty()) { + return Collections.emptyList(); // + } + + List campaignOrsRequest = new ArrayList<>(); + Integer userId = jwtUtil.extractUserId(token); + String userName = userServiceRoleRepo.getUserNamedByUserId(userId); + + for (OrsCampaignDTO campaignDTO : orsCampaignDTO) { + if (campaignDTO.getFields() == null) { + continue; + } + + CampaignOrs campaignOrsEntity = new CampaignOrs(); + campaignOrsEntity.setUserId(userId); + campaignOrsEntity.setCreatedBy(userName); + campaignOrsEntity.setUpdatedBy(userName); + campaignOrsEntity.setStartDate(campaignDTO.getFields().getStartDate()); + campaignOrsEntity.setEndDate(campaignDTO.getFields().getEndDate()); + + try { + String familiesStr = campaignDTO.getFields().getNumberOfFamilies(); + if (familiesStr != null && !familiesStr.trim().isEmpty()) { + double familiesDouble = Double.parseDouble(familiesStr); + campaignOrsEntity.setNumberOfFamilies((int) familiesDouble); + } else { + campaignOrsEntity.setNumberOfFamilies(0); // default 0 + } + } catch (NumberFormatException e) { + throw new IEMRException("Invalid number format for families: " + campaignDTO.getFields().getNumberOfFamilies()); + } + + OrsCampaignListDTO campaignListDTO = campaignDTO.getFields(); + + if(campaignListDTO!=null){ + String photosJson = objectMapper.writeValueAsString(campaignListDTO.getCampaignPhotos()); + campaignOrsEntity.setCampaignPhotos(photosJson); + } + + campaignOrsRequest.add(campaignOrsEntity); + } + + if (!campaignOrsRequest.isEmpty()) { + List savedCampaigns = orsCampaignRepo.saveAll(campaignOrsRequest); + savedCampaigns.forEach(ors->{ + checkMonthlyPulseOrsDistribution(ors.getUserId(),ors.getStartDate(),ors.getEndDate()); + }); + return savedCampaigns; + } + + return Collections.emptyList(); + } + + @Override + public List getOrsCampaign(String token) throws IEMRException { + Integer userId = jwtUtil.extractUserId(token); + List orsCampaignDTOSResponse = new ArrayList<>(); + int page = 0; + int pageSize = 10; + Page campaignOrsPage; + do { + Pageable pageable = PageRequest.of(page, pageSize); + campaignOrsPage = orsCampaignRepo.findByUserId(userId, pageable); + for (CampaignOrs campaignOrs : campaignOrsPage.getContent()) { + OrsCampaignResponseDTO dto = convertOrsToDTO(campaignOrs); + orsCampaignDTOSResponse.add(dto); + } + page++; + } while (campaignOrsPage.hasNext()); + return orsCampaignDTOSResponse; + } + + + @Override + @Transactional + public List savePolioCampaign(List polioCampaignDTOs, String token) + throws IEMRException, JsonProcessingException { + + if (polioCampaignDTOs == null || polioCampaignDTOs.isEmpty()) { + throw new IEMRException("Campaign data is required"); + } + + List campaignPolioRequest = new ArrayList<>(); + Integer userId = jwtUtil.extractUserId(token); + String userName = userServiceRoleRepo.getUserNamedByUserId(userId); + + for (PolioCampaignDTO campaignDTO : polioCampaignDTOs) { + if (campaignDTO.getFields() == null) { + continue; + } + + PulsePolioCampaign campaignPolioEntity = new PulsePolioCampaign(); + campaignPolioEntity.setUserId(userId); + campaignPolioEntity.setCreatedBy(userName); + campaignPolioEntity.setUpdatedBy(userName); + + // Set start and end dates + campaignPolioEntity.setStartDate(campaignDTO.getFields().getStartDate()); + campaignPolioEntity.setEndDate(campaignDTO.getFields().getEndDate()); + + // Parse number of children + try { + String childrenStr = campaignDTO.getFields().getNumberOfChildren(); + if (childrenStr != null && !childrenStr.trim().isEmpty()) { + try { + // parse as double first, then cast to int + double childrenDouble = Double.parseDouble(childrenStr); + campaignPolioEntity.setNumberOfChildren((int) childrenDouble); + } catch (NumberFormatException e) { + campaignPolioEntity.setNumberOfChildren(0); // default 0 if invalid + } + } else { + campaignPolioEntity.setNumberOfChildren(0); + } + } catch (NumberFormatException e) { + throw new IEMRException("Invalid number format for children: " + e.getMessage()); + } + + // Convert photos to base64 JSON array + + PolioCampaignListDTO polioCampaignListDTO = campaignDTO.getFields(); + if(polioCampaignListDTO!=null){ + String photosJson = objectMapper.writeValueAsString(polioCampaignListDTO.getCampaignPhotos()); + campaignPolioEntity.setCampaignPhotos(photosJson); + + + } + + campaignPolioRequest.add(campaignPolioEntity); + } + + if (!campaignPolioRequest.isEmpty()) { + List savedCampaigns = pulsePolioCampaignRepo.saveAll(campaignPolioRequest); + savedCampaigns.forEach(this::checkIncentiveForPulsePolio); + + return savedCampaigns; + } + + throw new IEMRException("No valid campaign data to save"); + } + + private void checkIncentiveForPulsePolio(PulsePolioCampaign pulsePolioCampaign){ + checkMonthlyPulsePolioIncentive(pulsePolioCampaign.getUserId(),pulsePolioCampaign.getStartDate(),pulsePolioCampaign.getEndDate()); + + } + + @Override + @Transactional + public List saveFilariasisCampaign(List filariasisCampaignDTOS, String token) throws IEMRException, JsonProcessingException { + + if (filariasisCampaignDTOS == null || filariasisCampaignDTOS.isEmpty()) { + throw new IEMRException("Campaign data is required"); + } + + List campaignPolioRequest = new ArrayList<>(); + Integer userId = jwtUtil.extractUserId(token); + String userName = userServiceRoleRepo.getUserNamedByUserId(userId); + + for (FilariasisCampaignDTO campaignDTO : filariasisCampaignDTOS) { + if (campaignDTO.getFields() == null) { + continue; + } + + FilariasisCampaign filariasisCampaign = new FilariasisCampaign(); + filariasisCampaign.setUserId(userId); + filariasisCampaign.setCreatedBy(userName); + filariasisCampaign.setUpdatedBy(userName); + + // Set start and end dates + filariasisCampaign.setStartDate(campaignDTO.getFields().getStartDate()); + filariasisCampaign.setEndDate(campaignDTO.getFields().getEndDate()); + + // Parse number of children + try { + String numberOfFamilies = (campaignDTO != null && campaignDTO.getFields() != null) + ? campaignDTO.getFields().getNumberOfFamilies() + : null; + + String numberOfIndividuals = (campaignDTO != null && campaignDTO.getFields() != null) + ? campaignDTO.getFields().getNumberOfIndividuals() + : null; + if (numberOfFamilies != null && !numberOfFamilies.trim().isEmpty()) { + try { + // parse as double first, then cast to int + double noDouble = Double.parseDouble(numberOfFamilies); + filariasisCampaign.setNumberOfFamilies((int) noDouble); + } catch (NumberFormatException e) { + filariasisCampaign.setNumberOfFamilies(0); // default 0 if invalid + } + } else { + filariasisCampaign.setNumberOfFamilies(0); + } + + if (numberOfIndividuals != null && !numberOfIndividuals.trim().isEmpty()) { + try { + // parse as double first, then cast to int + double noDouble = Double.parseDouble(numberOfIndividuals); + filariasisCampaign.setNumberOfIndividuals((int) noDouble); + } catch (NumberFormatException e) { + filariasisCampaign.setNumberOfIndividuals(0); // default 0 if invalid + } + } else { + filariasisCampaign.setNumberOfIndividuals(0); + } + } catch (NumberFormatException e) { + throw new IEMRException("Invalid number format for children: " + e.getMessage()); + } + + // Convert photos to base64 JSON array + FilariasisCampaignListDTO filariasisCampaignListDTO = campaignDTO.getFields(); + if(filariasisCampaignListDTO!=null){ + String photosJson = objectMapper.writeValueAsString(filariasisCampaignListDTO.getMdaPhotos()); + filariasisCampaign.setCampaignPhotos(photosJson); + + + } + + campaignPolioRequest.add(filariasisCampaign); + } + + if (!campaignPolioRequest.isEmpty()) { + List savedCampaigns = filariasisCampaignRepo.saveAll(campaignPolioRequest); + + savedCampaigns.forEach(filariasisCampaign -> { + checkMonthlyFilariasisIncentive(filariasisCampaign.getUserId(),filariasisCampaign.getStartDate(),filariasisCampaign.getEndDate()); + + });{ + + } + return savedCampaigns; + } + + throw new IEMRException("No valid campaign data to save"); + } + + + + @Override + public List getPolioCampaign(String token) throws IEMRException { + Integer userId = jwtUtil.extractUserId(token); + List polioCampaignDTOSResponse = new ArrayList<>(); + int page = 0; + int pageSize = 10; + Page campaignPolioPage; + do { + Pageable pageable = PageRequest.of(page, pageSize); + campaignPolioPage = pulsePolioCampaignRepo.findByUserId(userId, pageable); + for (PulsePolioCampaign campaignOrs : campaignPolioPage.getContent()) { + PolioCampaignResponseDTO dto = convertPolioToDTO(campaignOrs); + polioCampaignDTOSResponse.add(dto); + + } + page++; + } while (campaignPolioPage.hasNext()); + return polioCampaignDTOSResponse; + } + + @Override + public List getAllFilariasisCampaign(String token) throws IEMRException { + Integer userId = jwtUtil.extractUserId(token); + List filariasisResponseDTOS = new ArrayList<>(); + int page = 0; + int pageSize = 10; + Page campaignPolioPage; + do { + Pageable pageable = PageRequest.of(page, pageSize); + campaignPolioPage = filariasisCampaignRepo.findByUserId(userId, pageable); + for (FilariasisCampaign campaignOrs : campaignPolioPage.getContent()) { + FilariasisResponseDTO dto = convertFilariasisDTO(campaignOrs); + filariasisResponseDTOS.add(dto); + } + page++; + } while (campaignPolioPage.hasNext()); + return filariasisResponseDTOS; + } + + + private OrsCampaignResponseDTO convertOrsToDTO(CampaignOrs campaign) { + OrsCampaignResponseDTO dto = new OrsCampaignResponseDTO(); + OrsCampaignListResponseDTO orsCampaignListDTO = new OrsCampaignListResponseDTO(); + if (campaign.getCampaignPhotos() != null) { + ObjectMapper objectMapper = new ObjectMapper(); + List photosList = new ArrayList<>(); + + String photoStr = campaign.getCampaignPhotos(); + + if (photoStr != null && !photoStr.trim().isEmpty()) { + try { + // try JSON list + photosList = objectMapper.readValue( + photoStr, + new TypeReference>() {} + ); + } catch (Exception e) { + // fallback: single image + photosList.add(photoStr.trim()); + } + } + orsCampaignListDTO.setCampaignPhotos(photosList); + } + orsCampaignListDTO.setEndDate(campaign.getEndDate()); + orsCampaignListDTO.setStartDate(campaign.getStartDate()); + orsCampaignListDTO.setNumberOfFamilies(Double.valueOf(campaign.getNumberOfFamilies())); + dto.setId(campaign.getId()); + dto.setFields(orsCampaignListDTO); + + return dto; + } + + private PolioCampaignResponseDTO convertPolioToDTO(PulsePolioCampaign campaign) { + PolioCampaignResponseDTO dto = new PolioCampaignResponseDTO(); + PolioCampaignListResponseDTO polioCampaignListDTO = new PolioCampaignListResponseDTO(); + if (campaign.getCampaignPhotos() != null) { + List photosList = new ArrayList<>(); + + String photoStr = campaign.getCampaignPhotos(); + + if (photoStr != null && !photoStr.trim().isEmpty()) { + try { + // try JSON list + photosList = objectMapper.readValue( + photoStr, + new TypeReference>() {} + ); + } catch (Exception e) { + // fallback: single image + photosList.add(photoStr.trim()); + } + } + + polioCampaignListDTO.setCampaignPhotos(photosList); + } + polioCampaignListDTO.setEndDate(campaign.getEndDate()); + polioCampaignListDTO.setStartDate(campaign.getStartDate()); + polioCampaignListDTO.setNumberOfChildren(Double.valueOf(campaign.getNumberOfChildren())); + dto.setId(campaign.getId()); + dto.setFields(polioCampaignListDTO); + return dto; + } + + private FilariasisResponseDTO convertFilariasisDTO(FilariasisCampaign campaign) { + FilariasisResponseDTO dto = new FilariasisResponseDTO(); + FilariasisCampaignListResponseDTO filariasisCampaignListDTO = new FilariasisCampaignListResponseDTO(); + if (campaign.getCampaignPhotos() != null) { + List photosList = new ArrayList<>(); + String photoStr = campaign.getCampaignPhotos(); + + if (photoStr != null && !photoStr.trim().isEmpty()) { + try { + // try JSON list + photosList = objectMapper.readValue( + photoStr, + new TypeReference>() {} + ); + } catch (Exception e) { + // fallback: single image + photosList.add(photoStr.trim()); + } + } + + filariasisCampaignListDTO.setMdaPhotos(photosList); + } + filariasisCampaignListDTO.setEndDate(campaign.getEndDate()); + filariasisCampaignListDTO.setStartDate(campaign.getStartDate()); + Double numberOfIndividuals = null; + Double numberOfFamilies = null; + + if (campaign.getNumberOfIndividuals() != null) { + numberOfIndividuals = Double.valueOf(campaign.getNumberOfIndividuals()); + } + + if (campaign.getNumberOfFamilies() != null) { + numberOfFamilies = Double.valueOf(campaign.getNumberOfFamilies()); + } + + filariasisCampaignListDTO.setNumberOfIndividuals(numberOfIndividuals); + filariasisCampaignListDTO.setNumberOfFamilies(numberOfFamilies); + + dto.setFields(filariasisCampaignListDTO); + return dto; + } + private List parseBase64Json(String jsonString) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(jsonString, new TypeReference>() {}); + } catch (JsonProcessingException e) { + return Collections.emptyList(); + } + } + + private void checkMonthlyPulsePolioIncentive(Integer ashaId,LocalDate startDate,LocalDate endDate) { + + IncentiveActivity CHILD_MOBILIZATION_SESSIONS = incentivesRepo.findIncentiveMasterByNameAndGroup("PULSE_POLIO_SUPPORT", GroupName.ACTIVITY.getDisplayName()); + if (CHILD_MOBILIZATION_SESSIONS != null) { + addAshaIncentiveRecord(CHILD_MOBILIZATION_SESSIONS, ashaId,startDate,endDate); + } + + } + + private void checkMonthlyFilariasisIncentive(Integer ashaId,LocalDate startDate,LocalDate endDate) { + IncentiveActivity FILARIASIS_MEDICINE_DISTRIBUTION = incentivesRepo.findIncentiveMasterByNameAndGroup("FILARIASIS_MEDICINE_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); + if (FILARIASIS_MEDICINE_DISTRIBUTION != null) { + addAshaIncentiveRecord(FILARIASIS_MEDICINE_DISTRIBUTION, ashaId,startDate,endDate); + } + + } + + private void checkMonthlyPulseOrsDistribution(Integer ashaId,LocalDate startDate,LocalDate endDate) { + IncentiveActivity ORS_DISTRIBUTION = incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); + if (ORS_DISTRIBUTION != null) { + addAshaIncentiveRecord(ORS_DISTRIBUTION, ashaId,startDate,endDate); + } + + } + + private void addAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId,LocalDate startDate,LocalDate endDate) { + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + + Timestamp startOfMonth = Timestamp.valueOf(startDate.atStartOfDay()); + Timestamp endOfMonth = Timestamp.valueOf(endDate.atStartOfDay()); + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + 0L, + ashaId, + startOfMonth, + endOfMonth + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(timestamp); + record.setCreatedBy(userServiceRoleRepo.getUserNamedByUserId(ashaId)); + record.setStartDate(timestamp); + record.setEndDate(timestamp); + record.setUpdatedDate(timestamp); + record.setUpdatedBy(userServiceRoleRepo.getUserNamedByUserId(ashaId)); + record.setBenId(0L); + record.setAshaId(ashaId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } + +} + diff --git a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java index 43a9eb1f..e65e0f53 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildCareServiceImpl.java @@ -3,19 +3,28 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.ChildCareService; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; +import jakarta.persistence.EntityNotFoundException; import org.aspectj.weaver.ast.Or; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -75,6 +84,19 @@ public class ChildCareServiceImpl implements ChildCareService { @Autowired private OrsDistributionRepo orsDistributionRepo; + @Autowired + private IncentivePendingActivityRepository incentivePendingActivityRepository; + + @Autowired + private UserService userService; + + @Autowired + private IncentiveLogicService incentiveLogicService; + + @Autowired + private ANCVisitRepo ancVisitRepo; + @Autowired + private PNCVisitRepo pncVisitRepo; @Override @@ -82,6 +104,7 @@ public String registerHBYC(List hbycDTOs) { try { List hbycList = new ArrayList<>(); + hbycDTOs.forEach(it -> { HbycDTO hbycDTO = it.getFields(); hbycDTO.setVisit_date(it.getVisitDate()); @@ -90,14 +113,11 @@ public String registerHBYC(List hbycDTOs) { if (hbyc != null) { Long id = hbyc.getId(); - modelMapper.map(it, hbycDTO); hbyc.setId(id); hbyc.setUserId(userRepo.getUserIdByName(it.getUserName())); hbyc.setCreated_by(it.getUserName()); } else { hbyc = new HbycChildVisit(); - modelMapper.map(it, hbycDTO); - hbyc.setId(null); hbyc.setUserId(userRepo.getUserIdByName(it.getUserName())); hbyc.setCreated_by(it.getUserName()); hbyc.setBeneficiaryId(it.getBeneficiaryId()); @@ -134,14 +154,17 @@ public String registerHBYC(List hbycDTOs) { hbyc.setMcp_card_images(hbycDTO.getMcp_card_images()); } + hbycList.add(hbyc); }); hbycRepo.saveAll(hbycList); + logger.info("Total records to save : {}", hbycList.size()); checkAndAddHbyncIncentives(hbycList); return "no of hbyc details saved: " + hbycDTOs.size(); } catch (Exception e) { - logger.info("error while saving hbyc details: " + e.getMessage()); + logger.error("error while saving hbyc details", e); + } return null; } @@ -210,46 +233,62 @@ public List getHbycRecords(GetBenRequestHandler dto) { @Override public List getHBNCDetails(GetBenRequestHandler dto) { List result = new ArrayList<>(); + int page = 0; + int size = 20; + + Page visitPage; try { - List hbncVisits = hbncVisitRepo.findByAshaId(dto.getAshaId()); + do { + Pageable pageable = PageRequest.of(page, size, Sort.by("id").descending()); - for (HbncVisit visit : hbncVisits) { - HbncVisitResponseDTO responseDTO = new HbncVisitResponseDTO(); - responseDTO.setId(visit.getId()); - responseDTO.setBeneficiaryId(visit.getBeneficiaryId()); // Update with actual value - responseDTO.setHouseHoldId(visit.getHouseHoldId()); // Update with actual value - responseDTO.setVisitDate(visit.getVisit_date().split(" ")[0]); // Format visit.getVisitDate() + visitPage = hbncVisitRepo.findByAshaId(dto.getAshaId(), pageable); - // Convert all fields to Map - Map fields = new HashMap<>(); - addIfValid(fields, "visit_day", visit.getVisit_day()); - addIfValid(fields, "due_date", visit.getDue_date()); - addIfValid(fields, "is_baby_alive", convert(visit.getIs_baby_alive())); - addIfValid(fields, "date_of_death", visit.getDate_of_death()); - addIfValid(fields, "reason_for_death", visit.getReasonForDeath()); - addIfValid(fields, "place_of_death", visit.getPlace_of_death()); - addIfValid(fields, "other_place_of_death", visit.getOther_place_of_death()); - addIfValid(fields, "baby_weight", visit.getBaby_weight()); - addIfValid(fields, "urine_passed", convert(visit.getUrine_passed())); - addIfValid(fields, "stool_passed", convert(visit.getStool_passed())); - addIfValid(fields, "diarrhoea", convert(visit.getDiarrhoea())); - addIfValid(fields, "vomiting", convert(visit.getVomiting())); - addIfValid(fields, "convulsions", convert(visit.getConvulsions())); - addIfValid(fields, "activity", visit.getActivity()); - addIfValid(fields, "sucking", visit.getSucking()); - addIfValid(fields, "breathing", visit.getBreathing()); - addIfValid(fields, "chest_indrawing", visit.getChest_indrawing()); - addIfValid(fields, "temperature", visit.getTemperature()); - addIfValid(fields, "jaundice", convert(visit.getJaundice())); - addIfValid(fields, "umbilical_stump", visit.getUmbilical_stump()); - addIfValid(fields, "discharged_from_sncu", convert(visit.getDischarged_from_sncu())); - addIfValid(fields, "discharge_summary_upload", visit.getDischarge_summary_upload()); - - // Add more fields as required - - responseDTO.setFields(fields); - result.add(responseDTO); - } + List hbncVisits = visitPage.getContent(); + + for (HbncVisit visit : hbncVisits) { + HbncVisitResponseDTO responseDTO = new HbncVisitResponseDTO(); + responseDTO.setId(visit.getId()); + responseDTO.setBeneficiaryId(visit.getBeneficiaryId()); // Update with actual value + responseDTO.setHouseHoldId(visit.getHouseHoldId()); // Update with actual value + responseDTO.setVisitDate(visit.getVisit_date().split(" ")[0]); // Format visit.getVisitDate() + + // Convert all fields to Map + Map fields = new HashMap<>(); + if(visit.getVisit_day()!=null){ + addIfValid(fields, "visit_day", visit.getVisit_day()); + + } + addIfValid(fields, "due_date", visit.getDue_date()); + addIfValid(fields, "is_baby_alive", convert(visit.getIs_baby_alive())); + addIfValid(fields, "date_of_death", visit.getDate_of_death()); + addIfValid(fields, "reason_for_death", visit.getReasonForDeath()); + addIfValid(fields, "place_of_death", visit.getPlace_of_death()); + addIfValid(fields, "other_place_of_death", visit.getOther_place_of_death()); + addIfValid(fields, "baby_weight", visit.getBaby_weight()); + addIfValid(fields, "urine_passed", convert(visit.getUrine_passed())); + addIfValid(fields, "stool_passed", convert(visit.getStool_passed())); + addIfValid(fields, "diarrhoea", convert(visit.getDiarrhoea())); + addIfValid(fields, "vomiting", convert(visit.getVomiting())); + addIfValid(fields, "convulsions", convert(visit.getConvulsions())); + addIfValid(fields, "activity", visit.getActivity()); + addIfValid(fields, "sucking", visit.getSucking()); + addIfValid(fields, "breathing", visit.getBreathing()); + addIfValid(fields, "chest_indrawing", visit.getChest_indrawing()); + addIfValid(fields, "temperature", visit.getTemperature()); + addIfValid(fields, "jaundice", convert(visit.getJaundice())); + addIfValid(fields, "umbilical_stump", visit.getUmbilical_stump()); + addIfValid(fields, "discharged_from_sncu", convert(visit.getDischarged_from_sncu())); + addIfValid(fields, "discharge_summary_upload", visit.getDischarge_summary_upload()); + + // Add more fields as required + + responseDTO.setFields(fields); + result.add(responseDTO); + + } + page++; + + }while (visitPage.hasNext()); } catch (Exception e) { logger.error("Error in getHBNCDetails: ", e); @@ -271,8 +310,8 @@ private String convert(Boolean value) { } private Boolean convertBollen(String value) { - if (value.equals("Yes")) { - return true; + if (value != null && !value.isEmpty()) { + return value.equalsIgnoreCase("Yes"); } else { return false; } @@ -291,7 +330,7 @@ private String convert(String value) { @Override - public String saveHBNCDetails(List hbncRequestDTOs) { + public String saveHBNCDetails(List hbncRequestDTOs, Integer userId) { try { List hbncList = new ArrayList<>(); @@ -321,7 +360,7 @@ public String saveHBNCDetails(List hbncRequestDTOs) { hbncVisitRepo.saveAll(hbncList); - checkAndAddHbncIncentives(hbncList); + checkAndAddHbncIncentives(hbncList, userId); logger.info("HBNC details saved"); @@ -341,11 +380,18 @@ public List getChildVaccinationDetails(GetBenRequestHandler List result = new ArrayList<>(); vaccinationDetails.forEach(childVaccination -> { ChildVaccinationDTO vaccinationDTO = mapper.convertValue(childVaccination, ChildVaccinationDTO.class); - BigInteger benId = beneficiaryRepo.getBenIdFromRegID(childVaccination.getBeneficiaryRegId()); - vaccinationDTO.setBeneficiaryId(benId.longValue()); + if(childVaccination.getBeneficiaryRegId()!=null){ + BigInteger benId = beneficiaryRepo.getBenIdFromRegID(childVaccination.getBeneficiaryRegId()); + vaccinationDTO.setBeneficiaryId(benId.longValue()); + + } + if(!vaccinationDetails.isEmpty()){ + checkAndAddIncentives(vaccinationDetails); + + } + result.add(vaccinationDTO); - checkAndAddIncentives(vaccinationDetails); }); return result; } catch (Exception e) { @@ -377,7 +423,10 @@ public String saveChildVaccinationDetails(List childVaccina vaccinationList.add(vaccination); }); childVaccinationRepo.saveAll(vaccinationList); - checkAndAddIncentives(vaccinationList); + if(!vaccinationList.isEmpty()){ + checkAndAddIncentives(vaccinationList); + + } logger.info("Child Vaccination details saved"); return "No of child vaccination details saved: " + vaccinationList.size(); } catch (Exception e) { @@ -436,7 +485,7 @@ public List getAllChildVaccines(String category) { } @Override - public String saveSamDetails(List samRequest) { + public String saveSamDetails(List samRequest, Integer userId, String userName) { try { List vaccinationList = new ArrayList<>(); @@ -457,11 +506,9 @@ public String saveSamDetails(List samRequest) { samVisit.setVisitDate(LocalDate.parse(samDTO.getVisitDate())); // ✅ Common user details - samVisit.setUserId(userRepo.getUserIdByName(jwtUtil.getUserNameFromStorage())); - samVisit.setCreatedBy(jwtUtil.getUserNameFromStorage()); - if (samVisit.getCreatedBy() == null) { - samVisit.setCreatedBy(jwtUtil.getUserNameFromStorage()); - } + samVisit.setUserId(userId); + samVisit.setCreatedBy(userName); + // ✅ Field mapping samVisit.setMuac(samDTO.getFields().getMuac()); @@ -491,7 +538,7 @@ public String saveSamDetails(List samRequest) { samVisitRepository.saveAll(vaccinationList); // ✅ Handle incentive logic - checkAndAddSamVisitNRCReferalIncentive(vaccinationList); + checkAndAddSamVisitNRCReferalIncentive(vaccinationList, userId); return "Saved/Updated " + samRequest.size() + " SAM visit records successfully"; } catch (Exception e) { @@ -531,8 +578,10 @@ public List getSamVisitsByBeneficiary(GetBenRequestHandler reque // ✅ Final Visit Label dto.setVisitLabel("Visit-" + visitNo); - - dto.setMuac(Double.parseDouble(entity.getMuac())); + String muacVal = entity.getMuac(); + dto.setMuac((muacVal != null && !muacVal.trim().isEmpty()) + ? Double.parseDouble(muacVal.trim()) + : 0.0); dto.setWeightForHeightStatus(entity.getWeightForHeightStatus()); dto.setIsChildReferredNrc(entity.getIsChildReferredNrc()); dto.setIsChildAdmittedNrc(entity.getIsChildAdmittedNrc()); @@ -544,7 +593,8 @@ public List getSamVisitsByBeneficiary(GetBenRequestHandler reque try { List followUpDates = mapper.readValue( entity.getFollowUpVisitDate(), - new TypeReference>() {}); + new TypeReference>() { + }); dto.setFollowUpVisitDate(followUpDates); } catch (JsonProcessingException e) { throw new RuntimeException(e); @@ -559,13 +609,13 @@ public List getSamVisitsByBeneficiary(GetBenRequestHandler reque } - return samResponseListDTO; } @Override public String saveOrsDistributionDetails(List orsDistributionDTOS) { try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); List orsDistributionList = new ArrayList<>(); orsDistributionDTOS.forEach(orsDistributionDTO -> { @@ -573,28 +623,31 @@ public String saveOrsDistributionDetails(List orsDistributio orsDistribution.setId(orsDistributionDTO.getId()); orsDistribution.setBeneficiaryId(orsDistributionDTO.getBeneficiaryId()); orsDistribution.setNumOrsPackets(orsDistributionDTO.getFields().getNum_ors_packets().toString()); - orsDistribution.setChildCount(orsDistributionDTO.getFields().getNum_under5_children().toString()); + if (orsDistributionDTO.getFields().getNum_under5_children() != null) { + orsDistribution.setChildCount(orsDistributionDTO.getFields().getNum_under5_children().toString()); + + } orsDistribution.setHouseholdId(orsDistributionDTO.getHouseHoldId()); orsDistribution.setUserId(userRepo.getUserIdByName(orsDistributionDTO.getUserName())); - orsDistribution.setVisitDate(LocalDate.parse(orsDistributionDTO.getFields().getVisit_date(),formatter)); + orsDistribution.setVisitDate(LocalDate.parse(orsDistributionDTO.getFields().getVisit_date(), formatter)); orsDistributionList.add(orsDistribution); }); - logger.info("orsList"+orsDistributionList.size()); - if(!orsDistributionList.isEmpty()){ + logger.info("orsList" + orsDistributionList.size()); + if (!orsDistributionList.isEmpty()) { orsDistributionRepo.saveAll(orsDistributionList); checkAndAddOrdDistributionIncentive(orsDistributionList); return "Saved " + orsDistributionList.size() + " ORS visit records successfully"; } - }catch (Exception e){ - logger.error("ORS Error"+e); + } catch (Exception e) { + logger.error("ORS Error" + e); } - return null ; + return null; } @@ -603,23 +656,28 @@ public List getOrdDistrubtion(GetBenRequestHandler r List entities = orsDistributionRepo.findByUserId(request.getAshaId()); List orsDistributionResponseDTOSList = new ArrayList<>(); - for(OrsDistribution orsDistribution: entities){ + for (OrsDistribution orsDistribution : entities) { OrsDistributionResponseDTO orsDistributionResponseDTO = new OrsDistributionResponseDTO(); OrsDistributionResponseListDTO orsDistributionResponseListDTO = new OrsDistributionResponseListDTO(); orsDistributionResponseDTO.setId(orsDistribution.getId()); orsDistributionResponseDTO.setBeneficiaryId(orsDistribution.getBeneficiaryId()); orsDistributionResponseDTO.setHouseHoldId(orsDistribution.getHouseholdId()); - orsDistributionResponseListDTO.setNum_ors_packets(orsDistribution.getNumOrsPackets().toString()); - orsDistributionResponseListDTO.setNum_under5_children(orsDistribution.getChildCount().toString()); + if (orsDistribution.getNumOrsPackets() != null) { + orsDistributionResponseListDTO.setNum_ors_packets(orsDistribution.getNumOrsPackets().toString()); + + } + if (orsDistribution.getChildCount() != null) { + orsDistributionResponseListDTO.setNum_under5_children(orsDistribution.getChildCount().toString()); + + } orsDistributionResponseDTO.setFields(orsDistributionResponseListDTO); orsDistributionResponseDTO.setVisitDate(parseDate(orsDistribution.getVisitDate().toString()).toString()); orsDistributionResponseDTOSList.add(orsDistributionResponseDTO); - } - return orsDistributionResponseDTOSList; + return orsDistributionResponseDTOSList; } @@ -633,30 +691,75 @@ private LocalDate parseDate(String dateStr) { for (DateTimeFormatter f : formatters) { try { return LocalDate.parse(dateStr, f); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } } throw new DateTimeParseException("Invalid date format: " + dateStr, dateStr, 0); } + @Override - public List saveAllIfa(List dtoList) { - return dtoList.stream() - .map(this::mapToEntity) + public List saveAllIfa(List dtoList, Integer userId) { + List savedList = dtoList.stream() + .map(dto -> mapToEntity(dto, userId)) .map(ifaDistributionRepository::save) .toList(); - } + // incentive generate + savedList.forEach(data -> { + Timestamp visitTimestamp = + Timestamp.valueOf(data.getIfaProvisionDate().atStartOfDay()); + if(data.getIfaBottleCount().equals("10.0")){ + incentiveLogicService.incentiveForGiveingIFA( + data.getBeneficiaryId(), + visitTimestamp, + visitTimestamp, + data.getUserId() + ); + } + + }); + + return savedList; + } @Override public List getByBeneficiaryId(GetBenRequestHandler requestHandler) { - return ifaDistributionRepository.findByUserId(requestHandler.getAshaId()).stream() - .map(this::mapToDTO) + + return ifaDistributionRepository.findByUserId(requestHandler.getAshaId()) + .stream() + .map(data -> { + + try { + if ("10.0".equals(data.getIfaBottleCount())) { + + Timestamp visitTimestamp = + Timestamp.valueOf(data.getIfaProvisionDate().atStartOfDay()); + + incentiveLogicService.incentiveForGiveingIFA( + data.getBeneficiaryId(), + visitTimestamp, + visitTimestamp, + data.getUserId() + ); + } + } catch (Exception e) { + logger.error( + "Error while processing IFA incentive for beneficiaryId: {}", + data.getBeneficiaryId(), + e + ); + } + + return mapToDTO(data); + }) .toList(); } + // 🔁 Entity → DTO (date formatted as dd-MM-yyyy) private IfaDistributionDTO mapToDTO(IfaDistribution entity) { - final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); IfaDistributionDTO dto = new IfaDistributionDTO(); @@ -678,7 +781,7 @@ private IfaDistributionDTO mapToDTO(IfaDistribution entity) { } // 🔄 Helper method to convert DTO → Entity - private IfaDistribution mapToEntity(IfaDistributionDTO dto) { + private IfaDistribution mapToEntity(IfaDistributionDTO dto, Integer userId) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); IfaDistribution entity = new IfaDistribution(); @@ -687,7 +790,7 @@ private IfaDistribution mapToEntity(IfaDistributionDTO dto) { entity.setHouseHoldId(dto.getHouseHoldId()); entity.setFormId(dto.getFormId()); entity.setVisitDate(dto.getVisitDate()); - entity.setUserId(userRepo.getUserIdByName(jwtUtil.getUserNameFromStorage())); + entity.setUserId(userId); if (dto.getFields() != null) { if (dto.getFields().getIfa_provision_date() != null) { @@ -707,20 +810,25 @@ private IfaDistribution mapToEntity(IfaDistributionDTO dto) { return entity; } - private void checkAndAddSamVisitNRCReferalIncentive(List samVisits){ + private void checkAndAddSamVisitNRCReferalIncentive(List samVisits, Integer userId) { samVisits.forEach(samVisit -> { IncentiveActivity samreferralnrcActivityAm = incentivesRepo.findIncentiveMasterByNameAndGroup("SAM_REFERRAL_NRC", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity samreferralnrcActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("SAM_REFERRAL_NRC", GroupName.ACTIVITY.getDisplayName()); - if(samreferralnrcActivityAm!=null){ - if(samVisit.getIsChildReferredNrc().equals("Yes")){ - createIncentiveRecordforSamReferalToNrc(samVisit,samVisit.getBeneficiaryId(),samreferralnrcActivityAm,jwtUtil.getUserNameFromStorage()); + IncentiveActivity samreferralnrcActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("SAM_REFERRAL_NRC", GroupName.ACTIVITY.getDisplayName()); + if (userService.getUserDetail(userId).getStateId().equals(StateCode.AM.getStateCode())) { + + if (samreferralnrcActivityAm != null) { + if (samVisit.getIsChildReferredNrc().equals("Yes")) { + createIncentiveRecordforSamReferalToNrc(samVisit, samVisit.getBeneficiaryId(), samreferralnrcActivityAm, samVisit.getCreatedBy()); + } } } - if(samreferralnrcActivityCH!=null){ - if(samVisit.getIsChildReferredNrc().equals("Yes")){ - createIncentiveRecordforSamReferalToNrc(samVisit,samVisit.getBeneficiaryId(),samreferralnrcActivityCH,jwtUtil.getUserNameFromStorage()); + if (userService.getUserDetail(userId).getStateId().equals(StateCode.CG.getStateCode())) { + if (samreferralnrcActivityCH != null) { + if (samVisit.getIsChildReferredNrc().equals("Yes")) { + createIncentiveRecordforSamReferalToNrc(samVisit, samVisit.getBeneficiaryId(), samreferralnrcActivityCH, samVisit.getCreatedBy()); + } } } @@ -728,20 +836,14 @@ private void checkAndAddSamVisitNRCReferalIncentive(List samVisits){ }); } - private void checkAndAddOrdDistributionIncentive(List orsDistributionList){ + + private void checkAndAddOrdDistributionIncentive(List orsDistributionList) { orsDistributionList.forEach(orsDistribution -> { IncentiveActivity orsPacketActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity orsPacketActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); - if(orsPacketActivityAM!=null){ - if(orsDistribution.getNumOrsPackets()!=null){ - createIncentiveRecordforOrsDistribution(orsDistribution,orsDistribution.getBeneficiaryId(),orsPacketActivityAM,userRepo.getUserNamedByUserId(orsDistribution.getUserId()),false); - } - } - - if(orsPacketActivityCH!=null){ - if(orsDistribution.getNumOrsPackets()!=null){ - createIncentiveRecordforOrsDistribution(orsDistribution,orsDistribution.getBeneficiaryId(),orsPacketActivityCH,userRepo.getUserNamedByUserId(orsDistribution.getUserId()),true); + if (orsPacketActivityAM != null) { + if (orsDistribution.getNumOrsPackets() != null) { + createIncentiveRecordforOrsDistribution(orsDistribution, orsDistribution.getBeneficiaryId(), orsPacketActivityAM, userRepo.getUserNamedByUserId(orsDistribution.getUserId()), false); } } @@ -751,74 +853,89 @@ private void checkAndAddOrdDistributionIncentive(List orsDistr } private void checkAndAddHbyncIncentives(List hbycList) { - IncentiveActivity hbync15MonethVisitActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity hbyncVisitActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.CHILD_HEALTH.getDisplayName()); + if(!hbycList.isEmpty()){ + Integer userId = hbycList.get(0).getUserId(); + Integer stateId = userService.getUserDetail(userId).getStateId(); + IncentiveActivity hbync15MonethVisitActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity hbyncVisitActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("HBYC_QUARTERLY_VISITS", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity hbyncOrsPacketActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("ORS_DISTRIBUTION", GroupName.ACTIVITY.getDisplayName()); - hbycList.forEach(hbyc -> { - Set eligibleHbycVisits = Set.of("3 Months", "6 Months", "9 Months", "12 Months", "15 Months"); + IncentiveActivity hbyncLactatingIronPacketActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("LACTATING_MOTHERS_HOME_VISIT", GroupName.ACTIVITY.getDisplayName()); - if (hbyncVisitActivity != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { - createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncVisitActivity, hbyc.getCreated_by()); - } - - if (hbync15MonethVisitActivityCH != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { - createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbync15MonethVisitActivityCH, hbyc.getCreated_by()); - } + hbycList.forEach(hbyc -> { + Set eligibleHbycVisits = Set.of("3 Months", "6 Months", "9 Months", "12 Months", "15 Months"); + if(stateId.equals(StateCode.AM.getStateCode())){ + if (hbyncVisitActivity != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncVisitActivity, hbyc.getCreated_by()); + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ + if (hbync15MonethVisitActivityCH != null && eligibleHbycVisits.contains(hbyc.getVisit_day())) { + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbync15MonethVisitActivityCH, hbyc.getCreated_by()); + } + if(hbyc.getIfa_given() && eligibleHbycVisits.contains(hbyc.getVisit_day())){ + if(hbyncLactatingIronPacketActivityCH!=null){ + createIncentiveRecordforHbyncVisit(hbyc, hbyc.getBeneficiaryId(), hbyncLactatingIronPacketActivityCH, hbyc.getCreated_by()); + } + } + } - if (hbyncOrsPacketActivityCH != null) { - if (hbyc.getOrs_given()) { - createIncentiveRecordforHbyncOrsDistribution(hbyc, hbyc.getBeneficiaryId(), hbyncOrsPacketActivityCH, hbyc.getCreated_by()); - } - } + }); + } - }); } - private void checkAndAddHbncIncentives(List hbncVisits) { + private void checkAndAddHbncIncentives(List hbncVisits, Integer userId) { + Integer stateCode = userService.getUserDetail(userId).getStateId(); hbncVisits.forEach(hbncVisit -> { - boolean isVisitDone = List.of("1st Day", "3rd Day", "7th Day", "42nd Day") - .stream() - .allMatch(hbncVisits::contains); - - GroupName.setIsCh(false); Long benId = hbncVisit.getBeneficiaryId(); - if (hbncVisit.getVisit_day().equals("42nd Day")) { - IncentiveActivity visitActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.CHILD_HEALTH.getDisplayName()); - IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.ACTIVITY.getDisplayName()); + if (stateCode.equals(StateCode.AM.getStateCode())) { + if (hbncVisit.getVisit_day().equals("42nd Day")) { + IncentiveActivity visitActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.CHILD_HEALTH.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityAM, "HBNC_0_42_DAYS"); - createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HBNC_0_42_DAYS_CH"); + createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityAM, "HBNC_0_42_DAYS"); - } - logger.info("getDischarged_from_sncu" + hbncVisit.getDischarged_from_sncu()); + } - if (hbncVisit.getVisit_day().equals("42nd Day") && hbncVisit.getDischarged_from_sncu() && hbncVisit.getBaby_weight() <=2.5) { - IncentiveActivity babyDisChargeSNCUAActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("SNCU_LBW_FOLLOWUP", GroupName.CHILD_HEALTH.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, benId, babyDisChargeSNCUAActivity, "SNCU_LBW_FOLLOWUP"); + logger.info("getDischarged_from_sncu" + hbncVisit.getDischarged_from_sncu()); + + if (hbncVisit.getVisit_day().equals("42nd Day") && hbncVisit.getDischarged_from_sncu() && hbncVisit.getBaby_weight() <= 2.5) { + IncentiveActivity babyDisChargeSNCUAActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("SNCU_LBW_FOLLOWUP", GroupName.CHILD_HEALTH.getDisplayName()); + + createIncentiveRecordforHbncVisit(hbncVisit, benId, babyDisChargeSNCUAActivity, "SNCU_LBW_FOLLOWUP"); + + } + logger.info("getIs_baby_alive" + hbncVisit.getIs_baby_alive()); + if (!hbncVisit.getIs_baby_alive()) { + IncentiveActivity isChildDeathActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); + + createIncentiveRecordforHbncVisit(hbncVisit, benId, isChildDeathActivity, "CHILD_DEATH_REPORTING"); + } } - logger.info("getIs_baby_alive" + hbncVisit.getIs_baby_alive()); - if (!hbncVisit.getIs_baby_alive()) { - IncentiveActivity isChildDeathActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); - createIncentiveRecordforHbncVisit(hbncVisit, benId, isChildDeathActivity, "CHILD_DEATH_REPORTING"); + if (stateCode.equals(StateCode.CG.getStateCode())) { + if (hbncVisit.getVisit_day().equals("42nd Day")) { + IncentiveActivity visitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("HBNC_0_42_DAYS", GroupName.ACTIVITY.getDisplayName()); + createIncentiveRecordforHbncVisit(hbncVisit, benId, visitActivityCH, "HBNC_0_42_DAYS"); + + + } } @@ -829,59 +946,184 @@ private void checkAndAddHbncIncentives(List hbncVisits) { private void checkAndAddIncentives(List vaccinationList) { + String createdBy = vaccinationList.get(0).getCreatedBy(); - + Integer userId = userRepo.getUserIdByName(createdBy); + Integer stateId = userService.getUserDetail(userId).getStateId(); vaccinationList.forEach(vaccination -> { - Long benId = beneficiaryRepo.getBenIdFromRegID(vaccination.getBeneficiaryRegId()).longValue(); - Integer userId = userRepo.getUserIdByName(vaccination.getCreatedBy()); - Integer immunizationServiceId = getImmunizationServiceIdForVaccine(vaccination.getVaccineId().shortValue()); - if (immunizationServiceId < 6) { - IncentiveActivity immunizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FULL_IMMUNIZATION_0_1", GroupName.IMMUNIZATION.getDisplayName()); - IncentiveActivity immunizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FULL_IMMUNIZATION_0_1", GroupName.ACTIVITY.getDisplayName()); - - - if (immunizationActivityAM != null && childVaccinationRepo.getFirstYearVaccineCountForBenId(vaccination.getBeneficiaryRegId()) - .equals(childVaccinationRepo.getFirstYearVaccineCount())) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivityAM); + Long benId= null; + if(vaccination.getBeneficiaryRegId()!=null){ + BigInteger benIdObj = beneficiaryRepo.getBenIdFromRegID(vaccination.getBeneficiaryRegId()); + if (benIdObj != null) { + benId = benIdObj.longValue(); } - if (immunizationActivityCH != null && childVaccinationRepo.getFirstYearVaccineCountForBenId(vaccination.getBeneficiaryRegId()) - .equals(childVaccinationRepo.getFirstYearVaccineCount())) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivityCH); + Integer immunizationServiceId = getImmunizationServiceIdForVaccine(vaccination.getVaccineId().shortValue()); + if (immunizationServiceId < 6) { + + Integer completedVaccines = + childVaccinationRepo.getEligibleFirstYearVaccines( + vaccination.getBeneficiaryRegId()); + + + logger.info( + "FULL_IMMUNIZATION_0_1 :: BeneficiaryRegId={}, Vaccine={}, VaccineId={}, CompletedVaccines={}, StateId={}", + vaccination.getBeneficiaryRegId(), + vaccination.getVaccineName(), + vaccination.getVaccineId(), + completedVaccines, + stateId + ); + + IncentiveActivity immunizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FULL_IMMUNIZATION_0_1", + GroupName.IMMUNIZATION.getDisplayName()); + + IncentiveActivity immunizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FULL_IMMUNIZATION_0_1", + GroupName.ACTIVITY.getDisplayName()); + +// Required vaccines = 8 + if (completedVaccines != null && completedVaccines == 8) { + + logger.info( + "Beneficiary {} completed all required first year vaccines.", + vaccination.getBeneficiaryRegId()); + + if (stateId.equals(StateCode.AM.getStateCode()) + && immunizationActivityAM != null) { + + logger.info( + "Creating Assam FULL_IMMUNIZATION_0_1 incentive for BeneficiaryRegId={}", + vaccination.getBeneficiaryRegId()); + + createIncentiveRecord( + vaccination, + benId, + userId, + immunizationActivityAM); + } + + if (stateId.equals(StateCode.CG.getStateCode()) + && immunizationActivityCH != null) { + + logger.info( + "Creating Chhattisgarh FULL_IMMUNIZATION_0_1 incentive for BeneficiaryRegId={}", + vaccination.getBeneficiaryRegId()); + + createIncentiveRecord( + vaccination, + benId, + userId, + immunizationActivityCH); + } + + } else { + + logger.info( + "BeneficiaryRegId={} not eligible for FULL_IMMUNIZATION_0_1. CompletedVaccines={}/8", + vaccination.getBeneficiaryRegId(), + completedVaccines + ); + } + + } else if (immunizationServiceId == 7) { + + IncentiveActivity immunizationActivity2AM = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "COMPLETE_IMMUNIZATION_1_2", + GroupName.IMMUNIZATION.getDisplayName()); + + IncentiveActivity immunizationActivity2CH = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "COMPLETE_IMMUNIZATION_1_2", + GroupName.ACTIVITY.getDisplayName()); + + Integer completedVaccines = + childVaccinationRepo.getEligibleSecondYearVaccines( + vaccination.getBeneficiaryRegId()); + + logger.info( + "COMPLETE_IMMUNIZATION_1_2 :: BeneficiaryRegId={}, Vaccine={}, VaccineId={}, CompletedVaccines={}", + vaccination.getBeneficiaryRegId(), + vaccination.getVaccineName(), + vaccination.getVaccineId(), + completedVaccines + ); + + // Required vaccines count = 3 + if (completedVaccines != null && completedVaccines == 3) { + + logger.info( + "Beneficiary {} completed all required second year vaccines.", + vaccination.getBeneficiaryRegId()); + if(userService.getUserDetail(userId).getStateId().equals(StateCode.AM.getStateCode())) { + + if (immunizationActivity2AM != null) { + + logger.info( + "Creating IMMUNIZATION incentive for BeneficiaryRegId={}", + vaccination.getBeneficiaryRegId()); + + createIncentiveRecord( + vaccination, + benId, + userId, + immunizationActivity2AM); + } + } + if(userService.getUserDetail(userId).getStateId().equals(StateCode.CG.getStateCode())) { + + if (immunizationActivity2CH != null) { + + logger.info( + "Creating ACTIVITY incentive for BeneficiaryRegId={}", + vaccination.getBeneficiaryRegId()); + + createIncentiveRecord( + vaccination, + benId, + userId, + immunizationActivity2CH); + } + } + + } else { + + logger.info( + "BeneficiaryRegId={} not eligible. CompletedVaccines={}/3", + vaccination.getBeneficiaryRegId(), + completedVaccines); + } } - } else if (immunizationServiceId == 7) { - IncentiveActivity immunizationActivity2AM = - incentivesRepo.findIncentiveMasterByNameAndGroup("COMPLETE_IMMUNIZATION_1_2", GroupName.IMMUNIZATION.getDisplayName()); - IncentiveActivity immunizationActivity2CH = - incentivesRepo.findIncentiveMasterByNameAndGroup("COMPLETE_IMMUNIZATION_1_2", GroupName.ACTIVITY.getDisplayName()); - if (immunizationActivity2AM != null && childVaccinationRepo.getSecondYearVaccineCountForBenId(vaccination.getBeneficiaryRegId()) - .equals(childVaccinationRepo.getSecondYearVaccineCount())) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivity2AM); + IncentiveActivity immunizationActivity5AM = + incentivesRepo.findIncentiveMasterByNameAndGroup("DPT_IMMUNIZATION_5_YEARS", GroupName.IMMUNIZATION.getDisplayName()); + if(userService.getUserDetail(userId).getStateId().equals(StateCode.AM.getStateCode())) { + + if (immunizationActivity5AM != null && childVaccinationRepo.checkDptVaccinatedUser(vaccination.getBeneficiaryRegId()) == 1) { + createIncentiveRecord(vaccination, benId, userId, immunizationActivity5AM); + } } - if (immunizationActivity2CH != null && childVaccinationRepo.getSecondYearVaccineCountForBenId(vaccination.getBeneficiaryRegId()) - .equals(childVaccinationRepo.getSecondYearVaccineCount())) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivity2CH); + + IncentiveActivity immunizationActivity5CH = + incentivesRepo.findIncentiveMasterByNameAndGroup("DPT_IMMUNIZATION_5_YEARS", GroupName.ACTIVITY.getDisplayName()); + if(userService.getUserDetail(userId).getStateId().equals(StateCode.CG.getStateCode())) { + + if (immunizationActivity5CH != null && childVaccinationRepo.checkDptVaccinatedUser(vaccination.getBeneficiaryRegId()) == 1) { + createIncentiveRecord(vaccination, benId, userId, immunizationActivity5CH); + } } - } - IncentiveActivity immunizationActivity5AM = - incentivesRepo.findIncentiveMasterByNameAndGroup("DPT_IMMUNIZATION_5_YEARS", GroupName.IMMUNIZATION.getDisplayName()); - if (immunizationActivity5AM != null && childVaccinationRepo.checkDptVaccinatedUser(vaccination.getBeneficiaryRegId()) == 1) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivity5AM); - } - IncentiveActivity immunizationActivity5CH = - incentivesRepo.findIncentiveMasterByNameAndGroup("DPT_IMMUNIZATION_5_YEARS", GroupName.ACTIVITY.getDisplayName()); - if (immunizationActivity5CH != null && childVaccinationRepo.checkDptVaccinatedUser(vaccination.getBeneficiaryRegId()) == 1) { - createIncentiveRecord(vaccination, benId, userId, immunizationActivity5CH); } + }); } private void createIncentiveRecord(ChildVaccination vaccination, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), vaccination.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), vaccination.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); @@ -903,7 +1145,7 @@ private void createIncentiveRecordforHbncVisit(HbncVisit hbncVisit, Long benId, logger.info("RecordIncentive" + activityName); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), hbncVisit.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), hbncVisit.getCreatedDate(), benId,hbncVisit.getAshaId()); if (record == null) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); @@ -928,37 +1170,60 @@ record = new IncentiveActivityRecord(); } } - private void createIncentiveRecordforHbyncVisit(HbycChildVisit data, Long benId, IncentiveActivity immunizationActivity, String createdBy) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + private void updatePendingActivity(Integer userId, Long recordId, Long activityId, Long mIncentiveId) { + IncentivePendingActivity incentivePendingActivity = new IncentivePendingActivity(); + incentivePendingActivity.setActivityId(activityId); + incentivePendingActivity.setRecordId(recordId); + incentivePendingActivity.setUserId(userId); + incentivePendingActivity.setMincentiveId(mIncentiveId); + if (incentivePendingActivity != null) { + incentivePendingActivityRepository.save(incentivePendingActivity); + } - // Convert to LocalDate - LocalDate localDate = LocalDate.parse(data.getVisit_date(), formatter); + } - // Convert LocalDate to Timestamp (00:00:00 by default) - Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); + public HbncVisit updateHbncFromFileUpload(MultipartFile[] dischargeSncuImage, Long incentiveRecordId, Long id) throws JsonProcessingException { + HbncVisit existingHbncVisit = hbncVisitRepo.findById(id) + .orElseThrow(() -> new EntityNotFoundException("Meeting not found: " + id)); - if (record == null) { + // Images - only if provided + if (dischargeSncuImage != null && dischargeSncuImage.length > 0) { + List base64Images = Arrays.stream(dischargeSncuImage) + .filter(file -> file != null && !file.isEmpty()) + .map(this::convertToBase64) + .collect(Collectors.toList()); + existingHbncVisit.setDischarge_summary_upload(mapper.writeValueAsString(base64Images)); + } - record = new IncentiveActivityRecord(); - record.setActivityId(immunizationActivity.getId()); - record.setCreatedDate(visitDate); - record.setCreatedBy(createdBy); - record.setStartDate(visitDate); - record.setEndDate(visitDate); - record.setUpdatedDate(visitDate); - record.setUpdatedBy(createdBy); - record.setBenId(benId); - record.setAshaId(beneficiaryRepo.getUserIDByUserName(createdBy)); - record.setAmount(Long.valueOf(immunizationActivity.getRate())); + if (existingHbncVisit.getDischarge_summary_upload() != null) { + updateIncentive(incentiveRecordId); + + } + return hbncVisitRepo.save(existingHbncVisit); + } + + private void updateIncentive(Long id) { + + Optional optionalRecord = recordRepo.findById(id); + + if (optionalRecord.isPresent()) { + IncentiveActivityRecord record = optionalRecord.get(); + record.setIsEligible(true); recordRepo.save(record); } } - private void createIncentiveRecordforHbyncOrsDistribution(HbycChildVisit data, Long benId, IncentiveActivity immunizationActivity, String createdBy) { + private String convertToBase64(MultipartFile file) { + try { + return Base64.getEncoder().encodeToString(file.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Failed to convert image to Base64: " + file.getOriginalFilename(), e); + } + } + + private void createIncentiveRecordforHbyncVisit(HbycChildVisit data, Long benId, IncentiveActivity immunizationActivity, String createdBy) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); // Convert to LocalDate @@ -967,7 +1232,7 @@ private void createIncentiveRecordforHbyncOrsDistribution(HbycChildVisit data, L // Convert LocalDate to Timestamp (00:00:00 by default) Timestamp visitDate = Timestamp.valueOf(localDate.atStartOfDay()); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId,data.getUserId()); if (record == null) { @@ -981,46 +1246,47 @@ record = new IncentiveActivityRecord(); record.setUpdatedDate(visitDate); record.setUpdatedBy(createdBy); record.setBenId(benId); - record.setAshaId(beneficiaryRepo.getUserIDByUserName(createdBy)); + record.setAshaId(data.getUserId()); record.setAmount(Long.valueOf(immunizationActivity.getRate())); recordRepo.save(record); } } - private void createIncentiveRecordforOrsDistribution(OrsDistribution data, Long benId, IncentiveActivity immunizationActivity, String createdBy,boolean isCH) { - try { - // Convert to LocalDate - Timestamp visitDate = Timestamp.valueOf(data.getVisitDate().atStartOfDay()); - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId); - double packets = Double.parseDouble(data.getNumOrsPackets()); - double rate = immunizationActivity.getRate(); - - if (record == null) { - - record = new IncentiveActivityRecord(); - record.setActivityId(immunizationActivity.getId()); - record.setCreatedDate(visitDate); - record.setCreatedBy(createdBy); - record.setStartDate(visitDate); - record.setEndDate(visitDate); - record.setUpdatedDate(visitDate); - record.setUpdatedBy(createdBy); - record.setBenId(benId); - record.setAshaId(beneficiaryRepo.getUserIDByUserName(createdBy)); - if(isCH){ - record.setAmount((long) rate); - - }else { - record.setAmount((long) (rate * packets)); - - } - recordRepo.save(record); - } - }catch (Exception e){ - logger.error("Exp"+e.getMessage()); - - } + + private void createIncentiveRecordforOrsDistribution(OrsDistribution data, Long benId, IncentiveActivity immunizationActivity, String createdBy, boolean isCH) { + try { + // Convert to LocalDate + Timestamp visitDate = Timestamp.valueOf(data.getVisitDate().atStartOfDay()); + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), visitDate, benId,data.getUserId()); + double packets = Double.parseDouble(data.getNumOrsPackets()); + double rate = immunizationActivity.getRate(); + + if (record == null) { + + record = new IncentiveActivityRecord(); + record.setActivityId(immunizationActivity.getId()); + record.setCreatedDate(visitDate); + record.setCreatedBy(createdBy); + record.setStartDate(visitDate); + record.setEndDate(visitDate); + record.setUpdatedDate(visitDate); + record.setUpdatedBy(createdBy); + record.setBenId(0L); + record.setAshaId(data.getUserId()); + if (isCH) { + record.setAmount((long) rate); + + } else { + record.setAmount((long) (rate * packets)); + + } + recordRepo.save(record); + } + } catch (Exception e) { + logger.error("Exp" + e.getMessage()); + + } } @@ -1029,7 +1295,7 @@ private void createIncentiveRecordforSamReferalToNrc(SamVisit data, Long benId, // Convert to LocalDate Timestamp visitDate = Timestamp.valueOf(data.getVisitDate().atStartOfDay()); IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), visitDate, benId); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), visitDate, benId,data.getUserId()); if (record == null) { @@ -1042,12 +1308,14 @@ record = new IncentiveActivityRecord(); record.setUpdatedDate(visitDate); record.setUpdatedBy(createdBy); record.setBenId(benId); - record.setAshaId(beneficiaryRepo.getUserIDByUserName(createdBy)); + record.setAshaId(data.getUserId()); record.setAmount((long) incentiveActivity.getRate()); + record.setIsEligible(true); + record.setIsDefaultActivity(false); recordRepo.save(record); } - }catch (Exception e){ - logger.error("Exp"+e.getMessage()); + } catch (Exception e) { + logger.error("Exp" + e.getMessage()); } diff --git a/src/main/java/com/iemr/flw/service/impl/ChildServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/ChildServiceImpl.java index 0ce841e8..32c6d76a 100644 --- a/src/main/java/com/iemr/flw/service/impl/ChildServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/ChildServiceImpl.java @@ -2,18 +2,24 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.iemr.flw.domain.identity.RMNCHBeneficiaryDetailsRmnch; import com.iemr.flw.domain.iemr.ChildRegister; +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.domain.iemr.UserServiceRole; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.ChildRegisterDTO; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.ChildRegisterRepo; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.ChildService; +import com.iemr.flw.service.IncentiveLogicService; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.sql.Timestamp; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -28,6 +34,12 @@ public class ChildServiceImpl implements ChildService { @Autowired private BeneficiaryRepo beneficiaryRepo; + @Autowired + private IncentiveLogicService incentiveLogicService; + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; + public String getByUserId(GetBenRequestHandler dto) { try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); @@ -38,6 +50,7 @@ public String getByUserId(GetBenRequestHandler dto) { // ChildRegisterDTO childDTO = modelMapper.map(childRegister, ChildRegisterDTO.class); // result.add(childDTO); // }); + List result = childRegisterList.stream() .map(childRegister -> modelMapper.map(childRegister, ChildRegisterDTO.class)) .collect(Collectors.toList()); @@ -68,6 +81,68 @@ public String save(List childRegisterDTOs) throws Exception { listToBeSaved.add(childRegister); }); childRepo.saveAll(listToBeSaved); + for (ChildRegister childRegister : listToBeSaved) { + processFirstChildIncentive(childRegister); + } + for (ChildRegister childRegister : listToBeSaved) { + processSecondChildGapIncentive(childRegister); + } return "no of child details saved: " + childRegisterDTOs.size(); } + + public void processFirstChildIncentive(ChildRegister childRegister) { + Long benId = childRegister.getBenId(); + logger.info("Child register {}"+childRegister.getBenId()); + + // First child validation + List childCount = childRepo.findByBenId(benId); + + + if(!childCount.isEmpty()){ + logger.info("Child register {}"+childCount.size()); + + if(childCount.size()==1){ + Integer userId = + userServiceRoleRepo.getUserIdByName(childRegister.getCreatedBy()); + + incentiveLogicService.incentiveForChildBirthGap( + benId, + childRegister.getCreatedDate(), + childRegister.getCreatedDate(), + userId + ); + } + } + + + + } + + private void processSecondChildGapIncentive(ChildRegister currentChild) { + + Long benId = currentChild.getBenId(); + + // Total children count + List childCount = childRepo.findByBenId(benId); + + // Applicable only for second child + + if(!childCount.isEmpty()){ + if(childCount.size()==2){ + Integer userId = + userServiceRoleRepo.getUserIdByName( + currentChild.getCreatedBy()); + + incentiveLogicService.incentiveForSecondChildGap( + benId, + currentChild.getCreatedDate(), + currentChild.getCreatedDate(), + userId + ); + } + } + + + + } } diff --git a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java index 95b0557b..e22147af 100644 --- a/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CoupleServiceImpl.java @@ -11,14 +11,17 @@ import com.iemr.flw.dto.iemr.EligibleCoupleDTO; import com.iemr.flw.dto.iemr.EligibleCoupleTrackingDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.CoupleService; +import com.iemr.flw.service.UserService; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @@ -27,6 +30,7 @@ import java.util.Arrays; import java.util.Base64; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Service @@ -46,6 +50,9 @@ public class CoupleServiceImpl implements CoupleService { @Autowired private UserServiceRoleRepo userRepo; + + @Autowired + private UserService userService; @Autowired private IncentiveRecordRepo recordRepo; @@ -54,82 +61,139 @@ public class CoupleServiceImpl implements CoupleService { private BeneficiaryRepo beneficiaryRepo; private final Logger logger = LoggerFactory.getLogger(CoupleServiceImpl.class); + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + @Override - public String registerEligibleCouple(List eligibleCoupleDTOs, MultipartFile kitPhoto1, MultipartFile kitPhoto2) { + @Transactional + public String registerEligibleCouple(List eligibleCoupleDTOs, + MultipartFile kitPhoto1, + MultipartFile kitPhoto2) { try { + List ecrList = new ArrayList<>(); - List recordList = new ArrayList<>(); - eligibleCoupleDTOs.forEach(it -> { - EligibleCoupleRegister existingECR = -// eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenIdAndCreatedDate(it.getBenId(), it.getCreatedDate()); - eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(it.getBenId()); - if (kitPhoto1 != null) { - String kitPhoto1base64Image = null; - try { - kitPhoto1base64Image = Base64.getEncoder().encodeToString(kitPhoto1.getBytes()); - } catch (IOException e) { - throw new RuntimeException(e); + if(!eligibleCoupleDTOs.isEmpty()){ + for (EligibleCoupleDTO it : eligibleCoupleDTOs) { + Integer userId = userRepo.getUserIdByName(it.getCreatedBy()); + Integer stateId = userService.getUserDetail(userId).getStateId(); + EligibleCoupleRegister existingECR = + eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(it.getBenId()); + + boolean isNew = false; + + if (existingECR == null) { + existingECR = new EligibleCoupleRegister(); + isNew = true; } - existingECR.setKitPhoto1(String.valueOf(kitPhoto1base64Image)); - } + Long id = existingECR.getId(); + modelMapper.map(it, existingECR); - if (kitPhoto2 != null) { - String kitPhoto2base64Image = null; - try { - kitPhoto2base64Image = Base64.getEncoder().encodeToString(kitPhoto2.getBytes()); - } catch (IOException e) { - throw new RuntimeException(e); - } - existingECR.setKitPhoto2(String.valueOf(kitPhoto2base64Image)); + existingECR.setId(id); - } + // Photo 1 + if (kitPhoto1 != null && !kitPhoto1.isEmpty()) { + existingECR.setKitPhoto1( + Base64.getEncoder().encodeToString(kitPhoto1.getBytes())); + } - if (existingECR != null && null != existingECR.getNumLiveChildren()) { - if (existingECR.getNumLiveChildren() == 0 && it.getNumLiveChildren() >= 1 && it.getMarriageFirstChildGap() != null && it.getMarriageFirstChildGap() >= 2) { - IncentiveActivity activity1 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_DELAY_2Y", GroupName.FAMILY_PLANNING.getDisplayName()); - createIncentiveRecord(recordList, it, activity1); - } else if (existingECR.getNumLiveChildren() == 1 && it.getNumLiveChildren() >= 2 && it.getFirstAndSecondChildGap() != null && it.getFirstAndSecondChildGap() == 3) { - IncentiveActivity activity2 = - incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", GroupName.FAMILY_PLANNING.getDisplayName()); - createIncentiveRecord(recordList, it, activity2); + // Photo 2 + if (kitPhoto2 != null && !kitPhoto2.isEmpty()) { + existingECR.setKitPhoto2( + Base64.getEncoder().encodeToString(kitPhoto2.getBytes())); } - Long id = existingECR.getId(); - modelMapper.map(it, existingECR); - existingECR.setId(id); - } else { - existingECR = new EligibleCoupleRegister(); - modelMapper.map(it, existingECR); - existingECR.setId(null); - } - if (existingECR.getIsKitHandedOver() && (!existingECR.getKitPhoto1().isEmpty() || !existingECR.getKitPhoto2().isEmpty())) { - IncentiveActivity handoverKitActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_NP_KIT", GroupName.FAMILY_PLANNING.getDisplayName()); - if (handoverKitActivityAM != null) { - createIncentiveRecord(recordList, it, handoverKitActivityAM); + // Incentive only for new registration + if (isNew) { + + if (it.getMarriageFirstChildGap() != null + && it.getMarriageFirstChildGap() >= 2) { + + IncentiveActivity activity = null; + + if (stateId.equals(StateCode.AM.getStateCode())) { + activity = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.FAMILY_PLANNING.getDisplayName()); + + } else if (stateId.equals(StateCode.CG.getStateCode())) { + activity = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.ACTIVITY.getDisplayName()); + } + + if (activity != null) { + createIncentiveRecord(existingECR, activity); + } + } + + if (it.getFirstAndSecondChildGap() != null + && it.getFirstAndSecondChildGap() >= 3) { + + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.FAMILY_PLANNING.getDisplayName()); + + createIncentiveRecord(existingECR, activity); + + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecord(existingECR, activity); + } + } } + // Kit Incentive + if (Boolean.TRUE.equals(existingECR.getIsKitHandedOver()) + && ((existingECR.getKitPhoto1() != null && !existingECR.getKitPhoto1().isEmpty()) + || (existingECR.getKitPhoto2() != null && !existingECR.getKitPhoto2().isEmpty()))) { + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_NP_KIT", + GroupName.FAMILY_PLANNING.getDisplayName()); + + if (activity != null) { + createIncentiveRecord(existingECR, activity); + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_NP_KIT", + GroupName.ACTIVITY.getDisplayName()); + + if (activity != null) { + createIncentiveRecord(existingECR, activity); + } + } - IncentiveActivity handoverKitActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_NP_KIT", GroupName.ACTIVITY.getDisplayName()); - if (handoverKitActivityCH != null) { - createIncentiveRecord(recordList, it, handoverKitActivityCH); } + + ecrList.add(existingECR); } - ecrList.add(existingECR); - }); - eligibleCoupleRegisterRepo.saveAll(ecrList); - recordRepo.saveAll(recordList); - return "no of ecr details saved: " + ecrList.size(); + + eligibleCoupleRegisterRepo.saveAll(ecrList); + + } + + + return "No of ECR details saved: " + ecrList.size(); + } catch (Exception e) { - return "error while saving ecr details: " + e.getMessage(); + logger.error("Error while saving Eligible Couple Registration", e); + return "Error while saving ECR details: " + e.getMessage(); } } @@ -137,46 +201,141 @@ public String registerEligibleCouple(List eligibleCoupleDTOs, public String registerEligibleCouple(List eligibleCoupleDTOs) { try { List ecrList = new ArrayList<>(); - List recordList = new ArrayList<>(); eligibleCoupleDTOs.forEach(it -> { EligibleCoupleRegister existingECR = -// eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenIdAndCreatedDate(it.getBenId(), it.getCreatedDate()); eligibleCoupleRegisterRepo.findEligibleCoupleRegisterByBenId(it.getBenId()); - - if (existingECR != null && null != existingECR.getNumLiveChildren()) { - if (it.getNumLiveChildren() >= 1 && it.getMarriageFirstChildGap() != null && it.getMarriageFirstChildGap() >= 2) { - IncentiveActivity activity1 = - incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", GroupName.FAMILY_PLANNING.getDisplayName()) - ; - - IncentiveActivity activityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("MARRIAGE_1st_CHILD_GAP", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecord(recordList, it, activity1); - createIncentiveRecord(recordList, it, activityCH); - } else if (it.getNumLiveChildren() >= 2 && it.getMarriageFirstChildGap() != null && it.getMarriageFirstChildGap() >= 3) { - IncentiveActivity activity2 = - incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", GroupName.FAMILY_PLANNING.getDisplayName()); - - IncentiveActivity activityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("1st_2nd_CHILD_GAP", GroupName.ACTIVITY.getDisplayName()); - createIncentiveRecord(recordList, it, activity2); - createIncentiveRecord(recordList, it, activityCH); - } + if(existingECR!=null){ Long id = existingECR.getId(); modelMapper.map(it, existingECR); existingECR.setId(id); - } else { + }else { existingECR = new EligibleCoupleRegister(); modelMapper.map(it, existingECR); existingECR.setId(null); } + ecrList.add(existingECR); + + }); + + eligibleCoupleRegisterRepo.saveAll(ecrList); + if(!ecrList.isEmpty()){ + Integer userId = userRepo.getUserIdByName(ecrList.get(0).getCreatedBy()); + Integer stateId = userService.getUserDetail(userId).getStateId(); + checkIncentiveForChildGap(stateId,ecrList.get(0).getCreatedBy(),ecrList); + + } + return "no of ecr details saved: " + ecrList.size(); + } catch (Exception e) { + return "error while saving ecr details: " + e.getMessage(); + } + } + + + private void checkIncentiveForChildGap(Integer stateId, String userName,List eligibleCoupleRegisters) { + + logger.info("Checking Child Gap Incentive for user: {}, stateId: {}", userName, stateId); + + + logger.info("Eligible Couple Records Found: {}", eligibleCoupleRegisters.size()); + + if (!eligibleCoupleRegisters.isEmpty()) { + + eligibleCoupleRegisters.forEach(eligibleCoupleRegister -> { + + logger.info( + "Processing EligibleCoupleRegister -> BenId: {}, NumChildren: {}, MarriageFirstChildGap: {}, FirstAndSecondChildGap: {}", + eligibleCoupleRegister.getBenId(), + eligibleCoupleRegister.getNumChildren(), + eligibleCoupleRegister.getMarriageFirstChildGap(), + eligibleCoupleRegister.getFirstAndSecondChildGap()); + + // Marriage -> First Child Gap + if(eligibleCoupleRegister.getFirstAndSecondChildGap()!=null){ + if (eligibleCoupleRegister.getFirstAndSecondChildGap()>=2 ) { + + logger.info("Marriage -> First Child Gap condition matched."); + + if (stateId.equals(StateCode.AM.getStateCode())) { + + logger.info("Fetching incentive for Assam."); + + IncentiveActivity activity1 = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.FAMILY_PLANNING.getDisplayName()); + + logger.info("Incentive Activity: {}", activity1); + + createIncentiveRecord(eligibleCoupleRegister, activity1); - if (existingECR.getIsKitHandedOver()) { + logger.info("Marriage -> First Child Gap incentive created."); + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + + logger.info("Fetching incentive for Chhattisgarh."); + + IncentiveActivity activityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.ACTIVITY.getDisplayName()); + + logger.info("Incentive Activity: {}", activityCH); + + createIncentiveRecord(eligibleCoupleRegister, activityCH); + + logger.info("Marriage -> First Child Gap incentive created."); + } + } + } + + + // First -> Second Child Gap + if(eligibleCoupleRegister.getMarriageFirstChildGap()!=null){ + if (eligibleCoupleRegister.getMarriageFirstChildGap()>=3) { + + logger.info("1st -> 2nd Child Gap condition matched."); + + if (stateId.equals(StateCode.AM.getStateCode())) { + + logger.info("Fetching incentive for Assam."); + + IncentiveActivity activity2 = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.FAMILY_PLANNING.getDisplayName()); + + logger.info("Incentive Activity: {}", activity2); + + createIncentiveRecord(eligibleCoupleRegister, activity2); + + logger.info("1st -> 2nd Child Gap incentive created."); + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + + logger.info("Fetching incentive for Chhattisgarh."); + + IncentiveActivity activityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.ACTIVITY.getDisplayName()); + + logger.info("Incentive Activity: {}", activityCH); + + createIncentiveRecord(eligibleCoupleRegister, activityCH); + + logger.info("1st -> 2nd Child Gap incentive created."); + } + } + } + + if (eligibleCoupleRegister.getIsKitHandedOver()!=null && eligibleCoupleRegister.getIsKitHandedOver()) { IncentiveActivity handoverKitActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("FP_NP_KIT", GroupName.FAMILY_PLANNING.getDisplayName()); if (handoverKitActivityAM != null) { - createIncentiveRecord(recordList, it, handoverKitActivityAM); + createIncentiveRecord(eligibleCoupleRegister, handoverKitActivityAM); } @@ -184,41 +343,54 @@ public String registerEligibleCouple(List eligibleCoupleDTOs) IncentiveActivity handoverKitActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("FP_NP_KIT", GroupName.ACTIVITY.getDisplayName()); if (handoverKitActivityCH != null) { - createIncentiveRecord(recordList, it, handoverKitActivityCH); + createIncentiveRecord(eligibleCoupleRegister, handoverKitActivityCH); } } - ecrList.add(existingECR); + + + + }); - eligibleCoupleRegisterRepo.saveAll(ecrList); - recordRepo.saveAll(recordList); - return "no of ecr details saved: " + ecrList.size(); - } catch (Exception e) { - return "error while saving ecr details: " + e.getMessage(); + + } else { + logger.info("No Eligible Couple Register records found for user: {}", userName); } + + logger.info("Completed Child Gap Incentive check for user: {}", userName); } - private void createIncentiveRecord(List recordList, EligibleCoupleDTO eligibleCoupleDTO, IncentiveActivity activity) { - if (activity != null) { - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(activity.getId(), eligibleCoupleDTO.getCreatedDate(), eligibleCoupleDTO.getBenId()); - Integer userId = userRepo.getUserIdByName(eligibleCoupleDTO.getCreatedBy()); - if (record == null) { - record = new IncentiveActivityRecord(); - record.setActivityId(activity.getId()); - record.setCreatedDate(eligibleCoupleDTO.getCreatedDate()); - record.setCreatedBy(eligibleCoupleDTO.getCreatedBy()); - record.setStartDate(eligibleCoupleDTO.getCreatedDate()); - record.setEndDate(eligibleCoupleDTO.getCreatedDate()); - record.setUpdatedDate(eligibleCoupleDTO.getCreatedDate()); - record.setUpdatedBy(eligibleCoupleDTO.getCreatedBy()); - record.setBenId(eligibleCoupleDTO.getBenId()); - record.setAshaId(userId); - record.setAmount(Long.valueOf(activity.getRate())); - recordList.add(record); + private void createIncentiveRecord(EligibleCoupleRegister eligibleCoupleDTO, IncentiveActivity activity) { + String lockKey = activity.getId() + "_" + eligibleCoupleDTO.getBenId() + "_" + eligibleCoupleDTO.getCreatedDate(); + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + synchronized (lock){ + if (activity != null) { + Integer userId = userRepo.getUserIdByName(eligibleCoupleDTO.getCreatedBy()); + + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), eligibleCoupleDTO.getCreatedDate(), eligibleCoupleDTO.getBenId(),userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(eligibleCoupleDTO.getCreatedDate()); + record.setCreatedBy(eligibleCoupleDTO.getCreatedBy()); + record.setStartDate(eligibleCoupleDTO.getCreatedDate()); + record.setEndDate(eligibleCoupleDTO.getCreatedDate()); + record.setUpdatedDate(eligibleCoupleDTO.getCreatedDate()); + record.setUpdatedBy(eligibleCoupleDTO.getCreatedBy()); + record.setBenId(eligibleCoupleDTO.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(activity.getRate())); + recordRepo.save(record); + } } } + lockMap.remove(lockKey, lock); + + + } @Override @@ -240,7 +412,7 @@ public String registerEligibleCoupleTracking(List eli ect.setId(null); } ectList.add(ect); - checkAndAddAntaraIncentive(recordList, ect); + checkAndAddAntaraIncentive(ect); }); eligibleCoupleTrackingRepo.saveAll(ectList); recordRepo.saveAll(recordList); @@ -250,135 +422,170 @@ public String registerEligibleCoupleTracking(List eli } } - private void checkAndAddAntaraIncentive(List recordList, EligibleCoupleTracking ect) { + private void checkAndAddAntaraIncentive(EligibleCoupleTracking ect) { Integer userId = userRepo.getUserIdByName(ect.getCreatedBy()); logger.info("Antra" + ect.getMethodOfContraception()); logger.info("Antra" + ect.getAntraDose()); + Integer stateId = userService.getUserDetail(userId).getStateId(); if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().contains("ANTRA Injection")) { - // for CG incentive - IncentiveActivity antaraActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", GroupName.ACTIVITY.getDisplayName()); - if (antaraActivityCH != null) { - String dose = ect.getAntraDose(); + if(stateId.equals(StateCode.CG.getStateCode())){ + // for CG incentive + IncentiveActivity antaraActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", GroupName.ACTIVITY.getDisplayName()); + if (antaraActivityCH != null) { + String dose = ect.getAntraDose(); - List validDoses = Arrays.asList("Dose-1", "Dose-2", "Dose-3", "Dose-4"); + List validDoses = Arrays.asList("Dose-1", "Dose-2", "Dose-3", "Dose-4"); - boolean isDose = validDoses.stream().anyMatch(dose::contains); + boolean isDose = validDoses.stream().anyMatch(dose::contains); - if (isDose) { - addIncenticeRecord(recordList, ect, userId, antaraActivityCH); + if (isDose) { + addIncenticeRecord(ect, userId, antaraActivityCH); + } } } - if (ect.getAntraDose().contains("Dose-1")) { - IncentiveActivity antaraActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", "FAMILY PLANNING"); - if (antaraActivity != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity); - } - } else if (ect.getAntraDose().contains("Dose-2")) { - IncentiveActivity antaraActivity2 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA2", "FAMILY PLANNING"); - if (antaraActivity2 != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity2); - } - } else if (ect.getAntraDose().contains("Dose-3")) { - IncentiveActivity antaraActivity3 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA3", "FAMILY PLANNING"); - if (antaraActivity3 != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity3); - } - } else if (ect.getAntraDose().contains("Dose-4")) { - IncentiveActivity antaraActivity4 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA4", "FAMILY PLANNING"); - if (antaraActivity4 != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity4); - } + if(stateId.equals(StateCode.AM.getStateCode())){ + if (ect.getAntraDose().contains("Dose-1")) { + IncentiveActivity antaraActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", "FAMILY PLANNING"); + if (antaraActivity != null) { + addIncenticeRecord(ect, userId, antaraActivity); + } + } else if (ect.getAntraDose().contains("Dose-2")) { + IncentiveActivity antaraActivity2 = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA2", "FAMILY PLANNING"); + if (antaraActivity2 != null) { + addIncenticeRecord(ect, userId, antaraActivity2); + } + } else if (ect.getAntraDose().contains("Dose-3")) { + IncentiveActivity antaraActivity3 = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA3", "FAMILY PLANNING"); + if (antaraActivity3 != null) { + addIncenticeRecord(ect, userId, antaraActivity3); + } + } else if (ect.getAntraDose().contains("Dose-4")) { + IncentiveActivity antaraActivity4 = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA4", "FAMILY PLANNING"); + if (antaraActivity4 != null) { + addIncenticeRecord(ect, userId, antaraActivity4); + } - } else if (ect.getAntraDose().contains("Dose-5")) { - IncentiveActivity antaraActivity4 = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA5", GroupName.FAMILY_PLANNING.getDisplayName()); + }else if (ect.getAntraDose().contains("Dose-5")) { + IncentiveActivity antaraActivity4 = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA5", GroupName.FAMILY_PLANNING.getDisplayName()); + + if (antaraActivity4 != null) { + addIncenticeRecord(ect, userId, antaraActivity4); + } + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ IncentiveActivity antaraActivity4CH = incentivesRepo.findIncentiveMasterByNameAndGroup("FP_ANC_MPA1", GroupName.ACTIVITY.getDisplayName()); if (antaraActivity4CH != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity4CH); - } - - if (antaraActivity4 != null) { - addIncenticeRecord(recordList, ect, userId, antaraActivity4); + addIncenticeRecord(ect, userId, antaraActivity4CH); } } + + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("MALE STERILIZATION")) { - - IncentiveActivity maleSterilizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", "FAMILY PLANNING"); - - IncentiveActivity maleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); - if (maleSterilizationActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, maleSterilizationActivityAM); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity maleSterilizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", "FAMILY PLANNING"); + + if (maleSterilizationActivityAM != null) { + addIncenticeRecord(ect, userId, maleSterilizationActivityAM); + } + } - - if (maleSterilizationActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, maleSterilizationActivityCH); + if(stateId.equals(StateCode.CG.getStateCode())){ + + IncentiveActivity maleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); + + + if (maleSterilizationActivityCH != null) { + addIncenticeRecord(ect, userId, maleSterilizationActivityCH); + } } + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("FEMALE STERILIZATION")) { + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity femaleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity femaleSterilizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); - - IncentiveActivity femaleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - if (femaleSterilizationActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, femaleSterilizationActivityAM); + if (femaleSterilizationActivityCH != null) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityCH); + } } + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity femaleSterilizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); + if (femaleSterilizationActivityAM != null) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityAM); + } - if (femaleSterilizationActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, femaleSterilizationActivityCH); } - } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("MiniLap")) { - IncentiveActivity miniLapActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MINILAP", "FAMILY PLANNING"); - if (miniLapActivity != null) { - addIncenticeRecord(recordList, ect, userId, miniLapActivity); + + + + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("MiniLap")) { + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity miniLapActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MINILAP", "FAMILY PLANNING"); + if (miniLapActivity != null) { + addIncenticeRecord(ect, userId, miniLapActivity); + } } + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("Condom")) { - - IncentiveActivity comdomActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", "FAMILY PLANNING"); - if (comdomActivity != null) { - addIncenticeRecord(recordList, ect, userId, comdomActivity); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity comdomActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", "FAMILY PLANNING"); + if (comdomActivity != null) { + addIncenticeRecord(ect, userId, comdomActivity); + } } + } else if (ect.getMethodOfContraception() != null && ect.getMethodOfContraception().equals("Copper T (IUCD)")) { - - IncentiveActivity copperTActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", "FAMILY PLANNING"); - if (copperTActivity != null) { - addIncenticeRecord(recordList, ect, userId, copperTActivity); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity copperTActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", "FAMILY PLANNING"); + if (copperTActivity != null) { + addIncenticeRecord(ect, userId, copperTActivity); + } } + } if (ect.getMethodOfContraception() != null && (ect.getMethodOfContraception().contains("POST PARTUM STERILIZATION (PPS WITHIN 7 DAYS OF DELIVERY)") || ect.getMethodOfContraception().contains("MiniLap") || ect.getMethodOfContraception().contains("MALE STERILIZATION") || ect.getMethodOfContraception().contains("FEMALE STERILIZATION"))) { - IncentiveActivity limitiing2ChildActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_LIMIT_2CHILD", GroupName.FAMILY_PLANNING.getDisplayName()); - - IncentiveActivity limitiing2ChildActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_LIMIT_2CHILD", GroupName.ACTIVITY.getDisplayName()); - if (limitiing2ChildActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, limitiing2ChildActivityAM); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity limitiing2ChildActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_LIMIT_2CHILD", GroupName.FAMILY_PLANNING.getDisplayName()); + if (limitiing2ChildActivityAM != null) { + addIncenticeRecord(ect, userId, limitiing2ChildActivityAM); + } } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity limitiing2ChildActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_LIMIT_2CHILD", GroupName.ACTIVITY.getDisplayName()); + - if (limitiing2ChildActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, limitiing2ChildActivityCH); + if (limitiing2ChildActivityCH != null) { + addIncenticeRecord(ect, userId, limitiing2ChildActivityCH); + } } + + } } - private void addIncenticeRecord(List recordList, EligibleCoupleTracking ect, Integer userId, IncentiveActivity antaraActivity) { + private void addIncenticeRecord(EligibleCoupleTracking ect, Integer userId, IncentiveActivity antaraActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getCreatedDate(), ect.getBenId()); + .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getVisitDate(), ect.getBenId(),userId); // get bene details if (record == null) { @@ -393,7 +600,7 @@ record = new IncentiveActivityRecord(); record.setBenId(ect.getBenId()); record.setAshaId(userId); record.setAmount(Long.valueOf(antaraActivity.getRate())); - recordList.add(record); + recordRepo.save(record); } } @@ -409,6 +616,7 @@ public String getEligibleCoupleRegRecords(GetBenRequestHandler dto) { Gson gson = new GsonBuilder() .serializeNulls() .setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return gson.toJson(list); } catch (Exception e) { logger.error(e.getMessage()); @@ -418,6 +626,7 @@ public String getEligibleCoupleRegRecords(GetBenRequestHandler dto) { @Override public List getEligibleCoupleTracking(GetBenRequestHandler dto) { + List recordList = new ArrayList<>(); try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); @@ -425,9 +634,12 @@ public List getEligibleCoupleTracking(GetBenRequestHa List eligibleCoupleTrackingList = eligibleCoupleTrackingRepo.getECTrackRecords(user, dto.getFromDate(), dto.getToDate()); + recordRepo.saveAll(recordList); + return eligibleCoupleTrackingList.stream() .map(ect -> mapper.convertValue(ect, EligibleCoupleTrackingDTO.class)) .collect(Collectors.toList()); + } catch (Exception e) { logger.error(e.getMessage()); } diff --git a/src/main/java/com/iemr/flw/service/impl/CrashLogServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/CrashLogServiceImpl.java index da2fbaa0..4c85ae66 100644 --- a/src/main/java/com/iemr/flw/service/impl/CrashLogServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/CrashLogServiceImpl.java @@ -24,7 +24,7 @@ public class CrashLogServiceImpl implements CrashLogService { private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - @Value("${crash.logs.base.path}") + // @Value("${crash.logs.base.path}") private String crashLogsBasePath; @Override diff --git a/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java index 82cee5d0..b7eee7dd 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeathReportsServiceImpl.java @@ -7,15 +7,19 @@ import com.iemr.flw.dto.iemr.CdrDTO; import com.iemr.flw.dto.iemr.MdsrDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.DeathReportsService; import org.modelmapper.ModelMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; @Service @@ -43,16 +47,20 @@ public class DeathReportsServiceImpl implements DeathReportsService { @Autowired private IncentiveRecordRepo recordRepo; + @Autowired + private UpdateIncentivePendindDocService pendindDocService; + + private final Logger logger = LoggerFactory.getLogger(DeathReportsServiceImpl.class); @Override public String registerCDR(List cdrDTOs) { try { List cdrList = new ArrayList<>(); - cdrDTOs.forEach(it ->{ + cdrDTOs.forEach(it -> { CDR existingCDR = cdrRepo.findCDRByBenId(it.getBenId()); - if(existingCDR != null) { + if (existingCDR != null) { Long id = existingCDR.getId(); modelMapper.map(it, existingCDR); existingCDR.setId(id); @@ -73,15 +81,47 @@ public String registerCDR(List cdrDTOs) { } } + public String updateCDRUploadFiles(CdrDTO cdrDTOs, Long incentiveActivityId) { + try { + Optional cdrOptional = cdrRepo.findById(cdrDTOs.getId()); + CDR cdr = new CDR(); + if (cdrOptional.isPresent()) { + cdr = cdrOptional.get(); + if (cdrDTOs.getCdrImage() != null && !cdrDTOs.getCdrImage().isEmpty()) { + cdr.setCdrImage(cdrDTOs.getCdrImage()); + } + + if (cdrDTOs.getCdrImage2() != null && !cdrDTOs.getCdrImage2().isEmpty()) { + cdr.setCdrImage2(cdrDTOs.getCdrImage2()); + } + + if (cdrDTOs.getDeathCertImage1() != null && !cdrDTOs.getDeathCertImage1().isEmpty()) { + cdr.setDeathCertImage1(cdrDTOs.getDeathCertImage1()); + } + + if (cdrDTOs.getDeathCertImage2() != null && !cdrDTOs.getDeathCertImage2().isEmpty()) { + cdr.setDeathCertImage2(cdrDTOs.getDeathCertImage2()); + } + } + cdrRepo.save(cdr); + + pendindDocService.updateIncentive(incentiveActivityId); + + return "no of cdr details update: "; + } catch (Exception e) { + return "error while saving cdr details: " + e.getMessage(); + } + } + @Override public String registerMDSR(List mdsrDTOs) { try { List mdsrList = new ArrayList<>(); - mdsrDTOs.forEach(it ->{ + mdsrDTOs.forEach(it -> { MDSR mdsr = mdsrRepo.findMDSRByBenId(it.getBenId()); - if(mdsr != null) { + if (mdsr != null) { Long id = mdsr.getId(); modelMapper.map(it, mdsr); mdsr.setId(id); @@ -101,16 +141,56 @@ public String registerMDSR(List mdsrDTOs) { } } + public String updateMDSR(MdsrDTO mdsrDTO, Long incentiveActivityId) { + try { + + Optional mdsrOptional = mdsrRepo.findById(mdsrDTO.getId()); + MDSR mdsr = new MDSR(); + + if (mdsrOptional.isPresent()) { + + mdsr = mdsrOptional.get(); + + if (mdsrDTO.getMdsr1File() != null && !mdsrDTO.getMdsr1File().isEmpty()) { + mdsr.setMdsr1File(mdsrDTO.getMdsr1File()); + } + + if (mdsrDTO.getMdsr2File() != null && !mdsrDTO.getMdsr2File().isEmpty()) { + mdsr.setMdsr2File(mdsrDTO.getMdsr2File()); + } + + if (mdsrDTO.getMdsrDeathCertFile() != null && !mdsrDTO.getMdsrDeathCertFile().isEmpty()) { + mdsr.setMdsrDeathCertFile(mdsrDTO.getMdsrDeathCertFile()); + } + + } else { + return "MDSR record not found with id: " + mdsrDTO.getId(); + } + + mdsrRepo.save(mdsr); + + // incentive update + pendindDocService.updateIncentive(incentiveActivityId); + + return "MDSR updated successfully for id: " + mdsrDTO.getId(); + + } catch (Exception e) { + return "error while updating mdsr details: " + e.getMessage(); + } + } + @Override public List getCdrRecords(GetBenRequestHandler dto) { - try{ - String user = beneficiaryRepo.getUserName(dto.getAshaId()); + try { + String user = userRepo.getUserNamedByUserId(dto.getAshaId()); List cdrlist = - cdrRepo.getAllCdrByBenId(user, dto.getFromDate(), dto.getToDate()); + cdrRepo.findByCreatedBy(user); return cdrlist.stream() .map(cdr -> mapper.convertValue(cdr, CdrDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { + logger.error("MDSR Exception:" + e.getMessage()); + // log } return null; @@ -120,47 +200,74 @@ public List getCdrRecords(GetBenRequestHandler dto) { public List getMdsrRecords(GetBenRequestHandler dto) { try { - String user = beneficiaryRepo.getUserName(dto.getAshaId()); + String user = userRepo.getUserNamedByUserId(dto.getAshaId()); List mdsrList = - mdsrRepo.getAllMdsrByAshaId(user, dto.getFromDate(), dto.getToDate()); + mdsrRepo.findByCreatedBy(user); return mdsrList.stream() .map(mdsr -> mapper.convertValue(mdsr, MdsrDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { + logger.error("MDSR Exception:" + e.getMessage()); + // log } return null; } private void checkAndAddIncentives(List cdrList) { + if(!cdrList.isEmpty()){ + Integer userId = userRepo.getUserIdByName(cdrList.get(0).getCreatedBy()); + cdrList.forEach(cdr -> { + IncentiveActivity immunizationActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); + createIncentiveRecord(cdr, cdr.getBenId(), userId, immunizationActivity); + if(immunizationActivity!=null){ + createIncentiveRecord(cdr,cdr.getBenId(),userId,immunizationActivity); + + } + }); + + } + - cdrList.forEach( cdr -> { - Integer userId = userRepo.getUserIdByName(cdr.getCreatedBy()); - IncentiveActivity immunizationActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_DEATH_REPORTING", GroupName.CHILD_HEALTH.getDisplayName()); - createIncentiveRecord(cdr,cdr.getBenId(),userId,immunizationActivity); - }); } private void checkAndAddIncentivesMdsr(List mdsrList) { - - mdsrList.forEach( mdsr -> { + mdsrList.forEach(mdsr -> { Integer userId = userRepo.getUserIdByName(mdsr.getCreatedBy()); - IncentiveActivity immunizationActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("MATERNAL_DEATH_REPORT", GroupName.MATERNAL_HEALTH.getDisplayName()); + Integer stateId = userRepo.getUserRole(userId).get(0).getStateId(); + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity immunizationActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("MATERNAL_DEATH_REPORT", GroupName.MATERNAL_HEALTH.getDisplayName()); + + if(immunizationActivity!=null){ + createIncentiveRecord(mdsr,mdsr.getBenId(),userId,immunizationActivity); + + } + + + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity cgImmunizationActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("MATERNAL_DEATH_REPORT", GroupName.ACTIVITY.getDisplayName()); + + if(cgImmunizationActivity!=null){ + createIncentiveRecord(mdsr,mdsr.getBenId(),userId,cgImmunizationActivity); + + } + } + - createIncentiveRecord(mdsr,mdsr.getBenId(),userId,immunizationActivity); }); } - private void createIncentiveRecord(CDR cdr, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), cdr.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), cdr.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(immunizationActivity.getId()); @@ -173,13 +280,16 @@ record = new IncentiveActivityRecord(); record.setBenId(benId); record.setAshaId(userId); record.setAmount(Long.valueOf(immunizationActivity.getRate())); + record.setIsEligible(true); recordRepo.save(record); + + } } private void createIncentiveRecord(MDSR mdsr, Long benId, Integer userId, IncentiveActivity immunizationActivity) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), mdsr.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), mdsr.getCreatedDate(), benId,userId); if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(immunizationActivity.getId()); @@ -192,14 +302,29 @@ record = new IncentiveActivityRecord(); record.setBenId(benId); record.setAshaId(userId); record.setAmount(Long.valueOf(immunizationActivity.getRate())); - recordRepo.save(record); - } - } + if (userRepo.getUserRole(userId).get(0).getStateId() == StateCode.AM.getStateCode()) { + if (mdsr.getMdsrDeathCertFile() != null && mdsr.getMdsr1File() != null && mdsr.getMdsr2File() != null) { + record.setIsEligible(true); + recordRepo.save(record); + + } else { + record.setIsEligible(false); + IncentiveActivityRecord incentiveActivityRecord = recordRepo.save(record); + if (incentiveActivityRecord == null) { + recordRepo.save(record); + pendindDocService.updatePendingActivity(userId, mdsr.getId(), record.getId(), immunizationActivity.getId()); + } + } + } else { + recordRepo.save(record); + } + } + } } diff --git a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java index 0e329f4b..3170deba 100644 --- a/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DeliveryOutcomeServiceImpl.java @@ -11,6 +11,7 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.DeliveryOutcomeDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.identity.HouseHoldRepo; import com.iemr.flw.repo.iemr.DeliveryOutcomeRepo; @@ -18,6 +19,7 @@ import com.iemr.flw.repo.iemr.IncentivesRepo; import com.iemr.flw.repo.iemr.UserServiceRoleRepo; import com.iemr.flw.service.DeliveryOutcomeService; +import com.iemr.flw.service.UserService; import jakarta.annotation.PostConstruct; import org.apache.commons.lang3.Validate; import org.modelmapper.ModelMapper; @@ -27,6 +29,10 @@ import org.springframework.stereotype.Service; import java.math.BigInteger; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -51,6 +57,9 @@ public class DeliveryOutcomeServiceImpl implements DeliveryOutcomeService { @Autowired private UserServiceRoleRepo userRepo; + @Autowired + private UserService userService; + @Autowired private IncentiveRecordRepo recordRepo; @@ -108,98 +117,185 @@ public String registerDeliveryOutcome(List deliveryOutcomeDT @Override public List getDeliveryOutcome(GetBenRequestHandler dto) { try { - String user = beneficiaryRepo.getUserName(dto.getAshaId()); - List deliveryOutcomeList = deliveryOutcomeRepo.getDeliveryOutcomeByAshaId(user, dto.getFromDate(), dto.getToDate()); + String user = userRepo.getUserNamedByUserId(dto.getAshaId()); + List deliveryOutcomeList = deliveryOutcomeRepo.getDeliveryOutcomeByAshaId(user,dto.getFromDate(),dto.getToDate()); + logger.info("DeliveryOutcome Response{}",deliveryOutcomeList); return deliveryOutcomeList.stream() .map(deliveryOutcome -> mapper.convertValue(deliveryOutcome, DeliveryOutcomeDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { - logger.error(e.getMessage()); + logger.error("DeliveryOutcome Exception:"+e.getMessage()); } return null; } public void checkAndAddJsyIncentive(List delOutList) { + if(!delOutList.isEmpty()){ + Integer userID = userRepo.getUserIdByName(delOutList.get(0).getCreatedBy()); + Integer stateId = userService.getUserDetail(userID).getStateId(); + delOutList.forEach(deliveryOutcome -> { + + IncentiveActivity institutionalDeliveryActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MH_MOTIVATE_INST_DEL", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity institutionalDeliveryActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("INST_DELIVERY_ESCORT", GroupName.ACTIVITY.getDisplayName()); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); + + if (placeOfDelivery != null && + (!placeOfDelivery.equalsIgnoreCase("home") || + !placeOfDelivery.equalsIgnoreCase("in transit") || + !placeOfDelivery.equalsIgnoreCase("other private hospital"))) { + + // Institutional delivery (eligible case) + if (institutionalDeliveryActivityAM != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityAM); + } - delOutList.forEach(deliveryOutcome -> { - - IncentiveActivity institutionalDeliveryActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("MH_MOTIVATE_INST_DEL", GroupName.MATERNAL_HEALTH.getDisplayName()); - IncentiveActivity institutionalDeliveryActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("INST_DELIVERY_ESCORT", GroupName.ACTIVITY.getDisplayName()); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - String placeOfDelivery = deliveryOutcome.getPlaceOfDelivery(); - - if (placeOfDelivery != null && - (!placeOfDelivery.equalsIgnoreCase("home") || - !placeOfDelivery.equalsIgnoreCase("in transit") || - !placeOfDelivery.equalsIgnoreCase("other private hospital"))) { - - // Institutional delivery (eligible case) - if (institutionalDeliveryActivityAM != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityAM); + if (institutionalDeliveryActivityCH != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityCH); + } } + } - if (institutionalDeliveryActivityCH != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), institutionalDeliveryActivityCH); + if (deliveryOutcome.getIsJSYBenificiary()) { + IncentiveActivity incentiveActivityInstJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityInstJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + + + logger.info("delOutList" + gson.toJson(deliveryOutcome)); + IncentiveActivity incentiveActivityJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY1 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 1) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); + } + } } - } - } - if (deliveryOutcome.getIsJSYBenificiary()) { - IncentiveActivity incentiveActivityInstJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); - IncentiveActivity incentiveActivityInstJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_INST_RURAL", GroupName.JSY.getDisplayName()); + IncentiveActivity incentiveActivityJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY2 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 2) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY2); + if (deliveryOutcome.getPlaceOfDelivery() != null) { - logger.info("delOutList" + gson.toJson(deliveryOutcome)); - IncentiveActivity incentiveActivityJSY1 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_1ST_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY1 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 1) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY1); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY1); + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); + } } } - } + IncentiveActivity incentiveActivityJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY3 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 3) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY3); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); + } + } + } - IncentiveActivity incentiveActivityJSY2 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_2ND_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY2 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 2) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY2); - if (deliveryOutcome.getPlaceOfDelivery() != null) { + IncentiveActivity incentiveActivityJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); + if (incentiveActivityJSY4 != null) { + if (deliveryOutcome.getDeliveryOutcome() == 4) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY4); + if (deliveryOutcome.getPlaceOfDelivery() != null) { + createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY2); + } } } + } + if(deliveryOutcome.getDeliveryOutcome()!=null){ + if(!beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).isEmpty()){ + RMNCHBeneficiaryDetailsRmnch rmnchBeneficiaryDetailsRmnch = beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).get(0); + LocalDate marriageDate = rmnchBeneficiaryDetailsRmnch.getDateMarriage() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate deliveryDate = deliveryOutcome.getDateOfDelivery() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + long years = ChronoUnit.YEARS.between(marriageDate, deliveryDate); + if (years >= 2 && !rmnchBeneficiaryDetailsRmnch.getDoYouHavechildren()) { + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_DELAY_2Y", + GroupName.FAMILY_PLANNING.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + - IncentiveActivity incentiveActivityJSY3 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_3RD_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY3 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 3) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY3); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY3); } + } + + + } - IncentiveActivity incentiveActivityJSY4 = incentivesRepo.findIncentiveMasterByNameAndGroup("JSY_4TH_DEL_ANC_RURAL", GroupName.JSY.getDisplayName()); - if (incentiveActivityJSY4 != null) { - if (deliveryOutcome.getDeliveryOutcome() == 4) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityJSY4); - if (deliveryOutcome.getPlaceOfDelivery() != null) { - createIncentiveRecordforJsy(deliveryOutcome, deliveryOutcome.getBenId(), incentiveActivityInstJSY4); + if(deliveryOutcome.getDeliveryOutcome()!=null){ + if(!beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).isEmpty()){ + RMNCHBeneficiaryDetailsRmnch rmnchBeneficiaryDetailsRmnch = beneficiaryRepo.findByBenficieryid(deliveryOutcome.getBenId()).get(0); + LocalDate marriageDate = rmnchBeneficiaryDetailsRmnch.getDateMarriage() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + LocalDate deliveryDate = deliveryOutcome.getDateOfDelivery() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + + long years = ChronoUnit.YEARS.between(marriageDate, deliveryDate); + + if (years >= 3 && rmnchBeneficiaryDetailsRmnch.getDoYouHavechildren()) { + if(stateId.equals(StateCode.AM.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.FAMILY_PLANNING.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + if(stateId.equals(StateCode.CG.getStateCode())){ + IncentiveActivity activity = + incentivesRepo.findIncentiveMasterByNameAndGroup( + "1st_2nd_CHILD_GAP", + GroupName.ACTIVITY.getDisplayName()); + + createIncentiveRecordforYearGap(deliveryOutcome, deliveryOutcome.getBenId(), activity); + } + } } + + + } - } + + }); + } - }); // JSY_ANC_URBAN // JSY_INST_URBAN @@ -212,7 +308,41 @@ private void createIncentiveRecordforJsy(DeliveryOutcome delOutList, Long benId, try { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getCreatedDate(), benId); + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getDateOfDelivery(), benId,userRepo.getUserIdByName(delOutList.getUpdatedBy())); + + + if (record == null) { + logger.info("setStartDate" + delOutList.getDateOfDelivery()); + logger.info("setCreatedDate" + delOutList.getCreatedDate()); + record = new IncentiveActivityRecord(); + record.setActivityId(immunizationActivity.getId()); + record.setCreatedDate(delOutList.getDateOfDelivery()); + record.setCreatedBy(delOutList.getCreatedBy()); + record.setStartDate(delOutList.getDateOfDelivery()); + record.setEndDate(delOutList.getDateOfDelivery()); + record.setUpdatedDate(delOutList.getDateOfDelivery()); + record.setUpdatedBy(delOutList.getCreatedBy()); + record.setBenId(benId); + record.setAshaId(userRepo.getUserIdByName(delOutList.getUpdatedBy())); + record.setAmount(Long.valueOf(immunizationActivity.getRate())); + recordRepo.save(record); + } else { + logger.info("benId:" + record.getId()); + + } + } catch (Exception e) { + logger.error("JSY Incentive:", e); + } + + + } + + private void createIncentiveRecordforYearGap(DeliveryOutcome delOutList, Long benId, IncentiveActivity immunizationActivity) { + logger.info("benId" + benId); + + try { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(immunizationActivity.getId(), delOutList.getDateOfDelivery(), benId,userRepo.getUserIdByName(delOutList.getUpdatedBy())); if (record == null) { @@ -224,7 +354,7 @@ record = new IncentiveActivityRecord(); record.setCreatedBy(delOutList.getCreatedBy()); record.setStartDate(delOutList.getDateOfDelivery()); record.setEndDate(delOutList.getDateOfDelivery()); - record.setUpdatedDate(delOutList.getCreatedDate()); + record.setUpdatedDate(delOutList.getDateOfDelivery()); record.setUpdatedBy(delOutList.getCreatedBy()); record.setBenId(benId); record.setAshaId(userRepo.getUserIdByName(delOutList.getUpdatedBy())); diff --git a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java index bc780038..35746b2f 100644 --- a/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/DiseaseControlServiceImpl.java @@ -25,12 +25,21 @@ package com.iemr.flw.service.impl; import com.fasterxml.jackson.databind.ObjectMapper; -import com.iemr.flw.controller.CoupleController; +import com.iemr.flw.domain.identity.RMNCHBeneficiaryDetailsRmnch; import com.iemr.flw.domain.iemr.*; +import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.DiseaseType; +import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; +import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.DiseaseControlService; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; +import jakarta.transaction.Transactional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -42,6 +51,7 @@ import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; + import org.modelmapper.ModelMapper; @Service @@ -77,10 +87,23 @@ public class DiseaseControlServiceImpl implements DiseaseControlService { private MosquitoNetRepository mosquitoNetRepository; + @Autowired + private ChronicDiseaseVisitRepository chronicDiseaseVisitRepository; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private IncentiveLogicService incentiveLogicService; + + @Autowired + private UserService userService; + @Autowired + private BeneficiaryRepo beneficiaryRepo; - private final Logger logger = LoggerFactory.getLogger(CoupleController.class); + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); @Override public String saveMalaria(MalariaDTO diseaseControlDTO) { @@ -102,7 +125,7 @@ public String saveMalaria(MalariaDTO diseaseControlDTO) { @Override public String saveKalaAzar(KalaAzarDTO diseaseControlDTO) { - logger.info("Save request: "+diseaseControlDTO.toString()); + logger.info("Save request: " + diseaseControlDTO.toString()); for (DiseaseKalaAzarDTO diseaseControlData : diseaseControlDTO.getKalaAzarLists()) { if (diseaseKalaAzarRepository.findByBenId(diseaseControlData.getBenId()).isPresent()) { return updateKalaAzarDisease(diseaseControlData); @@ -268,6 +291,7 @@ private String updateFilaria(DiseaseFilariasisDTO diseaseControlData) { @Override + @Transactional public String saveLeprosy(LeprosyDTO diseaseControlDTO) { for (DiseaseLeprosyDTO diseaseControlData : diseaseControlDTO.getLeprosyLists()) { if (diseaseLeprosyRepository.findByBenId(diseaseControlData.getBenId()).isPresent()) { @@ -276,7 +300,21 @@ public String saveLeprosy(LeprosyDTO diseaseControlDTO) { if (diseaseControlDTO.getUserId() != null) { diseaseControlData.setUserId(diseaseControlDTO.getUserId()); } - diseaseLeprosyRepository.save(saveLeprosyData(diseaseControlData)); + ScreeningLeprosy screeningLeprosy = diseaseLeprosyRepository.save(saveLeprosyData(diseaseControlData)); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForIdentificationLeprosy( + screeningLeprosy.getBenId(), + screeningLeprosy.getHomeVisitDate(), + screeningLeprosy.getHomeVisitDate(), + diseaseControlDTO.getUserId()); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + return "Data add successfully"; } @@ -313,46 +351,54 @@ private LeprosyFollowUp saveLeprosyFollowUpData(LeprosyFollowUpDTO data) { entity.setModifiedBy(data.getModifiedBy()); entity.setLastModDate( data.getLastModDate() != null ? data.getLastModDate() : new Timestamp(System.currentTimeMillis())); - + if(!leprosyFollowUpRepository.findByBenId(entity.getBenId()).isEmpty()){ + if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=6 && leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()<=12){ + Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForLeprosyPaucibacillaryConfirmed( + entity.getBenId(), + entity.getTreatmentEndDate(), + entity.getTreatmentEndDate(), + userId); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + } + } + + if(!leprosyFollowUpRepository.findByBenId(entity.getBenId()).isEmpty()){ + if(leprosyFollowUpRepository.findByBenId(entity.getBenId()).size()>=12){ + Integer userId = userRepo.getUserIdByName(entity.getCreatedBy()); + IncentiveActivityRecord incentiveActivityRecord = + incentiveLogicService.incentiveForLeprosyMultibacillaryConfirmed( + entity.getBenId(), + entity.getTreatmentEndDate(), + entity.getTreatmentEndDate(), + userId); + + if (incentiveActivityRecord != null) { + logger.info("Incentive processed for Screening Leprosy successfully. RecordId={}", + incentiveActivityRecord.getId()); + } else { + logger.info("Incentive not created"); + } + } + } return entity; } - private String updateLeprosyFollowUpData(LeprosyFollowUpDTO data, LeprosyFollowUp entity) { - entity.setVisitNumber(data.getVisitNumber()); - entity.setFollowUpDate(data.getFollowUpDate()); - entity.setTreatmentStatus(data.getTreatmentStatus()); - entity.setMdtBlisterPackReceived(data.getMdtBlisterPackReceived()); - entity.setTreatmentCompleteDate(data.getTreatmentCompleteDate()); - entity.setRemarks(data.getRemarks()); - entity.setHomeVisitDate(data.getHomeVisitDate()); - entity.setLeprosySymptoms(data.getLeprosySymptoms()); - entity.setTypeOfLeprosy(data.getTypeOfLeprosy()); - entity.setLeprosySymptomsPosition(data.getLeprosySymptomsPosition()); - entity.setVisitLabel(data.getVisitLabel()); - entity.setLeprosyStatus(data.getLeprosyStatus()); - entity.setReferredTo(data.getReferredTo()); - entity.setReferToName(data.getReferToName()); - entity.setTreatmentEndDate(data.getTreatmentEndDate()); - entity.setMdtBlisterPackRecived(data.getMdtBlisterPackRecived()); - entity.setTreatmentStartDate(data.getTreatmentStartDate()); - - // Update audit info - entity.setModifiedBy(data.getModifiedBy()); - entity.setLastModDate( - data.getLastModDate() != null ? data.getLastModDate() : new Timestamp(System.currentTimeMillis())); - - leprosyFollowUpRepository.save(entity); - return "Follow-up data updated successfully"; - } - @Override public String saveLeprosyFollowUp(LeprosyFollowUpDTO dto) { if (dto == null) return "Invalid data"; - LeprosyFollowUp entity = saveLeprosyFollowUpData(dto); - leprosyFollowUpRepository.save(entity); - return "Follow-up data added successfully"; - + LeprosyFollowUp entity = saveLeprosyFollowUpData(dto); + leprosyFollowUpRepository.save(entity); + return "Follow-up data added successfully"; + } @Override @@ -369,7 +415,6 @@ public List getAllLeprosyData(String createdBy) { return dtos; } - @Override public List getAllLeprosyFollowUpData(String createdBy) { logger.info("Fetching leprosy data for createdBy: " + createdBy); @@ -390,47 +435,102 @@ public Object getAllMalaria(GetDiseaseRequestHandler getDiseaseRequestHandler) { // Fetch and filter malaria disease records List filteredList = diseaseMalariaRepository.findAll().stream() - .filter(disease -> Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getUserId())) + .filter(disease -> Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getAshaId())) .collect(Collectors.toList()); // Check if the list is empty if (filteredList.isEmpty()) { - return Collections.singletonMap("message", "No data found for Malaria."); + return filteredList; } // Map to DTOs List dtoList = filteredList.stream().map(disease -> { + DiseaseMalariaDTO dto = new DiseaseMalariaDTO(); - // Map fields from DiseaseMalaria to DTO - dto.setId(disease.getId()); - dto.setBenId(disease.getBenId()); - dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); - dto.setScreeningDate(disease.getScreeningDate()); - dto.setBeneficiaryStatus(disease.getBeneficiaryStatus()); - dto.setDateOfDeath(disease.getDateOfDeath()); - dto.setPlaceOfDeath(disease.getPlaceOfDeath()); - dto.setOtherPlaceOfDeath(disease.getOtherPlaceOfDeath()); - dto.setReasonForDeath(disease.getReasonForDeath()); - dto.setOtherReasonForDeath(disease.getOtherReasonForDeath()); - dto.setCaseStatus(disease.getCaseStatus()); - dto.setRapidDiagnosticTest(disease.getRapidDiagnosticTest()); - dto.setDateOfRdt(disease.getDateOfRdt()); - dto.setSlideTestPf(disease.getSlideTestPf()); - dto.setSlideTestPv(disease.getSlideTestPv()); - dto.setDateOfSlideTest(disease.getDateOfSlideTest()); - dto.setSlideNo(disease.getSlideNo()); - dto.setReferredTo(disease.getReferredTo()); - dto.setOtherReferredFacility(disease.getOtherReferredFacility()); - dto.setRemarks(disease.getRemarks()); - dto.setDateOfVisitBySupervisor(disease.getDateOfVisitBySupervisor()); - dto.setUserId(disease.getUserId()); - dto.setDiseaseTypeId(disease.getDiseaseTypeId()); - - // Parse symptoms (if present) + if (disease.getId() != null) + dto.setId(disease.getId()); + + if (disease.getBenId() != null) + dto.setBenId(disease.getBenId()); + + if (disease.getHouseHoldDetailsId() != null) + dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); + + if (disease.getScreeningDate() != null) + dto.setScreeningDate(disease.getScreeningDate()); + + if (disease.getBeneficiaryStatus() != null && !disease.getBeneficiaryStatus().trim().isEmpty()) + dto.setBeneficiaryStatus(disease.getBeneficiaryStatus()); + + if (disease.getDateOfDeath() != null) + dto.setDateOfDeath(disease.getDateOfDeath()); + + if (disease.getPlaceOfDeath() != null && !disease.getPlaceOfDeath().trim().isEmpty()) + dto.setPlaceOfDeath(disease.getPlaceOfDeath()); + + if (disease.getOtherPlaceOfDeath() != null && !disease.getOtherPlaceOfDeath().trim().isEmpty()) + dto.setOtherPlaceOfDeath(disease.getOtherPlaceOfDeath()); + + if (disease.getReasonForDeath() != null && !disease.getReasonForDeath().trim().isEmpty()) + dto.setReasonForDeath(disease.getReasonForDeath()); + + if (disease.getOtherReasonForDeath() != null && !disease.getOtherReasonForDeath().trim().isEmpty()) + dto.setOtherReasonForDeath(disease.getOtherReasonForDeath()); + + if (disease.getCaseStatus() != null && !disease.getCaseStatus().trim().isEmpty()) + dto.setCaseStatus(disease.getCaseStatus()); + + if (disease.getRapidDiagnosticTest() != null) + dto.setRapidDiagnosticTest(disease.getRapidDiagnosticTest()); + + if (disease.getDateOfRdt() != null) + dto.setDateOfRdt(disease.getDateOfRdt()); + + if (disease.getSlideTestPf() != null) + dto.setSlideTestPf(disease.getSlideTestPf()); + + if (disease.getSlideTestPv() != null) + dto.setSlideTestPv(disease.getSlideTestPv()); + + if (disease.getDateOfSlideTest() != null) + dto.setDateOfSlideTest(disease.getDateOfSlideTest()); + + if (disease.getSlideNo() != null && !disease.getSlideNo().trim().isEmpty()) + dto.setSlideNo(disease.getSlideNo()); + + if (disease.getReferredTo() != null) + dto.setReferredTo(disease.getReferredTo()); + + if (disease.getOtherReferredFacility() != null && !disease.getOtherReferredFacility().trim().isEmpty()) + dto.setOtherReferredFacility(disease.getOtherReferredFacility()); + + if (disease.getRemarks() != null && !disease.getRemarks().trim().isEmpty()) + dto.setRemarks(disease.getRemarks()); + + if (disease.getMalariaSlideTestType() != null && !disease.getMalariaSlideTestType().trim().isEmpty()) + dto.setMalariaSlideTestType(disease.getMalariaSlideTestType()); + + if (disease.getMalariaTestType() != null && !disease.getMalariaTestType().trim().isEmpty()) + dto.setMalariaTestType(disease.getMalariaTestType()); + + if (disease.getDateOfVisitBySupervisor() != null) + dto.setDateOfVisitBySupervisor(disease.getDateOfVisitBySupervisor()); + + if (disease.getUserId() != null) + dto.setUserId(disease.getUserId()); + + if (disease.getDiseaseTypeId() != null) + dto.setDiseaseTypeId(disease.getDiseaseTypeId()); + + // Symptoms JSON try { - if (disease.getSymptoms() != null && !disease.getSymptoms().isEmpty()) { - MalariaSymptomsDTO symptomsDTO = objectMapper.readValue(disease.getSymptoms(), MalariaSymptomsDTO.class); + if (disease.getSymptoms() != null && + !disease.getSymptoms().trim().isEmpty()) { + + MalariaSymptomsDTO symptomsDTO = + objectMapper.readValue(disease.getSymptoms(), MalariaSymptomsDTO.class); + dto.setFeverMoreThanTwoWeeks(symptomsDTO.isFeverMoreThanTwoWeeks()); dto.setFluLikeIllness(symptomsDTO.isFluLikeIllness()); dto.setShakingChills(symptomsDTO.isShakingChills()); @@ -442,7 +542,8 @@ public Object getAllMalaria(GetDiseaseRequestHandler getDiseaseRequestHandler) { dto.setDiarrhea(symptomsDTO.isDiarrhea()); } } catch (Exception e) { - throw new RuntimeException("Error parsing symptoms JSON for Malaria Disease ID: " + disease.getId(), e); + logger.error("Error parsing symptoms for diseaseId={}", + disease.getId(), e); } return dto; @@ -478,40 +579,87 @@ public Object getAllKalaAzar(GetDiseaseRequestHandler getDiseaseRequestHandler) // Fetch and filter Kala Azar disease records List filteredList = diseaseKalaAzarRepository.findAll().stream() - .filter(disease -> (Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getUserId()))) + .filter(disease -> (Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getAshaId()))) .collect(Collectors.toList()); // Check if the list is empty if (filteredList.isEmpty()) { - return Collections.singletonMap("message", "No data found for Kala Azar."); + return filteredList; } // Map to DTOs List dtoList = filteredList.stream().map(disease -> { + DiseaseKalaAzarDTO dto = new DiseaseKalaAzarDTO(); - dto.setId(disease.getId()); - dto.setBenId(disease.getBenId()); - dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); - dto.setVisitDate(disease.getVisitDate()); - dto.setBeneficiaryStatus(disease.getBeneficiaryStatus()); - dto.setDateOfDeath(disease.getDateOfDeath()); - dto.setPlaceOfDeath(disease.getPlaceOfDeath()); - dto.setOtherPlaceOfDeath(disease.getOtherPlaceOfDeath()); - dto.setReasonForDeath(disease.getReasonForDeath()); - dto.setOtherReasonForDeath(disease.getOtherReasonForDeath()); - dto.setKalaAzarCaseStatus(disease.getKalaAzarCaseStatus()); - dto.setKalaAzarCaseCount(disease.getKalaAzarCaseCount()); - dto.setRapidDiagnosticTest(disease.getRapidDiagnosticTest()); - dto.setDateOfRdt(disease.getDateOfRdt()); - dto.setFollowUpPoint(disease.getFollowUpPoint()); - dto.setReferredTo(disease.getReferredTo()); - dto.setOtherReferredFacility(disease.getOtherReferredFacility()); - dto.setCreatedDate(disease.getCreatedDate()); - dto.setCreatedBy(disease.getCreatedBy()); - dto.setBeneficiaryStatusId(disease.getBeneficiaryStatusId()); - dto.setReferToName(disease.getReferToName()); - dto.setUserId(disease.getUserId()); - dto.setDiseaseTypeId(disease.getDiseaseTypeId()); + + if (disease.getId() != null) + dto.setId(disease.getId()); + + if (disease.getBenId() != null) + dto.setBenId(disease.getBenId()); + + if (disease.getHouseHoldDetailsId() != null) + dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); + + if (disease.getVisitDate() != null) + dto.setVisitDate(disease.getVisitDate()); + + if (disease.getBeneficiaryStatus() != null && !disease.getBeneficiaryStatus().trim().isEmpty()) + dto.setBeneficiaryStatus(disease.getBeneficiaryStatus()); + + if (disease.getDateOfDeath() != null) + dto.setDateOfDeath(disease.getDateOfDeath()); + + if (disease.getPlaceOfDeath() != null && !disease.getPlaceOfDeath().trim().isEmpty()) + dto.setPlaceOfDeath(disease.getPlaceOfDeath()); + + if (disease.getOtherPlaceOfDeath() != null && !disease.getOtherPlaceOfDeath().trim().isEmpty()) + dto.setOtherPlaceOfDeath(disease.getOtherPlaceOfDeath()); + + if (disease.getReasonForDeath() != null && !disease.getReasonForDeath().trim().isEmpty()) + dto.setReasonForDeath(disease.getReasonForDeath()); + + if (disease.getOtherReasonForDeath() != null && !disease.getOtherReasonForDeath().trim().isEmpty()) + dto.setOtherReasonForDeath(disease.getOtherReasonForDeath()); + + if (disease.getKalaAzarCaseStatus() != null && !disease.getKalaAzarCaseStatus().trim().isEmpty()) + dto.setKalaAzarCaseStatus(disease.getKalaAzarCaseStatus()); + + if (disease.getKalaAzarCaseCount() != null) + dto.setKalaAzarCaseCount(disease.getKalaAzarCaseCount()); + + if (disease.getRapidDiagnosticTest() != null) + dto.setRapidDiagnosticTest(disease.getRapidDiagnosticTest()); + + if (disease.getDateOfRdt() != null) + dto.setDateOfRdt(disease.getDateOfRdt()); + + if (disease.getFollowUpPoint() != null) + dto.setFollowUpPoint(disease.getFollowUpPoint()); + + if (disease.getReferredTo() != null && !disease.getReferredTo().trim().isEmpty()) + dto.setReferredTo(disease.getReferredTo()); + + if (disease.getOtherReferredFacility() != null && !disease.getOtherReferredFacility().trim().isEmpty()) + dto.setOtherReferredFacility(disease.getOtherReferredFacility()); + + if (disease.getCreatedDate() != null) + dto.setCreatedDate(disease.getCreatedDate()); + + if (disease.getCreatedBy() != null && !disease.getCreatedBy().trim().isEmpty()) + dto.setCreatedBy(disease.getCreatedBy()); + + if (disease.getBeneficiaryStatusId() != null) + dto.setBeneficiaryStatusId(disease.getBeneficiaryStatusId()); + + if (disease.getReferToName() != null && !disease.getReferToName().trim().isEmpty()) + dto.setReferToName(disease.getReferToName()); + + if (disease.getUserId() != null) + dto.setUserId(disease.getUserId()); + + if (disease.getDiseaseTypeId() != null) + dto.setDiseaseTypeId(disease.getDiseaseTypeId()); return dto; }).collect(Collectors.toList()); @@ -522,17 +670,17 @@ public Object getAllKalaAzar(GetDiseaseRequestHandler getDiseaseRequestHandler) public Object getAllKalaAES(GetDiseaseRequestHandler getDiseaseRequestHandler) { if (diseaseAESJERepository.findAll().isEmpty()) { - return Collections.singletonMap("message", "No data found for AES."); + return diseaseAESJERepository.findAll(); } - return diseaseAESJERepository.findAll().stream().filter(diseaseAesje -> Objects.equals(diseaseAesje.getUserId(), getDiseaseRequestHandler.getUserId())).collect(Collectors.toList()); + return diseaseAESJERepository.findAll().stream().filter(diseaseAesje -> Objects.equals(diseaseAesje.getUserId(), getDiseaseRequestHandler.getAshaId())).collect(Collectors.toList()); } public Object getAllFilaria(GetDiseaseRequestHandler getDiseaseRequestHandler) { // Fetch and filter Filaria disease records - List filteredList = diseaseFilariasisRepository.findAll().stream().filter(screeningFilariasis -> Objects.equals(screeningFilariasis.getUserId(), getDiseaseRequestHandler.getUserId())).collect(Collectors.toList()); + List filteredList = diseaseFilariasisRepository.findAll().stream().filter(screeningFilariasis -> Objects.equals(screeningFilariasis.getUserId(), getDiseaseRequestHandler.getAshaId())).collect(Collectors.toList()); // Check if the list is empty if (filteredList.isEmpty()) { @@ -541,23 +689,58 @@ public Object getAllFilaria(GetDiseaseRequestHandler getDiseaseRequestHandler) { // Map to DTOs List dtoList = filteredList.stream().map(disease -> { + DiseaseFilariasisDTO dto = new DiseaseFilariasisDTO(); - dto.setId(disease.getId()); - dto.setBenId(disease.getBenId()); - dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); - dto.setSufferingFromFilariasis(disease.getSufferingFromFilariasis()); - dto.setAffectedBodyPart(disease.getAffectedBodyPart()); - dto.setMdaHomeVisitDate(disease.getMdaHomeVisitDate()); - dto.setDoseStatus(disease.getDoseStatus()); - dto.setFilariasisCaseCount(disease.getFilariasisCaseCount()); - dto.setOtherDoseStatusDetails(disease.getOtherDoseStatusDetails()); - dto.setMedicineSideEffect(disease.getMedicineSideEffect()); - dto.setOtherSideEffectDetails(disease.getOtherSideEffectDetails()); - dto.setCreatedDate(disease.getCreatedDate()); - dto.setCreatedBy(disease.getCreatedBy()); - dto.setUserId(disease.getUserId()); + + if (disease.getId() != null) + dto.setId(disease.getId()); + + if (disease.getBenId() != null) + dto.setBenId(disease.getBenId()); + + if (disease.getHouseHoldDetailsId() != null) + dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); + + if (disease.getSufferingFromFilariasis() != null) + dto.setSufferingFromFilariasis(disease.getSufferingFromFilariasis()); + + if (disease.getAffectedBodyPart() != null && + !disease.getAffectedBodyPart().trim().isEmpty()) + dto.setAffectedBodyPart(disease.getAffectedBodyPart()); + + if (disease.getMdaHomeVisitDate() != null) + dto.setMdaHomeVisitDate(disease.getMdaHomeVisitDate()); + + if (disease.getDoseStatus() != null && + !disease.getDoseStatus().trim().isEmpty()) + dto.setDoseStatus(disease.getDoseStatus()); + + if (disease.getFilariasisCaseCount() != null) + dto.setFilariasisCaseCount(disease.getFilariasisCaseCount()); + + if (disease.getOtherDoseStatusDetails() != null && + !disease.getOtherDoseStatusDetails().trim().isEmpty()) + dto.setOtherDoseStatusDetails(disease.getOtherDoseStatusDetails()); + + if (disease.getMedicineSideEffect() != null) + dto.setMedicineSideEffect(disease.getMedicineSideEffect()); + + if (disease.getOtherSideEffectDetails() != null && + !disease.getOtherSideEffectDetails().trim().isEmpty()) + dto.setOtherSideEffectDetails(disease.getOtherSideEffectDetails()); + + if (disease.getCreatedDate() != null) + dto.setCreatedDate(disease.getCreatedDate()); + + if (disease.getCreatedBy() != null && + !disease.getCreatedBy().trim().isEmpty()) + dto.setCreatedBy(disease.getCreatedBy()); + + if (disease.getUserId() != null) + dto.setUserId(disease.getUserId()); return dto; + }).collect(Collectors.toList()); return dtoList; @@ -568,30 +751,55 @@ public Object getAllLeprosy(GetDiseaseRequestHandler getDiseaseRequestHandler) { // Fetch and filter Leprosy disease records List filteredList = diseaseLeprosyRepository.findAll().stream() - .filter(disease -> Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getUserId())) + .filter(disease -> Objects.equals(disease.getUserId(), getDiseaseRequestHandler.getAshaId())) .collect(Collectors.toList()); // Check if the list is empty if (filteredList.isEmpty()) { - return Collections.singletonMap("message", "No data found for Leprosy."); + return filteredList; } // Map to DTOs List dtoList = filteredList.stream().map(disease -> { DiseaseLeprosyDTO dto = new DiseaseLeprosyDTO(); - dto.setId(disease.getId()); - dto.setBenId(disease.getBenId()); - dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); - dto.setHomeVisitDate(disease.getHomeVisitDate()); - dto.setLeprosyStatus(disease.getLeprosyStatus()); - dto.setReferredTo(disease.getReferredTo()); - dto.setOtherReferredTo(disease.getOtherReferredTo()); - dto.setLeprosyStatusDate(disease.getLeprosyStatusDate()); - dto.setTypeOfLeprosy(disease.getTypeOfLeprosy()); - dto.setFollowUpDate(disease.getFollowUpDate()); - dto.setBeneficiaryStatus(disease.getLeprosyStatus()); - dto.setRemark(disease.getRemark()); - dto.setUserId(disease.getUserId()); + if (disease.getId() != null) + dto.setId(disease.getId()); + + if (disease.getBenId() != null) + dto.setBenId(disease.getBenId()); + + if (disease.getHouseHoldDetailsId() != null) + dto.setHouseHoldDetailsId(disease.getHouseHoldDetailsId()); + + if (disease.getHomeVisitDate() != null) + dto.setHomeVisitDate(disease.getHomeVisitDate()); + + if (disease.getLeprosyStatus() != null && !disease.getLeprosyStatus().trim().isEmpty()) + dto.setLeprosyStatus(disease.getLeprosyStatus()); + + if (disease.getReferredTo() != null && !disease.getReferredTo().trim().isEmpty()) + dto.setReferredTo(disease.getReferredTo()); + + if (disease.getOtherReferredTo() != null && !disease.getOtherReferredTo().trim().isEmpty()) + dto.setOtherReferredTo(disease.getOtherReferredTo()); + + if (disease.getLeprosyStatusDate() != null) + dto.setLeprosyStatusDate(disease.getLeprosyStatusDate()); + + if (disease.getTypeOfLeprosy() != null && !disease.getTypeOfLeprosy().trim().isEmpty()) + dto.setTypeOfLeprosy(disease.getTypeOfLeprosy()); + + if (disease.getFollowUpDate() != null) + dto.setFollowUpDate(disease.getFollowUpDate()); + + if (disease.getLeprosyStatus() != null && !disease.getLeprosyStatus().trim().isEmpty()) + dto.setBeneficiaryStatus(disease.getLeprosyStatus()); + + if (disease.getRemark() != null && !disease.getRemark().trim().isEmpty()) + dto.setRemark(disease.getRemark()); + + if (disease.getUserId() != null) + dto.setUserId(disease.getUserId()); return dto; @@ -602,7 +810,7 @@ public Object getAllLeprosy(GetDiseaseRequestHandler getDiseaseRequestHandler) { private ScreeningKalaAzar saveKalaAzarDisease(DiseaseKalaAzarDTO dto) { - logger.info("KalaAzarRequest: "+dto); + logger.info("KalaAzarRequest: " + dto); ScreeningKalaAzar entity = new ScreeningKalaAzar(); entity.setBenId(dto.getBenId()); @@ -687,7 +895,10 @@ private ScreeningLeprosy saveLeprosyData(DiseaseLeprosyDTO diseaseControlData) { diseaseLeprosy.setDiseaseTypeId(diseaseControlData.getDiseaseTypeId()); diseaseLeprosy.setOtherReferredTo(diseaseControlData.getOtherReferredTo()); diseaseLeprosy.setLeprosyStatusDate(diseaseControlData.getLeprosyStatusDate()); - diseaseLeprosy.setTypeOfLeprosy(diseaseControlData.getTypeOfLeprosy()); + if(diseaseControlData.getTypeOfLeprosy()!=null){ + diseaseLeprosy.setTypeOfLeprosy(diseaseControlData.getTypeOfLeprosy()); + + } diseaseLeprosy.setFollowUpDate(diseaseControlData.getFollowUpDate()); diseaseLeprosy.setBeneficiaryStatus(diseaseControlData.getBeneficiaryStatus()); diseaseLeprosy.setBeneficiaryStatusId(diseaseControlData.getBeneficiaryStatusId()); @@ -717,6 +928,33 @@ private ScreeningLeprosy saveLeprosyData(DiseaseLeprosyDTO diseaseControlData) { diseaseLeprosy.setModifiedBy(diseaseControlData.getModifiedBy()); diseaseLeprosy.setLastModDate(diseaseControlData.getLastModDate()); + diseaseLeprosy.setRecurrentUlcerationId(diseaseControlData.getRecurrentUlcerationId()); + diseaseLeprosy.setRecurrentTinglingId(diseaseControlData.getRecurrentTinglingId()); + diseaseLeprosy.setHypopigmentedPatchId(diseaseControlData.getHypopigmentedPatchId()); + diseaseLeprosy.setThickenedSkinId(diseaseControlData.getThickenedSkinId()); + diseaseLeprosy.setSkinNodulesId(diseaseControlData.getSkinNodulesId()); + diseaseLeprosy.setSkinPatchDiscolorationId(diseaseControlData.getSkinPatchDiscolorationId()); + diseaseLeprosy.setRecurrentNumbnessId(diseaseControlData.getRecurrentNumbnessId()); + diseaseLeprosy.setClawingFingersId(diseaseControlData.getClawingFingersId()); + diseaseLeprosy.setTinglingNumbnessExtremitiesId(diseaseControlData.getTinglingNumbnessExtremitiesId()); + diseaseLeprosy.setInabilityCloseEyelidId(diseaseControlData.getInabilityCloseEyelidId()); + diseaseLeprosy.setDifficultyHoldingObjectsId(diseaseControlData.getDifficultyHoldingObjectsId()); + diseaseLeprosy.setWeaknessFeetId(diseaseControlData.getWeaknessFeetId()); + + diseaseLeprosy.setRecurrentUlceration(diseaseControlData.getRecurrentUlceration()); + diseaseLeprosy.setRecurrentTingling(diseaseControlData.getRecurrentTingling()); + diseaseLeprosy.setHypopigmentedPatch(diseaseControlData.getHypopigmentedPatch()); + diseaseLeprosy.setThickenedSkin(diseaseControlData.getThickenedSkin()); + diseaseLeprosy.setSkinNodules(diseaseControlData.getSkinNodules()); + diseaseLeprosy.setSkinPatchDiscoloration(diseaseControlData.getSkinPatchDiscoloration()); + diseaseLeprosy.setRecurrentNumbness(diseaseControlData.getRecurrentNumbness()); + diseaseLeprosy.setClawingFingers(diseaseControlData.getClawingFingers()); + diseaseLeprosy.setTinglingNumbnessExtremities(diseaseControlData.getTinglingNumbnessExtremities()); + diseaseLeprosy.setInabilityCloseEyelid(diseaseControlData.getInabilityCloseEyelid()); + diseaseLeprosy.setDifficultyHoldingObjects(diseaseControlData.getDifficultyHoldingObjects()); + diseaseLeprosy.setWeaknessFeet(diseaseControlData.getWeaknessFeet()); + + return diseaseLeprosy; } @@ -761,6 +999,33 @@ private String updateLeprosyData(DiseaseLeprosyDTO diseaseControlData) { existingDiseaseLeprosy.setModifiedBy(diseaseControlData.getModifiedBy()); existingDiseaseLeprosy.setLastModDate(diseaseControlData.getLastModDate()); + existingDiseaseLeprosy.setRecurrentUlcerationId(diseaseControlData.getRecurrentUlcerationId()); + existingDiseaseLeprosy.setRecurrentTinglingId(diseaseControlData.getRecurrentTinglingId()); + existingDiseaseLeprosy.setHypopigmentedPatchId(diseaseControlData.getHypopigmentedPatchId()); + existingDiseaseLeprosy.setThickenedSkinId(diseaseControlData.getThickenedSkinId()); + existingDiseaseLeprosy.setSkinNodulesId(diseaseControlData.getSkinNodulesId()); + existingDiseaseLeprosy.setSkinPatchDiscolorationId(diseaseControlData.getSkinPatchDiscolorationId()); + existingDiseaseLeprosy.setRecurrentNumbnessId(diseaseControlData.getRecurrentNumbnessId()); + existingDiseaseLeprosy.setClawingFingersId(diseaseControlData.getClawingFingersId()); + existingDiseaseLeprosy.setTinglingNumbnessExtremitiesId(diseaseControlData.getTinglingNumbnessExtremitiesId()); + existingDiseaseLeprosy.setInabilityCloseEyelidId(diseaseControlData.getInabilityCloseEyelidId()); + existingDiseaseLeprosy.setDifficultyHoldingObjectsId(diseaseControlData.getDifficultyHoldingObjectsId()); + existingDiseaseLeprosy.setWeaknessFeetId(diseaseControlData.getWeaknessFeetId()); + + existingDiseaseLeprosy.setRecurrentUlceration(diseaseControlData.getRecurrentUlceration()); + existingDiseaseLeprosy.setRecurrentTingling(diseaseControlData.getRecurrentTingling()); + existingDiseaseLeprosy.setHypopigmentedPatch(diseaseControlData.getHypopigmentedPatch()); + existingDiseaseLeprosy.setThickenedSkin(diseaseControlData.getThickenedSkin()); + existingDiseaseLeprosy.setSkinNodules(diseaseControlData.getSkinNodules()); + existingDiseaseLeprosy.setSkinPatchDiscoloration(diseaseControlData.getSkinPatchDiscoloration()); + existingDiseaseLeprosy.setRecurrentNumbness(diseaseControlData.getRecurrentNumbness()); + existingDiseaseLeprosy.setClawingFingers(diseaseControlData.getClawingFingers()); + existingDiseaseLeprosy.setTinglingNumbnessExtremities(diseaseControlData.getTinglingNumbnessExtremities()); + existingDiseaseLeprosy.setInabilityCloseEyelid(diseaseControlData.getInabilityCloseEyelid()); + existingDiseaseLeprosy.setDifficultyHoldingObjects(diseaseControlData.getDifficultyHoldingObjects()); + existingDiseaseLeprosy.setWeaknessFeet(diseaseControlData.getWeaknessFeet()); + + diseaseLeprosyRepository.save(existingDiseaseLeprosy); // Return the updated entity return "Data update successfully"; @@ -789,6 +1054,8 @@ private ScreeningMalaria saveMalariaDisease(DiseaseMalariaDTO requestData) { diseaseScreening.setSlideTestPv(requestData.getSlideTestPv()); diseaseScreening.setDateOfSlideTest(requestData.getDateOfSlideTest()); diseaseScreening.setSlideNo(requestData.getSlideNo()); + diseaseScreening.setMalariaTestType(requestData.getMalariaTestType()); + diseaseScreening.setMalariaSlideTestType(requestData.getMalariaSlideTestType()); diseaseScreening.setReferredTo(requestData.getReferredTo()); diseaseScreening.setOtherReferredFacility(requestData.getOtherReferredFacility()); diseaseScreening.setRemarks(requestData.getRemarks()); @@ -823,6 +1090,8 @@ private String updateMalariaDisease(DiseaseMalariaDTO requestData) { diseaseScreening.setSlideNo(requestData.getSlideNo()); diseaseScreening.setReferredTo(requestData.getReferredTo()); diseaseScreening.setOtherReferredFacility(requestData.getOtherReferredFacility()); + diseaseScreening.setMalariaSlideTestType(requestData.getMalariaSlideTestType()); + diseaseScreening.setMalariaTestType(requestData.getMalariaTestType()); diseaseScreening.setRemarks(requestData.getRemarks()); diseaseScreening.setCreatedDate(Timestamp.valueOf(LocalDateTime.now())); diseaseScreening.setDateOfVisitBySupervisor(requestData.getDateOfVisitBySupervisor()); @@ -861,8 +1130,10 @@ public List saveMosquitoMobilizationNet(List mos List entityList = mosquitoNetDTOList.stream().map(dto -> { MosquitoNetEntity entity = new MosquitoNetEntity(); + if(!beneficiaryRepo.findByHouseoldId(dto.getHouseHoldId()).isEmpty()){ + entity.setBeneficiaryId(beneficiaryRepo.findByHouseoldId(dto.getHouseHoldId()).get(0).getBenficieryid()); - entity.setBeneficiaryId(dto.getBeneficiaryId()); + } entity.setHouseHoldId(dto.getHouseHoldId()); // ✅ String → LocalDate conversion @@ -887,12 +1158,10 @@ public List saveMosquitoMobilizationNet(List mos }).collect(Collectors.toList()); - // ✅ Save all List savedEntities = mosquitoNetRepository.saveAll(entityList); - // ✅ Entity → DTO return return savedEntities.stream().map(entity -> { @@ -913,7 +1182,7 @@ public List saveMosquitoMobilizationNet(List mos if (dto.getFields() != null) { dto.getFields().setIs_net_distributed(entity.getIsNetDistributed()); } - + checkAndAddIncentives(entity); return dto; }).collect(Collectors.toList()); @@ -940,62 +1209,317 @@ public List getAllMosquitoMobilizationNet(Integer userId) { mosquitoNetListDTO.setIs_net_distributed(entity.getIsNetDistributed()); mosquitoNetListDTO.setVisit_date(entity.getVisitDate().format(formatter)); - dto.setFields(mosquitoNetListDTO); + dto.setFields(mosquitoNetListDTO); + return dto; }).collect(Collectors.toList()); } + private void checkAndAddIncentives(MosquitoNetEntity mosquitoNetEntity) { + Integer stateId = userService.getUserDetail(mosquitoNetEntity.getUserId()).getStateId(); + IncentiveActivity activityMobilizingMosquitoNets = incentivesRepo.findIncentiveMasterByNameAndGroup("MOSQUITO_NET_DISTRIBUTION_MOBILIZATION", GroupName.ACTIVITY.getDisplayName()); + if(stateId.equals(StateCode.CG.getStateCode())){ + addIncentive(activityMobilizingMosquitoNets, mosquitoNetEntity); + } + } private void checkAndAddIncentives(ScreeningMalaria diseaseScreening) { - IncentiveActivity diseaseScreeningActivity; - if (Objects.equals(diseaseScreening.getCaseStatus(), "Confirmed Case")) { - diseaseScreeningActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("MALARIA_1", "DISEASECONTROL"); + Integer stateId = userService.getUserDetail(diseaseScreening.getUserId()).getStateId(); + IncentiveActivity diseaseScreeningActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("NVBDCP_MALARIA_TREATMENT", GroupName.UMBRELLA_PROGRAMMES.getDisplayName()); + IncentiveActivity diseaseScreeningActivityCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NVBDCP_MALARIA_TREATMENT", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity incentiveActivityForCollectSlideAM = incentivesRepo.findIncentiveMasterByNameAndGroup("NVBDCP_SLIDE_COLLECTION", GroupName.UMBRELLA_PROGRAMMES.getDisplayName()); + IncentiveActivity incentiveActivityForCollectSlideCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NVBDCP_SLIDE_COLLECTION", GroupName.ACTIVITY.getDisplayName()); + + if (diseaseScreeningActivity != null) { + if(stateId.equals(StateCode.AM.getStateCode())){ + if (Objects.equals(diseaseScreening.getCaseStatus(), "Confirmed")) { + addIncentive(diseaseScreeningActivity, diseaseScreening); - } else { - diseaseScreeningActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("MALARIA_2", "DISEASECONTROL"); + } + } + if(stateId.equals(StateCode.CG.getStateCode())){ + if (Objects.equals(diseaseScreening.getCaseStatus(), "Confirmed")) { + addIncentive(diseaseScreeningActivityCG, diseaseScreening); + + } + } } + if (diseaseScreening.getCaseStatus().equals("Suspected")) { + if (!diseaseScreening.getMalariaTestType().isEmpty()) { + if (stateId.equals(StateCode.AM.getStateCode())) { + if (incentiveActivityForCollectSlideAM != null) { + addIncentive(incentiveActivityForCollectSlideAM, diseaseScreening); - if (diseaseScreeningActivity != null) { + } + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + if (incentiveActivityForCollectSlideCG != null) { + addIncentive(incentiveActivityForCollectSlideCG, diseaseScreening); + + } + } + + + } + + } + } + private void addIncentive(IncentiveActivity diseaseScreeningActivity, MosquitoNetEntity diseaseScreening) { + + Timestamp visitTimestamp = + Timestamp.valueOf(diseaseScreening.getVisitDate().atStartOfDay()); + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId( + diseaseScreeningActivity.getId(), + visitTimestamp, + diseaseScreening.getBeneficiaryId(),diseaseScreening.getUserId()); + + if (record == null) { + + record = new IncentiveActivityRecord(); + + record.setActivityId(diseaseScreeningActivity.getId()); + record.setCreatedDate(visitTimestamp); + record.setCreatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setStartDate(visitTimestamp); + record.setEndDate(visitTimestamp); + record.setUpdatedDate(visitTimestamp); + record.setUpdatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setBenId(diseaseScreening.getBeneficiaryId().longValue()); + record.setAshaId(diseaseScreening.getUserId()); + record.setAmount(Long.valueOf(diseaseScreeningActivity.getRate())); + record.setIsEligible(true); + + recordRepo.save(record); + } + + } + + + private void addIncentive(IncentiveActivity diseaseScreeningActivity, ScreeningMalaria diseaseScreening) { + try { + Timestamp screeningTimestamp = diseaseScreening.getScreeningDate() != null + ? new Timestamp(diseaseScreening.getScreeningDate().getTime()) + : null; IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(diseaseScreeningActivity.getId(), Timestamp.valueOf(diseaseScreening.getCreatedDate().toString()), diseaseScreening.getBenId().longValue()); + .findRecordByActivityIdCreatedDateBenId(diseaseScreeningActivity.getId(), Timestamp.valueOf(diseaseScreening.getCreatedDate().toString()), diseaseScreening.getBenId().longValue(),diseaseScreening.getUserId()); if (record == null) { - if (Objects.equals(diseaseScreening.getCaseStatus(), "Confirmed Case")) { - record = new IncentiveActivityRecord(); - record.setActivityId(diseaseScreeningActivity.getId()); - record.setCreatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setCreatedBy(diseaseScreening.getCreatedBy()); - record.setStartDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setEndDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedBy(diseaseScreening.getCreatedBy()); - record.setBenId(diseaseScreening.getBenId().longValue()); - record.setAshaId(diseaseScreening.getUserId()); - record.setName(diseaseScreeningActivity.getName()); - record.setAmount(Long.valueOf(diseaseScreeningActivity.getRate())); - recordRepo.save(record); - } else { - record = new IncentiveActivityRecord(); - record.setActivityId(diseaseScreeningActivity.getId()); - record.setCreatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setCreatedBy(diseaseScreening.getCreatedBy()); - record.setStartDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setEndDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedDate(Timestamp.valueOf(diseaseScreening.getCreatedDate().toString())); - record.setUpdatedBy(diseaseScreening.getCreatedBy()); - record.setBenId(diseaseScreening.getBenId().longValue()); - record.setName(diseaseScreeningActivity.getName()); - record.setAshaId(diseaseScreening.getUserId()); - record.setAmount(Long.valueOf(diseaseScreeningActivity.getRate())); - recordRepo.save(record); + record = new IncentiveActivityRecord(); + record.setActivityId(diseaseScreeningActivity.getId()); + record.setCreatedDate(screeningTimestamp); + record.setCreatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setStartDate(screeningTimestamp); + record.setEndDate(screeningTimestamp); + record.setUpdatedDate(screeningTimestamp); + record.setUpdatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setUpdatedBy(userService.getUserDetail(diseaseScreening.getUserId()).getUserName()); + record.setBenId(diseaseScreening.getBenId().longValue()); + record.setAshaId(diseaseScreening.getUserId()); + record.setAmount(Long.valueOf(diseaseScreeningActivity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + logger.info("Incentive for {}"+diseaseScreeningActivity.getDescription()); + + } + }catch (Exception e){ + logger.info("Fail to generate Incentive for {}"+diseaseScreeningActivity.getDescription()+ "Exception"+e.getMessage()); + + } + + } + + + @Override + public List saveChronicDiseaseVisit( + List requestList, String token) throws IEMRException { + Integer userId = jwtUtil.extractUserId(token); + String userName= userRepo.getUserNamedByUserId(userId); + + List responseList = new ArrayList<>(); + + for (ChronicDiseaseVisitDTO dto : requestList) { + + ChronicDiseaseVisitEntity entity = new ChronicDiseaseVisitEntity(); + + entity.setBenId(dto.getBenId()); + entity.setHhId(dto.getHhId()); + entity.setFormId(dto.getFormId()); + entity.setVersion(dto.getVersion()); + entity.setVisitNo(dto.getVisitNo()); + entity.setFollowUpNo(dto.getFollowUpNo()); + if (dto.getFollowUpDate() != null) { + entity.setFollowUpDate(dto.getFollowUpDate()); + + } + entity.setDiagnosisCodes(dto.getDiagnosisCodes()); + entity.setFormDataJson(dto.getFormDataJson()); + entity.setUserID(userId); + entity.setCreatedBy(userName); + entity.setUpdatedBy(userId); + + + if (dto.getTreatmentStartDate() != null) { + entity.setTreatmentStartDate( + LocalDate.parse(dto.getTreatmentStartDate()) + ); + } + + ChronicDiseaseVisitEntity savedEntity = + chronicDiseaseVisitRepository.save(entity); + + dto.setId(savedEntity.getId()); + responseList.add(dto); + checkIncentive(savedEntity, savedEntity.getUserID()); + + + } + + return responseList; + } + + private void checkIncentive(ChronicDiseaseVisitEntity chronicDiseaseVisitEntity, Integer ashaId) { + String userName = userRepo.getUserNamedByUserId(ashaId); + Integer stateId = userService.getUserDetail(ashaId).getStateId(); + IncentiveActivity incentiveActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_FOLLOWUP_TREATMENT", GroupName.NCD.getDisplayName()); + IncentiveActivity incentiveActivityCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_FOLLOWUP_TREATMENT", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity incentiveActivityCGForNCDnewPatient = incentivesRepo.findIncentiveMasterByNameAndGroup("NCD_NEW_PATIENT_MEDICATION_SUPPORT", GroupName.ACTIVITY.getDisplayName()); + logger.info("incentiveActivity:" + incentiveActivity.getId()); + + if (chronicDiseaseVisitEntity.getFollowUpNo() != null + && chronicDiseaseVisitEntity.getCreatedDate() != null + && chronicDiseaseVisitEntity.getDiagnosisCodes() != null) { + + List targetDiseases = Arrays.asList( + "Hypertension (BP)", + "Diabetes (DM)", + "Cancer" + ); + + + List diagnosisList = Arrays.asList( + chronicDiseaseVisitEntity.getDiagnosisCodes().split(",") + ); + + boolean matchFound = diagnosisList.stream() + .map(String::trim) + .anyMatch(targetDiseases::contains); + if(matchFound & Integer.valueOf(0).equals(chronicDiseaseVisitEntity.getFollowUpNo()) ){ + LocalDateTime localDateTime = chronicDiseaseVisitEntity.getTreatmentStartDate().atStartOfDay(); + + Timestamp treatmentStartDate = Timestamp.valueOf(localDateTime); + addNCDFolloupIncentiveRecord( + incentiveActivityCGForNCDnewPatient, + ashaId, + chronicDiseaseVisitEntity.getBenId(), + treatmentStartDate, + userName + ); } + if (matchFound && Integer.valueOf(6).equals(chronicDiseaseVisitEntity.getFollowUpNo())) { + LocalDateTime localDateTime = chronicDiseaseVisitEntity.getFollowUpDate().atStartOfDay(); + + Timestamp followUpTimestamp = Timestamp.valueOf(localDateTime); + if(stateId.equals(StateCode.AM.getStateCode())){ + addNCDFolloupIncentiveRecord( + incentiveActivity, + ashaId, + chronicDiseaseVisitEntity.getBenId(), + followUpTimestamp, + userName + ); + } + if(stateId.equals(StateCode.CG.getStateCode())){ + addNCDFolloupIncentiveRecord( + incentiveActivityCG, + ashaId, + chronicDiseaseVisitEntity.getBenId(), + followUpTimestamp, + userName + ); + } + } } + + + + } + + private void addNCDFolloupIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId, + Long benId, Timestamp createdDate, String userName) { + try { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), createdDate, benId,ashaId); + + Timestamp now = Timestamp.valueOf(LocalDateTime.now()); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(createdDate); + record.setCreatedBy(userName); + record.setStartDate(createdDate); + record.setEndDate(createdDate); + record.setUpdatedDate(now); + record.setUpdatedBy(userName); + record.setBenId(benId); + record.setAshaId(ashaId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + } + } catch (Exception e) { + logger.error("Fail to save IncentiveActivityRecord " + e.getMessage()); } + + + } + + @Override + public List getCdtfVisits(GetBenRequestHandler getBenRequestHandler) { + List dtoList = new ArrayList<>(); + + try { + + List entityList = chronicDiseaseVisitRepository.findByUserID(getBenRequestHandler.getAshaId()); + + + for (ChronicDiseaseVisitEntity entity : entityList) { + + ChronicDiseaseVisitDTO dto = new ChronicDiseaseVisitDTO(); + + dto.setId(entity.getId()); + dto.setBenId(entity.getBenId()); + dto.setHhId(entity.getHhId()); + dto.setFormId(entity.getFormId()); + dto.setVersion(entity.getVersion()); + dto.setVisitNo(entity.getVisitNo()); + dto.setFollowUpNo(entity.getFollowUpNo()); + if (entity.getFollowUpDate() != null) { + dto.setFollowUpDate(entity.getFollowUpDate()); + + } + dto.setDiagnosisCodes(entity.getDiagnosisCodes()); + dto.setFormDataJson(entity.getFormDataJson()); + + if (entity.getTreatmentStartDate() != null) { + dto.setTreatmentStartDate( + entity.getTreatmentStartDate().toString() + ); + } + checkIncentive(entity, entity.getUserID()); + dtoList.add(dto); + } + } catch (Exception e) { + + } + + return dtoList; } } \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/DynamicFormDefinitionServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DynamicFormDefinitionServiceImpl.java new file mode 100644 index 00000000..c40b65d7 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormDefinitionServiceImpl.java @@ -0,0 +1,416 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.domain.iemr.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.OptionCondition; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.QuestionValidation; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.dto.iemr.DynamicFormDTO; +import com.iemr.flw.dto.iemr.FormSectionDTO; +import com.iemr.flw.dto.iemr.OptionConditionDTO; +import com.iemr.flw.dto.iemr.QuestionOptionDTO; +import com.iemr.flw.dto.iemr.QuestionValidationDTO; +import com.iemr.flw.dto.iemr.SectionQuestionDTO; +import com.iemr.flw.mapper.DynamicFormMapper; +import com.iemr.flw.repo.iemr.DynamicFormRepo; +import com.iemr.flw.repo.iemr.FormSectionRepo; +import com.iemr.flw.repo.iemr.FormVersionRepo; +import com.iemr.flw.repo.iemr.OptionConditionRepo; +import com.iemr.flw.repo.iemr.QuestionOptionRepo; +import com.iemr.flw.repo.iemr.QuestionValidationRepo; +import com.iemr.flw.repo.iemr.SectionQuestionRepo; +import com.iemr.flw.service.DynamicFormDefinitionService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Implementation of DynamicFormDefinitionService with version-aware writes. + * Every structural change clones all sections fresh into a new FormVersion. + * Sections have a direct FK to FormVersion (no join table). + * + * @author Piramal Swasthya + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class DynamicFormDefinitionServiceImpl implements DynamicFormDefinitionService { + + private final DynamicFormRepo formRepo; + private final FormSectionRepo sectionRepo; + private final SectionQuestionRepo questionRepo; + private final QuestionOptionRepo optionRepo; + private final OptionConditionRepo conditionRepo; + private final QuestionValidationRepo validationRepo; + private final FormVersionRepo versionRepo; + private final DynamicFormMapper mapper; + + // ── PUBLIC WRITE METHODS ────────────────────────────────────────────────── + + @Override + @Transactional + public DynamicFormDTO createForm(DynamicFormDTO dto) { + formRepo.findByFormTypeAndIsActive(dto.getFormType(), true).ifPresent(existing -> { + throw new IllegalStateException( + "An active form of type " + dto.getFormType() + " already exists (formId=" + + existing.getFormId() + "). Deactivate it before creating a new one."); + }); + DynamicForm form = mapper.toEntity(dto); + // TODO: set audit fields when auth is re-enabled for /dynamicForm endpoints + // form.setCreatedBy(jwtUtil.extractUsername(authorization)); + // form.setUpdatedBy(jwtUtil.extractUsername(authorization)); + DynamicForm savedForm = formRepo.save(form); + FormVersion version = createNewVersion(savedForm, 1, null, null); + buildSectionsFromDto(dto.getSections(), version); + log.info("Form created: {} (v1)", savedForm.getFormUuid()); + return loadLatestFromDb(savedForm.getFormId()); + } + + @Override + @Transactional + public DynamicFormDTO updateForm(Long formId, DynamicFormDTO dto) { + DynamicForm form = requireForm(formId); + FormVersion current = requireLatestVersion(formId); + int nextVersion = current.getVersionNumber() + 1; + FormVersion newVersion = createNewVersion(form, nextVersion, null, null); + buildSectionsFromDto(dto.getSections(), newVersion); + current.setIsLatest(false); + versionRepo.save(current); + log.info("Form updated: {} -> v{}", form.getFormUuid(), nextVersion); + return loadLatestFromDb(formId); + } + + @Override + @Transactional + public void activateForm(Long formId) { + DynamicForm form = requireForm(formId); + form.setIsActive(true); + formRepo.save(form); + log.info("Form activated: {}", form.getFormUuid()); + } + + @Override + @Transactional + public void deactivateForm(Long formId) { + DynamicForm form = requireForm(formId); + form.setIsActive(false); + formRepo.save(form); + log.info("Form deactivated: {}", form.getFormUuid()); + } + + @Override + public DynamicFormDTO getFormDefinition(Long formId) { + return loadLatestFromDb(formId); + } + + @Override + public DynamicFormDTO getFormDefinitionByVersion(Long formId, Integer versionNumber) { + FormVersion version = versionRepo.findByDynamicForm_FormIdAndVersionNumber(formId, versionNumber) + .orElseThrow(() -> new RuntimeException( + "Version " + versionNumber + " not found for formId: " + formId)); + return buildFormDto(version.getDynamicForm(), version); + } + + @Override + public List getAllForms() { + return formRepo.findByIsActiveOrderByFormIdAsc(true) + .stream() + .map(form -> { + try { + return loadLatestFromDb(form.getFormId()); + } catch (RuntimeException e) { + log.warn("Skipping form {} — no active version: {}", form.getFormId(), e.getMessage()); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + // ── VERSION MANAGEMENT ──────────────────────────────────────────────────── + + private FormVersion createNewVersion(DynamicForm form, int versionNumber, + String createdBy, String notes) { + FormVersion version = new FormVersion(); + version.setDynamicForm(form); + version.setVersionNumber(versionNumber); + version.setIsLatest(true); + version.setCreatedBy(createdBy); + // TODO: set audit fields when auth is re-enabled for /dynamicForm endpoints + // version.setCreatedBy(jwtUtil.extractUsername(authorization)); + // version.setUpdatedBy(jwtUtil.extractUsername(authorization)); + version.setNotes(notes); + return versionRepo.save(version); + } + + // ── BUILD HELPERS (DTO → Entity) ────────────────────────────────────────── + + /** + * Two-pass build: + * Pass 1 — persist sections, questions, options, validations; collect uuid→entity maps. + * Pass 2 — wire conditions using targetQuestionUuid/targetSectionUuid from those maps. + */ + private void buildSectionsFromDto(List dtos, FormVersion version) { + if (dtos == null) return; + + Map sectionByUuid = new LinkedHashMap<>(); + Map questionByUuid = new LinkedHashMap<>(); + Map> pendingConditions = new LinkedHashMap<>(); + + // Pass 1: sections → questions → options + validations + for (FormSectionDTO sDto : dtos) { + FormSection section = mapper.toEntity(sDto); + section.setFormVersion(version); + section.setQuestions(new ArrayList<>()); + FormSection savedSection = sectionRepo.save(section); + sectionByUuid.put(savedSection.getSectionUuid(), savedSection); + + if (sDto.getQuestions() == null) continue; + for (SectionQuestionDTO qDto : sDto.getQuestions()) { + SectionQuestion q = mapper.toEntity(qDto); + q.setFormSection(savedSection); + q.setOptions(new ArrayList<>()); + q.setValidations(new ArrayList<>()); + SectionQuestion savedQ = questionRepo.save(q); + questionByUuid.put(savedQ.getQuestionUuid(), savedQ); + + if (qDto.getOptions() != null) { + for (QuestionOptionDTO oDto : qDto.getOptions()) { + QuestionOption opt = mapper.toEntity(oDto); + opt.setSectionQuestion(savedQ); + opt.setConditions(new ArrayList<>()); + QuestionOption savedOpt = optionRepo.save(opt); + if (oDto.getConditions() != null && !oDto.getConditions().isEmpty()) { + pendingConditions.put(savedOpt, oDto.getConditions()); + } + } + } + if (qDto.getValidations() != null) { + for (QuestionValidationDTO vDto : qDto.getValidations()) { + buildValidationEntity(vDto, savedQ); + } + } + } + } + + // Pass 2: conditions — resolve targets by UUID (create path) or ID (addCondition path) + for (Map.Entry> entry : pendingConditions.entrySet()) { + QuestionOption opt = entry.getKey(); + for (OptionConditionDTO cDto : entry.getValue()) { + OptionCondition cond = new OptionCondition(); + cond.setActionType(cDto.getActionType()); + cond.setQuestionOption(opt); + + if (cDto.getTargetQuestionUuid() != null) { + SectionQuestion target = questionByUuid.get(cDto.getTargetQuestionUuid()); + if (target == null) throw new RuntimeException( + "targetQuestionUuid not found in this form: " + cDto.getTargetQuestionUuid()); + cond.setTargetQuestion(target); + } else if (cDto.getTargetQuestionId() != null) { + cond.setTargetQuestion(requireQuestion(cDto.getTargetQuestionId())); + } + + if (cDto.getTargetSectionUuid() != null) { + FormSection target = sectionByUuid.get(cDto.getTargetSectionUuid()); + if (target == null) throw new RuntimeException( + "targetSectionUuid not found in this form: " + cDto.getTargetSectionUuid()); + cond.setTargetSection(target); + } else if (cDto.getTargetSectionId() != null) { + cond.setTargetSection(requireSection(cDto.getTargetSectionId())); + } + + conditionRepo.save(cond); + } + } + } + + private QuestionValidation buildValidationEntity(QuestionValidationDTO dto, + SectionQuestion question) { + QuestionValidation v = mapper.toEntity(dto); + v.setSectionQuestion(question); + return validationRepo.save(v); + } + + // ── LOAD / READ HELPERS ─────────────────────────────────────────────────── + + private DynamicFormDTO loadLatestFromDb(Long formId) { + FormVersion version = versionRepo.findByDynamicForm_FormIdAndIsLatest(formId, true) + .orElseThrow(() -> new RuntimeException("No active version for formId: " + formId)); + return buildFormDto(version.getDynamicForm(), version); + } + + /** + * Builds the full form DTO using exactly 5 queries (constant regardless of form size). + * All grouping, visibleByDefault computation, and embedded question/section population + * happen in memory — zero extra queries beyond the initial 5. + */ + private DynamicFormDTO buildFormDto(DynamicForm form, FormVersion version) { + // Query 1: sections + List sections = sectionRepo + .findByFormVersion_VersionIdOrderByDisplayOrderAsc(version.getVersionId()); + if (sections.isEmpty()) { + DynamicFormDTO dto = mapper.toDto(form); + dto.setVersionNumber(version.getVersionNumber()); + dto.setSections(Collections.emptyList()); + return dto; + } + + List sectionIds = sections.stream().map(FormSection::getSectionId) + .collect(Collectors.toList()); + + // Query 2: questions + List allQuestions = questionRepo + .findBySectionIdsOrderByDisplayOrderAsc(sectionIds); + + List questionIds = allQuestions.stream().map(SectionQuestion::getQuestionId) + .collect(Collectors.toList()); + + List allOptions; + List allValidations; + List allConditions; + + if (questionIds.isEmpty()) { + allOptions = Collections.emptyList(); + allValidations = Collections.emptyList(); + allConditions = Collections.emptyList(); + } else { + // Query 3: options + allOptions = optionRepo.findByQuestionIdsOrderByDisplayOrderAsc(questionIds); + // Query 4: validations + allValidations = validationRepo.findByQuestionIds(questionIds); + + List optionIds = allOptions.stream().map(QuestionOption::getOptionId) + .collect(Collectors.toList()); + // Query 5: conditions (LEFT JOIN FETCH targets) + allConditions = optionIds.isEmpty() ? Collections.emptyList() + : conditionRepo.findByOptionIds(optionIds); + } + + // Compute hidden question IDs (those targeted by any condition) + Set hiddenIds = allConditions.stream() + .filter(c -> c.getTargetQuestion() != null) + .map(c -> c.getTargetQuestion().getQuestionId()) + .collect(Collectors.toSet()); + + // Build index maps — no extra queries; FKs already in memory via JOIN FETCH + Map> questionsBySection = allQuestions.stream() + .collect(Collectors.groupingBy(q -> q.getFormSection().getSectionId())); + Map> optionsByQuestion = allOptions.stream() + .collect(Collectors.groupingBy(o -> o.getSectionQuestion().getQuestionId())); + Map> validationsByQuestion = allValidations.stream() + .collect(Collectors.groupingBy(v -> v.getSectionQuestion().getQuestionId())); + Map> conditionsByOption = allConditions.stream() + .collect(Collectors.groupingBy(c -> c.getQuestionOption().getOptionId())); + + DynamicFormDTO dto = mapper.toDto(form); + dto.setVersionNumber(version.getVersionNumber()); + dto.setSections(assembleSectionDtos(sections, questionsBySection, optionsByQuestion, + validationsByQuestion, conditionsByOption, hiddenIds)); + return dto; + } + + private List assembleSectionDtos( + List sections, + Map> questionsBySection, + Map> optionsByQuestion, + Map> validationsByQuestion, + Map> conditionsByOption, + Set hiddenIds) { + return sections.stream().map(section -> { + FormSectionDTO sDto = mapper.toDto(section); + List qs = questionsBySection + .getOrDefault(section.getSectionId(), Collections.emptyList()); + sDto.setQuestions(assembleQuestionDtos(qs, optionsByQuestion, + validationsByQuestion, conditionsByOption, hiddenIds)); + return sDto; + }).collect(Collectors.toList()); + } + + private List assembleQuestionDtos( + List questions, + Map> optionsByQuestion, + Map> validationsByQuestion, + Map> conditionsByOption, + Set hiddenIds) { + return questions.stream().map(q -> { + SectionQuestionDTO qDto = mapper.toDto(q); + qDto.setVisibleByDefault(!hiddenIds.contains(q.getQuestionId())); + List opts = optionsByQuestion + .getOrDefault(q.getQuestionId(), Collections.emptyList()); + qDto.setOptions(assembleOptionDtos(opts, conditionsByOption)); + qDto.setValidations(validationsByQuestion + .getOrDefault(q.getQuestionId(), Collections.emptyList()) + .stream().map(mapper::toDto).collect(Collectors.toList())); + return qDto; + }).collect(Collectors.toList()); + } + + private List assembleOptionDtos( + List options, + Map> conditionsByOption) { + return options.stream().map(opt -> { + QuestionOptionDTO oDto = mapper.toDto(opt); + oDto.setConditions(conditionsByOption + .getOrDefault(opt.getOptionId(), Collections.emptyList()) + .stream().map(mapper::toDto).collect(Collectors.toList())); + return oDto; + }).collect(Collectors.toList()); + } + + // ── REQUIRE HELPERS ─────────────────────────────────────────────────────── + + private DynamicForm requireForm(Long formId) { + return formRepo.findById(formId) + .orElseThrow(() -> new RuntimeException("Form not found: " + formId)); + } + + private FormVersion requireLatestVersion(Long formId) { + return versionRepo.findByDynamicForm_FormIdAndIsLatest(formId, true) + .orElseThrow(() -> new RuntimeException( + "No latest version found for formId: " + formId)); + } + + private FormSection requireSection(Long sectionId) { + return sectionRepo.findById(sectionId) + .orElseThrow(() -> new RuntimeException("Section not found: " + sectionId)); + } + + private SectionQuestion requireQuestion(Long questionId) { + return questionRepo.findById(questionId) + .orElseThrow(() -> new RuntimeException("Question not found: " + questionId)); + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java new file mode 100644 index 00000000..6e3b29c2 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/DynamicFormResponseServiceImpl.java @@ -0,0 +1,504 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.FormResponse; +import com.iemr.flw.domain.iemr.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.QuestionResponse; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.domain.iemr.SectionResponse; +import com.iemr.flw.dto.iemr.FormResponseDTO; +import com.iemr.flw.dto.iemr.FormResponseRequest; +import com.iemr.flw.dto.iemr.QuestionAnswerRequest; +import com.iemr.flw.dto.iemr.QuestionResponseDTO; +import com.iemr.flw.dto.iemr.SectionAnswerRequest; +import com.iemr.flw.dto.iemr.SectionResponseDTO; +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.masterEnum.FormType; +import com.iemr.flw.repo.iemr.DynamicFormRepo; +import com.iemr.flw.repo.iemr.FormResponseRepo; +import com.iemr.flw.repo.iemr.FormSectionRepo; +import com.iemr.flw.repo.iemr.FormVersionRepo; +import com.iemr.flw.repo.iemr.QuestionOptionRepo; +import com.iemr.flw.repo.iemr.QuestionResponseRepo; +import com.iemr.flw.repo.iemr.SectionQuestionRepo; +import com.iemr.flw.repo.iemr.SectionResponseRepo; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.service.CampConfigService; +import com.iemr.flw.service.DynamicFormResponseService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Handles save, submit, complete, and fetch of dynamic form responses. + * Resolves the latest FormVersion server-side so the client only needs to send formUuid. + * + * @author Piramal Swasthya + */ +@Slf4j +@RequiredArgsConstructor +@Service +public class DynamicFormResponseServiceImpl implements DynamicFormResponseService { + + private static final String STATUS_DRAFT = "DRAFT"; + private static final String STATUS_SUBMITTED = "SUBMITTED"; + private static final String STATUS_COMPLETE = "COMPLETE"; + private static final String SECTION_STATUS_DONE = "DONE"; + + private final DynamicFormRepo dynamicFormRepo; + private final FormResponseRepo formResponseRepo; + private final SectionResponseRepo sectionResponseRepo; + private final QuestionResponseRepo questionResponseRepo; + private final FormVersionRepo formVersionRepo; + private final FormSectionRepo formSectionRepo; + private final SectionQuestionRepo sectionQuestionRepo; + private final QuestionOptionRepo questionOptionRepo; + private final FormResponseItemSaver itemSaver; + private final JwtUtil jwtUtil; + private final CampConfigService campConfigService; + + @Override + @Transactional + public FormResponseDTO submitForm(FormResponseRequest request) { + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + FormVersion version = resolveLatestVersion(request.getFormUuid()); + Timestamp now = new Timestamp(System.currentTimeMillis()); + FormResponse formResponse; + if (request.getResponseId() != null) { + // Re-submit: update existing SUBMITTED response's sections + formResponse = formResponseRepo.findById(request.getResponseId()) + .orElseThrow(() -> new NoSuchElementException( + "FormResponse not found: " + request.getResponseId())); + if (STATUS_COMPLETE.equals(formResponse.getStatus())) { + throw new IllegalStateException( + "Cannot update a COMPLETE response (responseId=" + request.getResponseId() + ")"); + } + // Bump submittedAt to reflect the re-submission time + formResponse.setStatus(STATUS_SUBMITTED); + formResponse.setSubmittedAt(now); + formResponse.setLastFollowUpAt(now); + formResponse = formResponseRepo.save(formResponse); + } else { + formResponse = createFormResponse(request, version, STATUS_SUBMITTED, now, vanID, parkingPlaceID); + } + return processSections(formResponse, request, version, null, vanID, parkingPlaceID); + } + + @Override + @Transactional + public FormResponseDTO completeForm(FormResponseRequest request, String jwtToken) throws IEMRException { + String actor = jwtUtil.extractUserId(jwtToken).toString(); + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + + FormVersion version = resolveLatestVersion(request.getFormUuid()); + Long formId = version.getDynamicForm().getFormId(); + Timestamp now = new Timestamp(System.currentTimeMillis()); + + List existing = + formResponseRepo.findByBeneficiaryIdAndFormId(request.getBeneficiaryId(), formId); + FormResponse formResponse = existing.isEmpty() + ? createFormResponse(request, version, STATUS_COMPLETE, now, vanID, parkingPlaceID) + : existing.get(0); + + formResponse.setUpdatedBy(actor); + formResponse.setStatus(STATUS_COMPLETE); + formResponse.setCompletedAt(now); + formResponse = formResponseRepo.save(formResponse); + return processSections(formResponse, request, version, actor, vanID, parkingPlaceID); + } + + @Override + @Transactional(readOnly = true) + public List getResponsesByBeneficiary(Long beneficiaryId, String formUuid) { + FormVersion version = resolveLatestVersion(formUuid); + Long formId = version.getDynamicForm().getFormId(); + + List responses = + formResponseRepo.findByBeneficiaryIdAndFormId(beneficiaryId, formId); + return responses.stream() + .map(r -> buildFormResponseDTO(r, loadSectionResponseDTOs(r.getResponseId()))) + .collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public FormResponseDTO getResponseById(Long responseId) { + FormResponse formResponse = formResponseRepo.findById(responseId) + .orElseThrow(() -> new NoSuchElementException("FormResponse not found: " + responseId)); + return buildFormResponseDTO(formResponse, loadSectionResponseDTOs(responseId)); + } + + // ---- private helpers ---- + + private FormVersion resolveLatestVersion(String formUuid) { + return formVersionRepo.findByDynamicForm_FormUuidAndIsLatest(formUuid, true) + .orElseThrow(() -> new NoSuchElementException( + "No active FormVersion found for form code: " + formUuid)); + } + + /** Creates a new FormResponse row. */ + private FormResponse createFormResponse( + FormResponseRequest request, + FormVersion version, + String status, + Timestamp submittedAt, + Integer vanID, + Integer parkingPlaceID) { + + FormResponse formResponse = FormResponse.builder() + .beneficiaryId(request.getBeneficiaryId()) + .formId(version.getDynamicForm().getFormId()) + .versionId(version.getVersionId()) + .officerId(request.getOfficerId()) + .status(status) + .submittedAt(submittedAt) + .lastFollowUpAt(submittedAt) + // TODO: set audit fields when auth is re-enabled for /dynamicForm/response endpoints + // .createdBy(jwtUtil.extractUsername(authorization)) + // .updatedBy(jwtUtil.extractUsername(authorization)) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build(); + return formResponseRepo.save(formResponse); + } + + /** + * Batch-loads all sections and questions for the version, then processes each answered section. + */ + private FormResponseDTO processSections( + FormResponse formResponse, + FormResponseRequest request, + FormVersion version, + String actor, + Integer vanID, + Integer parkingPlaceID) { + + List allSections = + formSectionRepo.findByFormVersion_VersionIdOrderByDisplayOrderAsc(version.getVersionId()); + Map sectionByUuid = allSections.stream() + .collect(Collectors.toMap(FormSection::getSectionUuid, Function.identity())); + + Set sectionIds = allSections.stream() + .map(FormSection::getSectionId) + .collect(Collectors.toSet()); + + List allQuestions = + sectionQuestionRepo.findBySectionIdsOrderByDisplayOrderAsc(sectionIds); + Map> questionsBySection = allQuestions.stream() + .collect(Collectors.groupingBy( + q -> q.getFormSection().getSectionId(), + Collectors.toMap(SectionQuestion::getQuestionUuid, Function.identity()))); + + Set questionIds = allQuestions.stream() + .map(SectionQuestion::getQuestionId) + .collect(Collectors.toSet()); + List allOptions = + questionOptionRepo.findByQuestionIdsOrderByDisplayOrderAsc(questionIds); + + // Map: questionId → (optionValue → QuestionOption) + Map> optionsByQuestion = allOptions.stream() + .collect(Collectors.groupingBy( + o -> o.getSectionQuestion().getQuestionId(), + Collectors.toMap(QuestionOption::getOptionValue, Function.identity()))); + + List sectionDTOs = new ArrayList<>(); + for (SectionAnswerRequest sectionReq : request.getSections()) { + if (sectionReq.getSectionUuid() == null) { + throw new IllegalArgumentException( + "sectionUuid is null — did you send sectionCode instead?"); + } + FormSection section = sectionByUuid.get(sectionReq.getSectionUuid()); + if (section == null) { + throw new NoSuchElementException( + "Section '" + sectionReq.getSectionUuid() + + "' not found in form '" + request.getFormUuid() + "'"); + } + + SectionResponse sectionResponse = upsertSectionResponse( + formResponse.getResponseId(), section.getSectionId(), actor, vanID, parkingPlaceID); + + if ("POST_SUBMIT".equals(section.getSectionPhase())) { + formResponse.setLastFollowUpAt(sectionResponse.getSavedAt()); + formResponseRepo.save(formResponse); + } + + Map questionMap = + questionsBySection.getOrDefault(section.getSectionId(), Map.of()); + + List questionResponses = processAnswers( + sectionResponse.getSectionResponseId(), + sectionReq.getAnswers(), + questionMap, + optionsByQuestion, + actor, + vanID, + parkingPlaceID); + + questionResponseRepo.saveAll(questionResponses); + + sectionDTOs.add(buildSectionResponseDTO(sectionResponse, questionResponses)); + } + + return buildFormResponseDTO(formResponse, sectionDTOs); + } + + private SectionResponse upsertSectionResponse(Long responseId, Long sectionId, String actor, + Integer vanID, Integer parkingPlaceID) { + Optional existing = + sectionResponseRepo.findByResponseIdAndSectionId(responseId, sectionId); + if (existing.isPresent()) { + SectionResponse sr = existing.get(); + sr.setStatus(SECTION_STATUS_DONE); + sr.setSavedAt(new Timestamp(System.currentTimeMillis())); + sr.setUpdatedBy(actor); + if (sr.getVanID() == null) { sr.setVanID(vanID); sr.setParkingPlaceID(parkingPlaceID); } + return sectionResponseRepo.save(sr); + } + SectionResponse sr = SectionResponse.builder() + .responseId(responseId) + .sectionId(sectionId) + .status(SECTION_STATUS_DONE) + .savedAt(new Timestamp(System.currentTimeMillis())) + .createdBy(actor) + .updatedBy(actor) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build(); + return sectionResponseRepo.save(sr); + } + + private List processAnswers( + Long sectionResponseId, + List answers, + Map questionMap, + Map> optionsByQuestion, + String actor, + Integer vanID, + Integer parkingPlaceID) { + + List results = new ArrayList<>(); + + for (QuestionAnswerRequest answer : answers) { + if (answer.getQuestionUuid() == null) { + throw new IllegalArgumentException( + "questionUuid is null — did you send questionCode instead?"); + } + SectionQuestion question = questionMap.get(answer.getQuestionUuid()); + if (question == null) { + throw new NoSuchElementException( + "Question '" + answer.getQuestionUuid() + "' not found in section"); + } + QuestionType type = question.getQuestionType(); + Long questionId = question.getQuestionId(); + + if (type == QuestionType.DISPLAY) { + // DISPLAY questions carry no answer data + continue; + } + + // Delete any existing answers for this question in this section (handles re-saves) + questionResponseRepo.deleteByQuestionIdAndSectionResponseId(questionId, sectionResponseId); + + if (type == QuestionType.RADIO) { + if (answer.getOptionValue() != null) { + QuestionOption opt = resolveOption( + optionsByQuestion, questionId, answer.getOptionValue(), answer.getQuestionUuid()); + results.add(QuestionResponse.builder() + .sectionResponseId(sectionResponseId) + .questionId(questionId) + .optionId(opt != null ? opt.getOptionId() : null) + .createdBy(actor) + .updatedBy(actor) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build()); + } + } else if (type == QuestionType.MCQ) { + if (answer.getOptionValues() != null) { + for (String val : answer.getOptionValues()) { + QuestionOption opt = resolveOption( + optionsByQuestion, questionId, val, answer.getQuestionUuid()); + results.add(QuestionResponse.builder() + .sectionResponseId(sectionResponseId) + .questionId(questionId) + .optionId(opt != null ? opt.getOptionId() : null) + .createdBy(actor) + .updatedBy(actor) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build()); + } + } + } else { + // TEXT, DATE, AUTO_FILL — prefer answerText, then answerDate, then optionValue (legacy) + String value = answer.getAnswerText() != null ? answer.getAnswerText() + : answer.getAnswerDate() != null ? answer.getAnswerDate() + : answer.getOptionValue(); + results.add(QuestionResponse.builder() + .sectionResponseId(sectionResponseId) + .questionId(questionId) + .answerText(value) + .createdBy(actor) + .updatedBy(actor) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build()); + } + } + return results; + } + + private QuestionOption resolveOption( + Map> optionsByQuestion, + Long questionId, + String optionValue, + String questionUuid) { + + Map opts = optionsByQuestion.get(questionId); + if (opts == null || !opts.containsKey(optionValue)) { + log.warn("Option value '{}' not found for question '{}', storing null optionId", + optionValue, questionUuid); + return null; + } + return opts.get(optionValue); + } + + // ---- read helpers ---- + + private List loadSectionResponseDTOs(Long responseId) { + List sections = sectionResponseRepo.findByResponseId(responseId); + if (sections.isEmpty()) { + return List.of(); + } + Set srIds = sections.stream() + .map(SectionResponse::getSectionResponseId) + .collect(Collectors.toSet()); + List allAnswers = + questionResponseRepo.findBySectionResponseIdIn(srIds); + Map> answersBySectionResponse = allAnswers.stream() + .collect(Collectors.groupingBy(QuestionResponse::getSectionResponseId)); + + return sections.stream() + .map(sr -> buildSectionResponseDTO( + sr, + answersBySectionResponse.getOrDefault(sr.getSectionResponseId(), List.of()))) + .collect(Collectors.toList()); + } + + private FormResponseDTO buildFormResponseDTO(FormResponse r, List sections) { + return FormResponseDTO.builder() + .responseId(r.getResponseId()) + .beneficiaryId(r.getBeneficiaryId()) + .formId(r.getFormId()) + .versionId(r.getVersionId()) + .officerId(r.getOfficerId()) + .status(r.getStatus()) + .createdBy(r.getCreatedBy()) + .updatedBy(r.getUpdatedBy()) + .submittedAt(r.getSubmittedAt()) + .completedAt(r.getCompletedAt()) + .lastFollowUpAt(r.getLastFollowUpAt()) + .createdAt(r.getCreatedAt()) + .updatedAt(r.getUpdatedAt()) + .sections(sections) + .build(); + } + + private SectionResponseDTO buildSectionResponseDTO( + SectionResponse sr, List answers) { + List answerDTOs = answers.stream() + .map(a -> QuestionResponseDTO.builder() + .questionResponseId(a.getQuestionResponseId()) + .questionId(a.getQuestionId()) + .optionId(a.getOptionId()) + .answerText(a.getAnswerText()) + .build()) + .collect(Collectors.toList()); + return SectionResponseDTO.builder() + .sectionResponseId(sr.getSectionResponseId()) + .sectionId(sr.getSectionId()) + .status(sr.getStatus()) + .savedAt(sr.getSavedAt()) + .answers(answerDTOs) + .build(); + } + + @Override + public List submitBulk(List requests, String jwtToken) { + if (requests == null || requests.isEmpty()) return List.of(); + List results = new ArrayList<>(); + for (FormResponseRequest req : requests) { + try { + results.add(itemSaver.saveForBulk(req, jwtToken)); + } catch (Exception ex) { + log.warn("submitBulk: item skipped for beneficiaryId={} — {}", + req.getBeneficiaryId(), ex.getMessage()); + } + } + return results; + } + + @Override + @Transactional(readOnly = true) + public List findPendingFollowUps(List formIds, int delayDays) { + if (formIds == null || formIds.isEmpty()) { + return List.of(); + } + LocalDate target = LocalDate.now().minusDays(delayDays); + Timestamp windowStart = Timestamp.valueOf(target.atStartOfDay()); + Timestamp windowEnd = Timestamp.valueOf(target.plusDays(1).atStartOfDay()); + return formResponseRepo.findPendingFollowUps(formIds, windowStart, windowEnd) + .stream() + .map(r -> buildFormResponseDTO(r, List.of())) + .collect(Collectors.toList()); + } + + @Override + @Transactional(readOnly = true) + public List getCompletedBeneficiaries(FormType formType, Integer villageId, Integer providerServiceMapId) { + DynamicForm form = dynamicFormRepo.findByFormTypeAndIsActive(formType, true) + .orElseThrow(() -> new NoSuchElementException( + "No active form found for type: " + formType)); + return (villageId != null || providerServiceMapId != null) + ? formResponseRepo.findBeneficiaryIdsByFormIdAndStatusFiltered(form.getFormId(), STATUS_COMPLETE, villageId, providerServiceMapId) + : formResponseRepo.findBeneficiaryIdsByFormIdAndStatus(form.getFormId(), STATUS_COMPLETE); + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/EmployeeMasterImpl.java b/src/main/java/com/iemr/flw/service/impl/EmployeeMasterImpl.java index 2f67fc2b..acf7836c 100644 --- a/src/main/java/com/iemr/flw/service/impl/EmployeeMasterImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/EmployeeMasterImpl.java @@ -1,6 +1,6 @@ package com.iemr.flw.service.impl; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.repo.iemr.EmployeeMasterRepo; import com.iemr.flw.service.EmployeeMasterInter; @@ -19,13 +19,13 @@ public class EmployeeMasterImpl implements EmployeeMasterInter { @Override - public M_User getUserDetails(Integer userID) { + public User getUserDetails(Integer userID) { logger.debug("Fetching user details for userID: {}", userID); try { if (userID == null) { throw new IllegalArgumentException("UserID cannot be null"); } - return employeeMasterRepo.findByUserID(userID); + return employeeMasterRepo.findUserByUserID(userID); } catch (Exception e) { logger.error("Error fetching user details for userID: {}", userID, e); throw e; @@ -33,7 +33,7 @@ public M_User getUserDetails(Integer userID) { } @Override - public List getAllUsers() { + public List getAllUsers() { return employeeMasterRepo.findAll(); } } diff --git a/src/main/java/com/iemr/flw/service/impl/FacilityDataService.java b/src/main/java/com/iemr/flw/service/impl/FacilityDataService.java new file mode 100644 index 00000000..2e4f9556 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/FacilityDataService.java @@ -0,0 +1,186 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.AshaSupervisorMapping; +import com.iemr.flw.repo.iemr.AshaSupervisorLoginRepo; +import com.iemr.flw.repo.iemr.FacilityLoginRepo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Service +public class FacilityDataService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired + private AshaSupervisorLoginRepo ashaSupervisorLoginRepo; + + @Autowired + private FacilityLoginRepo facilityLoginRepo; + + public Map buildFacilityData(Integer userID, String roleName) { + Map result = new HashMap<>(); + result.put("location", emptyLocation()); + try { + if ("ASHA Supervisor".equalsIgnoreCase(roleName)) { + enrichAshaSupervisorData(result, userID); + } else if ("ASHA".equalsIgnoreCase(roleName)) { + enrichAshaData(result, userID); + } else { + enrichGeneralFacilityData(result, userID); + } + } catch (Exception e) { + logger.error("Error building facilityData for userID " + userID + ": " + e.getMessage(), e); + } + return result; + } + + private void enrichAshaSupervisorData(Map result, Integer supervisorUserID) { + ArrayList mappings = ashaSupervisorLoginRepo + .findBySupervisorUserIDAndDeletedFalse(supervisorUserID); + if (mappings == null || mappings.isEmpty()) return; + + Set facilityIDSet = new HashSet<>(); + for (AshaSupervisorMapping m : mappings) { + if (m.getFacilityID() != null) facilityIDSet.add(m.getFacilityID()); + } + if (facilityIDSet.isEmpty()) return; + List facilityIDs = new ArrayList<>(facilityIDSet); + + List facilityRows = facilityLoginRepo.getFacilityDetails(facilityIDs); + if (facilityRows == null || facilityRows.isEmpty()) return; + + result.put("location", buildLocation(facilityRows.get(0))); + + List> facilities = new ArrayList<>(); + for (Object[] row : facilityRows) { + Map facility = new HashMap<>(); + facility.put("facilityId", row[0]); + facility.put("facilityName", str(row[1])); + facility.put("facilityType", str(row[9])); + facilities.add(facility); + } + result.put("facilities", facilities); + + List ashaRows = facilityLoginRepo.getMappedAshasBySupervisor(supervisorUserID); + List> ashaList = buildAshaList(ashaRows); + result.put("ashaList", ashaList); + result.put("totalAshaCount", ashaList.size()); + } + + private void enrichAshaData(Map result, Integer ashaUserID) { + List facilityIDs = facilityLoginRepo.getUserFacilityIDs(ashaUserID); + if (facilityIDs == null || facilityIDs.isEmpty()) return; + + List facilityRows = facilityLoginRepo.getFacilityDetails(facilityIDs); + if (facilityRows == null || facilityRows.isEmpty()) return; + + result.put("location", buildLocation(facilityRows.get(0))); + + Object[] row = facilityRows.get(0); + Map facility = new HashMap<>(); + facility.put("facilityId", row[0]); + facility.put("facilityName", str(row[1])); + facility.put("facilityType", str(row[9])); + result.put("facility", facility); + + List supervisorRows = facilityLoginRepo.getSupervisorForAsha(ashaUserID); + if (supervisorRows != null && !supervisorRows.isEmpty()) { + Object[] sRow = supervisorRows.get(0); + Map supervisor = new HashMap<>(); + supervisor.put("userId", sRow[0]); + supervisor.put("fullName", fullName(sRow[1], sRow[2])); + supervisor.put("mobile", str(sRow[3])); + supervisor.put("employeeId", str(sRow[4]).isEmpty() ? null : str(sRow[4])); + result.put("supervisor", supervisor); + } else { + result.put("supervisor", null); + } + + List peerRows = facilityLoginRepo.getPeersAtFacility(facilityIDs, ashaUserID); + List> peers = new ArrayList<>(); + if (peerRows != null) { + for (Object[] pRow : peerRows) { + Map peer = new HashMap<>(); + peer.put("userId", pRow[0]); + peer.put("fullName", fullName(pRow[1], pRow[2])); + peer.put("role", str(pRow[3])); + peer.put("employeeId", str(pRow[4]).isEmpty() ? null : str(pRow[4])); + peer.put("mobile", str(pRow[5]).isEmpty() ? null : str(pRow[5])); + peers.add(peer); + } + } + result.put("peersAtFacility", peers); + } + + private void enrichGeneralFacilityData(Map result, Integer userID) { + List facilityIDs = facilityLoginRepo.getUserFacilityIDs(userID); + if (facilityIDs == null || facilityIDs.isEmpty()) return; + + List facilityRows = facilityLoginRepo.getFacilityDetails(facilityIDs); + if (facilityRows == null || facilityRows.isEmpty()) return; + + result.put("location", buildLocation(facilityRows.get(0))); + + List> facilities = new ArrayList<>(); + for (Object[] row : facilityRows) { + Map facility = new HashMap<>(); + facility.put("facilityId", row[0]); + facility.put("facilityName", str(row[1])); + facility.put("facilityType", str(row[9])); + facilities.add(facility); + } + result.put("facilities", facilities); + + List ashaRows = facilityLoginRepo.getAshaListByFacilities(facilityIDs); + List> ashaList = buildAshaList(ashaRows); + result.put("ashaList", ashaList); + result.put("totalAshaCount", ashaList.size()); + } + + private List> buildAshaList(List rows) { + List> list = new ArrayList<>(); + if (rows == null) return list; + for (Object[] row : rows) { + Map asha = new HashMap<>(); + asha.put("userId", row[0]); + asha.put("fullName", fullName(row[1], row[2])); + asha.put("employeeId", str(row[3]).isEmpty() ? null : str(row[3])); + asha.put("facilityId", row[4]); + asha.put("facilityName", str(row[5])); + asha.put("facilityType", str(row[6])); + asha.put("mobile", str(row[7]).isEmpty() ? null : str(row[7])); + list.add(asha); + } + return list; + } + + private Map buildLocation(Object[] facilityRow) { + Map location = new HashMap<>(); + location.put("state", str(facilityRow[3])); + location.put("district", str(facilityRow[5])); + location.put("blockOrUlb", str(facilityRow[7])); + location.put("locationType", str(facilityRow[8])); + return location; + } + + private Map emptyLocation() { + Map location = new HashMap<>(); + location.put("state", ""); + location.put("district", ""); + location.put("blockOrUlb", ""); + location.put("locationType", ""); + return location; + } + + private String str(Object val) { + return val != null ? val.toString() : ""; + } + + private String fullName(Object first, Object last) { + return (str(first) + " " + str(last)).trim(); + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/FormFollowUpNotificationScheduler.java b/src/main/java/com/iemr/flw/service/impl/FormFollowUpNotificationScheduler.java new file mode 100644 index 00000000..5062c9fb --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/FormFollowUpNotificationScheduler.java @@ -0,0 +1,110 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.dto.iemr.FormResponseDTO; +import com.iemr.flw.repo.iemr.DynamicFormRepo; +import com.iemr.flw.service.DynamicFormResponseService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * Generic daily scheduler that sends follow-up push notifications for any active + * dynamic form with a configured {@code followUpDelayDays}. The notification fires + * exactly N days after the most recently completed section (PRE_SUBMIT submission or + * any subsequent POST_SUBMIT section completion). + * + * @author Piramal Swasthya + */ +@Service +public class FormFollowUpNotificationScheduler { + + private static final Logger log = + LoggerFactory.getLogger(FormFollowUpNotificationScheduler.class); + + private final DynamicFormRepo dynamicFormRepo; + private final DynamicFormResponseService responseService; + private final NotificationService notificationService; + + public FormFollowUpNotificationScheduler( + DynamicFormRepo dynamicFormRepo, + DynamicFormResponseService responseService, + NotificationService notificationService) { + this.dynamicFormRepo = dynamicFormRepo; + this.responseService = responseService; + this.notificationService = notificationService; + } + + @Scheduled(cron = "0 0 9 * * *") + public void sendFollowUpReminders() { + log.info("FormFollowUpNotificationScheduler: starting daily follow-up scan"); + + List formsWithDelay = + dynamicFormRepo.findByIsActiveTrueAndFollowUpDelayDaysIsNotNull(); + + if (formsWithDelay.isEmpty()) { + log.debug("No active forms with followUpDelayDays configured — skipping"); + return; + } + + // Group by delay value so we issue one batch DB query per distinct delay + Map> byDelay = formsWithDelay.stream() + .collect(Collectors.groupingBy( + DynamicForm::getFollowUpDelayDays, + Collectors.mapping(DynamicForm::getFormId, Collectors.toList()))); + + for (Map.Entry> entry : byDelay.entrySet()) { + int delayDays = entry.getKey(); + List formIds = entry.getValue(); + + try { + List pending = + responseService.findPendingFollowUps(formIds, delayDays); + + log.info("delayDays={}: found {} pending follow-up(s)", delayDays, pending.size()); + + for (FormResponseDTO r : pending) { + try { + //Notification sending logic + log.info("Sent follow-up notification: responseId={}, officerId={}", + r.getResponseId(), r.getOfficerId()); + } catch (Exception e) { + log.error("Failed to send notification for responseId={}: {}", + r.getResponseId(), e.getMessage()); + } + } + } catch (Exception e) { + log.error("Follow-up scheduler failed for delayDays={}: {}", + delayDays, e.getMessage(), e); + } + } + + log.info("FormFollowUpNotificationScheduler: scan complete"); + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java b/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java new file mode 100644 index 00000000..6a8fb863 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/FormResponseItemSaver.java @@ -0,0 +1,420 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.FormResponse; +import com.iemr.flw.domain.iemr.FormSection; +import com.iemr.flw.domain.iemr.FormVersion; +import com.iemr.flw.domain.iemr.QuestionOption; +import com.iemr.flw.domain.iemr.QuestionResponse; +import com.iemr.flw.domain.iemr.SectionQuestion; +import com.iemr.flw.domain.iemr.SectionResponse; +import com.iemr.flw.dto.iemr.FormResponseDTO; +import com.iemr.flw.dto.iemr.FormResponseRequest; +import com.iemr.flw.dto.iemr.QuestionAnswerRequest; +import com.iemr.flw.dto.iemr.QuestionResponseDTO; +import com.iemr.flw.dto.iemr.SectionAnswerRequest; +import com.iemr.flw.dto.iemr.SectionResponseDTO; +import com.iemr.flw.repo.iemr.FormResponseRepo; +import com.iemr.flw.repo.iemr.FormSectionRepo; +import com.iemr.flw.repo.iemr.FormVersionRepo; +import com.iemr.flw.repo.iemr.QuestionOptionRepo; +import com.iemr.flw.repo.iemr.QuestionResponseRepo; +import com.iemr.flw.repo.iemr.SectionQuestionRepo; +import com.iemr.flw.repo.iemr.SectionResponseRepo; +import com.iemr.flw.masterEnum.QuestionType; +import com.iemr.flw.service.CampConfigService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Saves a single dynamic form response in its own REQUIRES_NEW transaction. + * Used by submitBulk so that each item in the batch is independently committed or rolled back — + * a failed item does not affect sibling items in the same bulk request. + * + * @author Piramal Swasthya + */ +@Slf4j +@RequiredArgsConstructor +@Component +public class FormResponseItemSaver { + + private static final String STATUS_SUBMITTED = "SUBMITTED"; + private static final String SECTION_STATUS_DONE = "DONE"; + + private final FormResponseRepo formResponseRepo; + private final SectionResponseRepo sectionResponseRepo; + private final QuestionResponseRepo questionResponseRepo; + private final FormVersionRepo formVersionRepo; + private final FormSectionRepo formSectionRepo; + private final SectionQuestionRepo sectionQuestionRepo; + private final QuestionOptionRepo questionOptionRepo; + private final JwtUtil jwtUtil; + private final CampConfigService campConfigService; + + /** + * Saves one form response in its own independent REQUIRES_NEW transaction. + * Order: validate → delete old → save new. If save fails the transaction rolls back, + * restoring the deleted rows automatically. + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + public FormResponseDTO saveForBulk(FormResponseRequest req, String jwtToken) throws IEMRException { + String actor = jwtUtil.extractUserId(jwtToken).toString(); + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + FormVersion version = resolveLatestVersion(req.getFormUuid()); + Timestamp now = new Timestamp(System.currentTimeMillis()); + Long formId = version.getDynamicForm().getFormId(); + + // Step 1: Validate all section + question UUIDs BEFORE any writes or deletes + validateRequest(req, version); + + // Step 2: Check for an existing response for this beneficiary+form + List existing = + formResponseRepo.findByBeneficiaryIdAndFormId(req.getBeneficiaryId(), formId); + + FormResponse formResponse; + if (!existing.isEmpty()) { + formResponse = existing.get(0); + Long responseId = formResponse.getResponseId(); + + // Step 3: Update FormResponse header + formResponse.setStatus(STATUS_SUBMITTED); + formResponse.setSubmittedAt(now); + formResponse.setUpdatedBy(actor); + formResponse.setLastFollowUpAt(now); + formResponse = formResponseRepo.save(formResponse); + log.info("saveForBulk: overwriting responseId={} for beneficiaryId={}", + formResponse.getResponseId(), req.getBeneficiaryId()); + } else { + formResponse = createFormResponse(req, version, now, actor, vanID, parkingPlaceID); + } + + // Step 5: Insert fresh sections and answers + return processSections(formResponse, req, version, actor, vanID, parkingPlaceID); + } + + /** Pre-flight: validates every sectionUuid and questionUuid in the request exist in the form. */ + private void validateRequest(FormResponseRequest req, FormVersion version) { + List allSections = + formSectionRepo.findByFormVersion_VersionIdOrderByDisplayOrderAsc(version.getVersionId()); + Map sectionByUuid = allSections.stream() + .collect(Collectors.toMap(FormSection::getSectionUuid, Function.identity())); + + Set sectionIds = allSections.stream() + .map(FormSection::getSectionId) + .collect(Collectors.toSet()); + List allQuestions = + sectionQuestionRepo.findBySectionIdsOrderByDisplayOrderAsc(sectionIds); + Map> questionUuidsBySectionId = allQuestions.stream() + .collect(Collectors.groupingBy( + q -> q.getFormSection().getSectionId(), + Collectors.mapping(SectionQuestion::getQuestionUuid, Collectors.toSet()))); + + for (SectionAnswerRequest sectionReq : req.getSections()) { + FormSection section = sectionByUuid.get(sectionReq.getSectionUuid()); + if (section == null) { + throw new NoSuchElementException( + "Section '" + sectionReq.getSectionUuid() + + "' not found in form '" + req.getFormUuid() + "'"); + } + Set validQuestions = + questionUuidsBySectionId.getOrDefault(section.getSectionId(), Set.of()); + for (QuestionAnswerRequest answer : sectionReq.getAnswers()) { + if (answer.getQuestionUuid() != null + && !validQuestions.contains(answer.getQuestionUuid())) { + throw new NoSuchElementException( + "Question '" + answer.getQuestionUuid() + + "' not found in section '" + sectionReq.getSectionUuid() + "'"); + } + } + } + } + + // ---- private helpers ---- + + private FormVersion resolveLatestVersion(String formUuid) { + return formVersionRepo.findByDynamicForm_FormUuidAndIsLatest(formUuid, true) + .orElseThrow(() -> new NoSuchElementException( + "No active FormVersion found for form: " + formUuid)); + } + + private FormResponse createFormResponse(FormResponseRequest req, FormVersion version, Timestamp now, String actor, + Integer vanID, Integer parkingPlaceID) { + FormResponse formResponse = FormResponse.builder() + .beneficiaryId(req.getBeneficiaryId()) + .formId(version.getDynamicForm().getFormId()) + .versionId(version.getVersionId()) + .officerId(req.getOfficerId()) + .status(STATUS_SUBMITTED) + .createdBy(actor) + .updatedBy(actor) + .submittedAt(now) + .lastFollowUpAt(now) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build(); + return formResponseRepo.save(formResponse); + } + + private FormResponseDTO processSections(FormResponse formResponse, FormResponseRequest req, FormVersion version, String actor, + Integer vanID, Integer parkingPlaceID) { + List allSections = + formSectionRepo.findByFormVersion_VersionIdOrderByDisplayOrderAsc(version.getVersionId()); + Map sectionByUuid = allSections.stream() + .collect(Collectors.toMap(FormSection::getSectionUuid, Function.identity())); + + Set sectionIds = allSections.stream() + .map(FormSection::getSectionId) + .collect(Collectors.toSet()); + + List allQuestions = + sectionQuestionRepo.findBySectionIdsOrderByDisplayOrderAsc(sectionIds); + Map> questionsBySection = allQuestions.stream() + .collect(Collectors.groupingBy( + q -> q.getFormSection().getSectionId(), + Collectors.toMap(SectionQuestion::getQuestionUuid, Function.identity()))); + + Set questionIds = allQuestions.stream() + .map(SectionQuestion::getQuestionId) + .collect(Collectors.toSet()); + List allOptions = + questionOptionRepo.findByQuestionIdsOrderByDisplayOrderAsc(questionIds); + Map> optionsByQuestion = allOptions.stream() + .collect(Collectors.groupingBy( + o -> o.getSectionQuestion().getQuestionId(), + Collectors.toMap(QuestionOption::getOptionValue, Function.identity()))); + + List sectionDTOs = new ArrayList<>(); + for (SectionAnswerRequest sectionReq : req.getSections()) { + if (sectionReq.getSectionUuid() == null) { + throw new IllegalArgumentException( + "sectionUuid is null — did you send sectionCode instead?"); + } + FormSection section = sectionByUuid.get(sectionReq.getSectionUuid()); + if (section == null) { + throw new NoSuchElementException( + "Section '" + sectionReq.getSectionUuid() + + "' not found in form '" + req.getFormUuid() + "'"); + } + + // Delete existing SectionResponse (and its QuestionResponses) for this section only + sectionResponseRepo.findByResponseIdAndSectionId( + formResponse.getResponseId(), section.getSectionId()) + .ifPresent(sr -> { + questionResponseRepo.deleteBySectionResponseIdIn(Set.of(sr.getSectionResponseId())); + sectionResponseRepo.deleteById(sr.getSectionResponseId()); + }); + + SectionResponse sectionResponse = upsertSectionResponse( + formResponse.getResponseId(), section.getSectionId(), actor, vanID, parkingPlaceID); + + if ("POST_SUBMIT".equals(section.getSectionPhase())) { + formResponse.setLastFollowUpAt(sectionResponse.getSavedAt()); + formResponseRepo.save(formResponse); + } + + Map questionMap = + questionsBySection.getOrDefault(section.getSectionId(), Map.of()); + + List questionResponses = processAnswers( + sectionResponse.getSectionResponseId(), + sectionReq.getAnswers(), + questionMap, + optionsByQuestion, + actor, + vanID, + parkingPlaceID); + + questionResponseRepo.saveAll(questionResponses); + sectionDTOs.add(buildSectionResponseDTO(sectionResponse, questionResponses)); + } + + return buildFormResponseDTO(formResponse, sectionDTOs); + } + + private SectionResponse upsertSectionResponse(Long responseId, Long sectionId, String actor, + Integer vanID, Integer parkingPlaceID) { + Optional existing = + sectionResponseRepo.findByResponseIdAndSectionId(responseId, sectionId); + if (existing.isPresent()) { + SectionResponse sr = existing.get(); + sr.setStatus(SECTION_STATUS_DONE); + sr.setSavedAt(new Timestamp(System.currentTimeMillis())); + sr.setUpdatedBy(actor); + if (sr.getVanID() == null) { sr.setVanID(vanID); sr.setParkingPlaceID(parkingPlaceID); } + return sectionResponseRepo.save(sr); + } + SectionResponse sr = SectionResponse.builder() + .responseId(responseId) + .sectionId(sectionId) + .status(SECTION_STATUS_DONE) + .savedAt(new Timestamp(System.currentTimeMillis())) + .createdBy(actor) + .updatedBy(actor) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build(); + return sectionResponseRepo.save(sr); + } + + private List processAnswers( + Long sectionResponseId, + List answers, + Map questionMap, + Map> optionsByQuestion, + String actor, + Integer vanID, + Integer parkingPlaceID) { + + List results = new ArrayList<>(); + for (QuestionAnswerRequest answer : answers) { + if (answer.getQuestionUuid() == null) { + throw new IllegalArgumentException( + "questionUuid is null — did you send questionCode instead?"); + } + SectionQuestion question = questionMap.get(answer.getQuestionUuid()); + if (question == null) { + throw new NoSuchElementException( + "Question '" + answer.getQuestionUuid() + "' not found in section"); + } + QuestionType type = question.getQuestionType(); + Long questionId = question.getQuestionId(); + + if (type == QuestionType.DISPLAY) { + continue; + } + + questionResponseRepo.deleteByQuestionIdAndSectionResponseId(questionId, sectionResponseId); + + if (type == QuestionType.RADIO) { + if (answer.getOptionValue() != null) { + QuestionOption opt = resolveOption(optionsByQuestion, questionId, + answer.getOptionValue(), answer.getQuestionUuid()); + results.add(QuestionResponse.builder() + .sectionResponseId(sectionResponseId) + .questionId(questionId) + .optionId(opt != null ? opt.getOptionId() : null) + .createdBy(actor) + .updatedBy(actor) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build()); + } + } else if (type == QuestionType.MCQ) { + if (answer.getOptionValues() != null) { + for (String val : answer.getOptionValues()) { + QuestionOption opt = resolveOption(optionsByQuestion, questionId, val, + answer.getQuestionUuid()); + results.add(QuestionResponse.builder() + .sectionResponseId(sectionResponseId) + .questionId(questionId) + .optionId(opt != null ? opt.getOptionId() : null) + .createdBy(actor) + .updatedBy(actor) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build()); + } + } + } else { + // TEXT, DATE, AUTO_FILL — prefer answerText, then answerDate, then optionValue (legacy) + String value = answer.getAnswerText() != null ? answer.getAnswerText() + : answer.getAnswerDate() != null ? answer.getAnswerDate() + : answer.getOptionValue(); + results.add(QuestionResponse.builder() + .sectionResponseId(sectionResponseId) + .questionId(questionId) + .answerText(value) + .createdBy(actor) + .updatedBy(actor) + .vanID(vanID) + .parkingPlaceID(parkingPlaceID) + .build()); + } + } + return results; + } + + private QuestionOption resolveOption(Map> optionsByQuestion, + Long questionId, String optionValue, String questionUuid) { + Map opts = optionsByQuestion.get(questionId); + if (opts == null || !opts.containsKey(optionValue)) { + log.warn("Option value '{}' not found for question '{}', storing null optionId", + optionValue, questionUuid); + return null; + } + return opts.get(optionValue); + } + + private FormResponseDTO buildFormResponseDTO(FormResponse r, List sections) { + return FormResponseDTO.builder() + .responseId(r.getResponseId()) + .beneficiaryId(r.getBeneficiaryId()) + .formId(r.getFormId()) + .versionId(r.getVersionId()) + .officerId(r.getOfficerId()) + .status(r.getStatus()) + .createdBy(r.getCreatedBy()) + .updatedBy(r.getUpdatedBy()) + .submittedAt(r.getSubmittedAt()) + .completedAt(r.getCompletedAt()) + .lastFollowUpAt(r.getLastFollowUpAt()) + .createdAt(r.getCreatedAt()) + .updatedAt(r.getUpdatedAt()) + .sections(sections) + .build(); + } + + private SectionResponseDTO buildSectionResponseDTO(SectionResponse sr, List answers) { + List answerDTOs = answers.stream() + .map(a -> QuestionResponseDTO.builder() + .questionResponseId(a.getQuestionResponseId()) + .questionId(a.getQuestionId()) + .optionId(a.getOptionId()) + .answerText(a.getAnswerText()) + .build()) + .collect(Collectors.toList()); + return SectionResponseDTO.builder() + .sectionResponseId(sr.getSectionResponseId()) + .sectionId(sr.getSectionId()) + .status(sr.getStatus()) + .savedAt(sr.getSavedAt()) + .answers(answerDTOs) + .build(); + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java index e4771229..362dc1ea 100644 --- a/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IFAFormSubmissionServiceImpl.java @@ -1,6 +1,8 @@ package com.iemr.flw.service.impl; import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.controller.DeathReportsController; +import com.iemr.flw.domain.iemr.EligibleCoupleRegister; import com.iemr.flw.domain.iemr.IFAFormSubmissionData; import com.iemr.flw.domain.iemr.IncentiveActivity; import com.iemr.flw.domain.iemr.IncentiveActivityRecord; @@ -9,13 +11,15 @@ import com.iemr.flw.dto.iemr.IFAFormSubmissionRequest; import com.iemr.flw.dto.iemr.IFAFormSubmissionResponse; import com.iemr.flw.masterEnum.GroupName; -import com.iemr.flw.repo.iemr.IFAFormSubmissionRepository; -import com.iemr.flw.repo.iemr.IncentiveRecordRepo; -import com.iemr.flw.repo.iemr.IncentivesRepo; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import com.iemr.flw.masterEnum.StateCode; +import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.IFAFormSubmissionService; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; +import jakarta.persistence.criteria.CriteriaBuilder; import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -31,6 +35,9 @@ public class IFAFormSubmissionServiceImpl implements IFAFormSubmissionService { private final IFAFormSubmissionRepository repository; private final ObjectMapper mapper = new ObjectMapper(); + private final Logger logger = LoggerFactory.getLogger(IFAFormSubmissionServiceImpl.class); + + @Autowired private JwtUtil jwtUtil; @@ -42,8 +49,14 @@ public class IFAFormSubmissionServiceImpl implements IFAFormSubmissionService { @Autowired private IncentiveRecordRepo incentiveRecordRepo; + @Autowired + private UserService userService; + + @Autowired + private EligibleCoupleRegisterRepo eligibleCoupleRegisterRepo; + @Override - public String saveFormData(List requests) { + public String saveFormData(List requests, Integer userId) { try { List entities = new ArrayList<>(); for (IFAFormSubmissionRequest req : requests) { @@ -60,7 +73,7 @@ public String saveFormData(List requests) { entities.add(data); } repository.saveAll(entities); - checkIFAIncentive(entities); + checkIFAIncentive(entities,userId); return "Form data saved successfully"; } catch (Exception e) { e.printStackTrace(); @@ -68,16 +81,37 @@ public String saveFormData(List requests) { } } - private void checkIFAIncentive(List entities) { - IncentiveActivity incentiveActivityAM= incentivesRepo.findIncentiveMasterByNameAndGroup("NIPI_CHILDREN", GroupName.CHILD_HEALTH.getDisplayName()); - - if(incentiveActivityAM!=null){ - entities.forEach(ifaFormSubmissionData -> { - addIFAIncentive(ifaFormSubmissionData,incentiveActivityAM); + private void checkIFAIncentive(List entities,Integer userId) { + try { + List records = repository.findByUserId(userId); + List eligibleCoupleRegisters = eligibleCoupleRegisterRepo.getECRegRecords(userService.getUserDetail(userId).getUserName()); + int totalEligibleCouples = eligibleCoupleRegisters.size(); + int totalIFASubmissions = records.size(); + if(totalEligibleCouples>0){ + double percentage = + (totalIFASubmissions * 100.0) / totalEligibleCouples; + if(percentage>=70){ + Integer stateCode = userService.getUserDetail(userId).getStateId(); + if(stateCode.equals(StateCode.CG.getStateCode())){ + IncentiveActivity incentiveActivityCG= incentivesRepo.findIncentiveMasterByNameAndGroup("NATIONAL_IRON_PLUS", GroupName.ACTIVITY.getDisplayName()); + + if(incentiveActivityCG!=null){ + entities.forEach(ifaFormSubmissionData -> { + addIFAIncentive(ifaFormSubmissionData,incentiveActivityCG); + + }); + } + + } + } + } + }catch (Exception e){ + logger.error("Error while processing IFA incentive", e); - }); } + + } private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, IncentiveActivity incentiveActivityAM) { @@ -87,10 +121,10 @@ private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, Incent Timestamp ifaVisitDateTimestamp = Timestamp.valueOf(ifaVisitDate.atStartOfDay()); - IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivityAM.getId(),ifaVisitDateTimestamp,ifaFormSubmissionData.getBeneficiaryId()); + IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivityAM.getId(),ifaVisitDateTimestamp,ifaFormSubmissionData.getBeneficiaryId(),userServiceRoleRepo.getUserIdByName(ifaFormSubmissionData.getUserName())); if(incentiveActivityRecord==null){ incentiveActivityRecord = new IncentiveActivityRecord(); - incentiveActivityRecord.setActivityId(ifaFormSubmissionData.getId()); + incentiveActivityRecord.setActivityId(incentiveActivityAM.getId()); incentiveActivityRecord.setCreatedDate(ifaVisitDateTimestamp); incentiveActivityRecord.setStartDate(ifaVisitDateTimestamp); incentiveActivityRecord.setEndDate(ifaVisitDateTimestamp); @@ -100,6 +134,7 @@ private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, Incent incentiveActivityRecord.setBenId(ifaFormSubmissionData.getBeneficiaryId()); incentiveActivityRecord.setAshaId(userServiceRoleRepo.getUserIdByName(ifaFormSubmissionData.getUserName())); incentiveActivityRecord.setAmount(Long.valueOf(incentiveActivityAM.getRate())); + incentiveActivityRecord.setIsEligible(true); incentiveRecordRepo.save(incentiveActivityRecord); } } diff --git a/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java index b294a3dc..26a5c1c7 100644 --- a/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IRSRoundServiceImpl.java @@ -17,7 +17,7 @@ public class IRSRoundServiceImpl implements IRSRoundService { private IRSRoundRepo irsRoundRepository; @Override - public List addRounds(List dtos) { + public List addRounds(List dtos,Integer userId,String userName) { // Validate input DTOs for (IRSRoundDTO dto : dtos) { if (dto.getDate() == null || dto.getHouseholdId() == null) { @@ -26,7 +26,7 @@ public List addRounds(List dtos) { } return irsRoundRepository.saveAll( dtos.stream() - .map(dto -> new IRSRound(null, dto.getDate(), dto.getRounds(), dto.getHouseholdId())) + .map(dto -> new IRSRound(null, dto.getDate(), dto.getRounds(), dto.getHouseholdId(),userName,userId)) .collect(Collectors.toList()) ); } diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java new file mode 100644 index 00000000..b6e4b7c7 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveLogicImpl.java @@ -0,0 +1,708 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.IncentiveActivity; +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; +import com.iemr.flw.repo.iemr.IncentiveRecordRepo; +import com.iemr.flw.repo.iemr.IncentivesRepo; +import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.util.Date; + +@Service +public class IncentiveLogicImpl implements IncentiveLogicService { + + private static final Logger logger = LoggerFactory.getLogger(IncentiveLogicImpl.class); + + @Autowired + private IncentivesRepo incentivesRepo; + + @Autowired + private IncentiveRecordRepo incentiveRecordRepo; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserService userService; + + @Autowired + private UserServiceRoleRepo userServiceRoleRepo; + + @Override + public IncentiveActivityRecord incentiveForLeprosyPaucibacillaryConfirmed( + Long benId, + Date treatmentStartDate, + Date treatmentEndDate, + Integer userId) { + + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NLEP_PB_TREATMENT"; + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check NLEP_PB_TREATMENT Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForTbSuspected(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "INFORMANT_INCENTIVE"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Tb Suspected Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForLeprosyMultibacillaryConfirmed( + Long benId, + Date treatmentStartDate, + Date treatmentEndDate, + Integer userId) { + + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NLEP_MB_TREATMENT"; + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check NLEP_MB_TREATMENT Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForVhndMeeting(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "VHND_PARTICIPATION"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check VHND_PARTICIPATION Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForClusterMeeting(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "CLUSTER_MEETING"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check CLUSTER_MEETING Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForAttendingVhsnc(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "VHSNC_MEETING"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check VHSNC_MEETING Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForChildBirthGap(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "FP_DELAY_2Y"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check FP_DELAY_2Y Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForEyeSurgeyReferGovtHospital(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NPCB_GOVT_CATARACT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Eye surgery Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForEyeSurgeyReferPrivateHospital(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NPCB_PRIVATE_CATARACT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Eye surgery Incentive Exception: ", e); + return null; + } + } + + + + @Override + public IncentiveActivityRecord incentiveForGiveingIFA(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NIPI_CHILDREN"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.CHILD_HEALTH.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check IFA Exception: ", e); + return null; + } } + + @Override + public IncentiveActivityRecord incentiveForTbFollowUpIsDrTb(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "DRTB_TREATMENT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check TB Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForTbFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "DSTB_TREATMENT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check TB Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForMalariaFollowUp(Long benId, Timestamp treatmentStartDate, Timestamp treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NVBDCP_MALARIA_TREATMENT"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentStartDate, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Eye surgery Incentive Exception: ", e); + return null; + } + } + + @Override + public IncentiveActivityRecord incentiveForSecondChildGap(Long benId, Timestamp secondChildDob, Timestamp secondChildDob1, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "1st_2nd_CHILD_GAP"; + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + secondChildDob, + secondChildDob1, + userId); + } + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.FAMILY_PLANNING.getDisplayName(), + benId, + secondChildDob, + secondChildDob1, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check FP_DELAY_2Y Incentive Exception: ", e); + return null; + } + } + + + + @Override + public IncentiveActivityRecord incentiveForIdentificationLeprosy(Long benId, Date treatmentStartDate, Date treatmentEndDate, Integer userId) { + try { + Integer stateCode = userService.getUserDetail(userId).getStateId(); + + if (stateCode == null) { + logger.warn("State code is null for user: {}", userId); + return null; + } + + String activityName = "NLEP_CASE_DETECTION"; + + if (stateCode.equals(StateCode.AM.getStateCode())) { + return processIncentive( + activityName, + GroupName.UMBRELLA_PROGRAMMES.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + if (stateCode.equals(StateCode.CG.getStateCode())) { + return processIncentive( + activityName, + GroupName.ACTIVITY.getDisplayName(), + benId, + treatmentStartDate, + treatmentEndDate, + userId); + } + + // state not supported + logger.info("No incentive mapping for stateCode: {}", stateCode); + return null; + + } catch (Exception e) { + logger.error("Check Leprosy Incentive Exception: ", e); + return null; + } + } + + private IncentiveActivityRecord processIncentive(String activityName, String groupName, Long benId, + Date startDate, Date endDate, Integer userId) { + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup(activityName, groupName); + + if (activity == null) { + logger.info("No IncentiveActivity found for name: {} and group: {}", activityName, groupName); + return null ; + } + + return saveIncentive(activity, benId, startDate, endDate, userId); + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + return null; + + } + } + + private IncentiveActivityRecord saveIncentive( + IncentiveActivity activity, + Long benId, + Date startDate, + Date endDate, + Integer userId) { + + try { + String userName = userServiceRoleRepo.getUserNamedByUserId(userId); + + if (activity == null || benId == null || startDate == null || endDate == null) { + logger.warn("Invalid input for saving incentive"); + return null; + } + + Timestamp startTimestamp = new Timestamp(startDate.getTime()); + Timestamp endTimestamp = new Timestamp(endDate.getTime()); + + + // 🔍 duplicate check + IncentiveActivityRecord existing = incentiveRecordRepo + .findRecordByActivityIdCreatedDateBenId( + activity.getId(), startTimestamp, benId,userId); + + if (existing != null) { + logger.info("Incentive already exists for benId: {}, activityId: {}", + benId, activity.getId()); + return existing; + } + + // 🆕 create record + IncentiveActivityRecord record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setStartDate(startTimestamp); + record.setEndDate(endTimestamp); + record.setCreatedBy(userName); + record.setUpdatedBy(userName); + record.setBenId(benId); + record.setAshaId(userId); + record.setAmount(Long.valueOf(activity.getRate())); + + record = incentiveRecordRepo.save(record); + + logger.info("Incentive saved successfully for benId: {}", benId); + + return record; + + } catch (Exception e) { + logger.error("Error Incentive Exception: ", e); + return null; + } + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java index 6a42b76d..f109c88a 100644 --- a/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/IncentiveServiceImpl.java @@ -1,239 +1,904 @@ package com.iemr.flw.service.impl; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.iemr.flw.domain.identity.RMNCHMBeneficiarydetail; -import com.iemr.flw.domain.iemr.IncentiveActivity; -import com.iemr.flw.domain.iemr.IncentiveActivityLangMapping; -import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.IncentiveApprovalStatus; +import com.iemr.flw.masterEnum.IncentiveName; import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; -import com.iemr.flw.repo.iemr.IncentiveActivityLangMappingRepo; -import com.iemr.flw.repo.iemr.IncentiveRecordRepo; -import com.iemr.flw.repo.iemr.IncentivesRepo; -import com.iemr.flw.repo.iemr.UserServiceRoleRepo; +import com.iemr.flw.repo.iemr.*; import com.iemr.flw.service.IncentiveService; +import com.iemr.flw.service.MaaMeetingService; +import com.iemr.flw.service.UserService; import com.iemr.flw.utils.JwtUtil; +import jakarta.persistence.criteria.CriteriaBuilder; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import java.math.BigInteger; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import java.util.stream.Collectors; @Service public class IncentiveServiceImpl implements IncentiveService { - private final Logger logger = LoggerFactory.getLogger(ChildCareServiceImpl.class); + + private final Logger logger = LoggerFactory.getLogger(IncentiveServiceImpl.class); @Autowired private BeneficiaryRepo beneficiaryRepo; + @Autowired + private IncentiveActivityLangMappingRepo incentiveActivityLangMappingRepo; + @Autowired + private IncentivesRepo incentivesRepo; + @Autowired + private IncentiveRecordRepo recordRepo; + @Autowired + private IncentivePendingActivityRepository incentivePendingActivityRepository; + @Autowired + private UserServiceRoleRepo userRepo; + ; ModelMapper modelMapper = new ModelMapper(); @Autowired - private IncentiveActivityLangMappingRepo incentiveActivityLangMappingRepo; + private JwtUtil jwtUtil; + @Autowired - IncentivesRepo incentivesRepo; + private MaaMeetingService maaMeetingService; @Autowired - IncentiveRecordRepo recordRepo; + private BenReferDetailsRepo benReferDetailsRepo; @Autowired - private JwtUtil jwtUtil; + private CbacIemrDetailsRepo cbacIemrDetailsRepo; @Autowired - private UserServiceRoleRepo userRepo; + private UserService userService; + + @Autowired + private EligibleCoupleRegisterRepo eligibleCoupleRegisterRepo; + + @Autowired + private IFAFormSubmissionRepository ifaFormSubmissionRepository; + + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + + + // ================= MASTER SAVE ================= @Override public String saveIncentivesMaster(List activityDTOS) { try { - activityDTOS.forEach(activityDTO -> { + for (IncentiveActivityDTO dto : activityDTOS) { IncentiveActivity activity = - incentivesRepo.findIncentiveMasterByNameAndGroup(activityDTO.getName(), activityDTO.getGroup()); + incentivesRepo.findIncentiveMasterByNameAndGroup(dto.getName(), dto.getGroup()); if (activity == null) { activity = new IncentiveActivity(); - modelMapper.map(activityDTO, activity); - } else { - Long id = activity.getId(); - modelMapper.map(activityDTO, activity); - activity.setId(id); } + + modelMapper.map(dto, activity); incentivesRepo.save(activity); - }); - String saved = ""; - activityDTOS.forEach(dto -> saved.concat(dto.getGroup() + ": " + dto.getName())); - return "saved master data for " + saved ; + } + return "Saved successfully"; } catch (Exception e) { - + logger.error("Error saving incentives", e); + return "Error"; } - return null; } + // ================= GET MASTER ================= @Override public String getIncentiveMaster(IncentiveRequestDTO incentiveRequestDTO) { try { + Integer stateCode = incentiveRequestDTO.getState(); + String langCode = incentiveRequestDTO.getLangCode(); - List incs = new ArrayList<>(); - if(incentiveRequestDTO.getState()==StateCode.CG.getStateCode()){ - incs = incentivesRepo.findAll().stream().filter(incentiveActivity -> incentiveActivity.getGroup().equals("ACTIVITY")).collect(Collectors.toList()); + // Integer comparison using intValue() — safe and reliable + boolean isCG = stateCode != null && stateCode.intValue() == StateCode.CG.getStateCode(); + boolean isAM = stateCode != null && stateCode.intValue() == StateCode.AM.getStateCode(); - }else { - incs = incentivesRepo.findAll().stream().filter(incentiveActivity -> !incentiveActivity.getGroup().equals("ACTIVITY")).collect(Collectors.toList()); + // Single filtered DB query instead of findAll() + stream filter + List incs = isCG + ? incentivesRepo.findByGroupAndIsDeleted("ACTIVITY", false) + : incentivesRepo.findByGroupNotAndIsDeleted("ACTIVITY", false); + if (incs.isEmpty()) { + return new Gson().toJson(Collections.emptyList()); } - List dtos = incs.stream().map(inc -> { - IncentiveActivityDTO dto = modelMapper.map(inc, IncentiveActivityDTO.class); - // Fetch language mapping - IncentiveActivityLangMapping mapping = incentiveActivityLangMappingRepo - .findByIdAndName(inc.getId(),inc.getName()); + // Fetch ALL lang mappings in ONE query instead of N queries in loop + List ids = incs.stream() + .map(IncentiveActivity::getId) + .collect(Collectors.toList()); + Map mappingById = incentiveActivityLangMappingRepo + .findAllByIdIn(ids) + .stream() + .collect(Collectors.toMap( + IncentiveActivityLangMapping::getId, + Function.identity() + )); + List dtos = incs.stream().map(inc -> { + IncentiveActivityDTO dto = modelMapper.map(inc, IncentiveActivityDTO.class); + IncentiveActivityLangMapping mapping = mappingById.get(inc.getId()); if (mapping != null) { dto.setName(mapping.getName()); - dto.setGroupName(mapping.getGroup()); - if(Objects.equals(incentiveRequestDTO.getLangCode(), "en")){ + + if (isCG) { + dto.setGroupName(""); + } else if (isAM) { + dto.setGroupName(mapping.getGroup()); + } + + // Set description based on language + if ("as".equals(langCode)) { + dto.setDescription(mapping.getAssameActivityDescription() != null + ? mapping.getAssameActivityDescription() + : mapping.getDescription()); + + } else if ("hi".equals(langCode)) { + dto.setDescription(mapping.getHindiActivityDescription() != null + ? mapping.getHindiActivityDescription() + : mapping.getDescription()); + + } else { + // default "en" dto.setDescription(inc.getDescription()); + } + + } else { + if (isCG) { + dto.setGroupName(""); + } else { + dto.setGroupName(inc.getGroup()); + } + } - }else if(Objects.equals(incentiveRequestDTO.getLangCode(), "as")){ + return dto; + }).collect(Collectors.toList()); - if(mapping.getAssameActivityDescription()!=null){ - dto.setDescription(mapping.getAssameActivityDescription()); + Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return gson.toJson(dtos); - }else { - dto.setDescription(mapping.getDescription()); + } catch (Exception e) { + logger.error("Error in getIncentiveMaster: ", e); + } + return null; + } - } + @Override + public String getAllIncentivesByUserId(GetBenRequestHandler request) { + int page = 0; + int size = 20; + Page pageResult; + List finalDtos = new ArrayList<>(); + + Integer stateCode = userService.getUserDetail(request.getAshaId()).getStateId(); + String userName = userService.getUserDetail(request.getAshaId()).getUserName(); + try { + + if (stateCode.equals(StateCode.AM.getStateCode())) { + checkMonthlyAshaIncentive(request.getAshaId()); + } + if (stateCode.equals(StateCode.CG.getStateCode())) { + checkMonthlyAshaIncentiveForCg(request.getAshaId()); + + } + + } catch (Exception e) { + logger.error("Error in checkMonthlyAshaIncentive: ", e); + } + + try { + addIncentiveForIronTablets(request.getAshaId()); + incentiveOfNcdReferal(request.getAshaId(), request.getVillageID()); + + } catch (Exception e) { + logger.error("Error in incentiveOfNcdReferal: ", e); + } + + boolean isCG = stateCode != null && stateCode.equals(StateCode.CG.getStateCode()); + + do { + + Pageable pageable = PageRequest.of( + page, + size, + Sort.by("id").descending() // latest first + ); + + pageResult = recordRepo.findRecordsByAsha( + request.getAshaId(), + pageable + ); + + List entities = pageResult.getContent(); + + if (entities.isEmpty()) { + return new Gson().toJson(Collections.emptyList()); + } - }else if(Objects.equals(incentiveRequestDTO.getLangCode(), "hi")){ - if(mapping.getHindiActivityDescription()!=null){ - dto.setDescription(mapping.getHindiActivityDescription()); + // Step 2: Collect all activityIds — fetch valid ones in ONE query + List activityIds = entities.stream() + .map(IncentiveActivityRecord::getActivityId) + .distinct() + .collect(Collectors.toList()); + + // Single bulk query instead of N individual findIncentiveMasterById() calls + Set validActivityIds = isCG + ? incentivesRepo.findValidActivityIds(activityIds, true) + : incentivesRepo.findValidActivityIds(activityIds, false); + + // Filter entities based on valid activity IDs + entities = entities.stream() + .filter(e -> validActivityIds.contains(e.getActivityId())) + .collect(Collectors.toList()); + + // Step 3: Collect all benIds that need name lookup (name == null and benId > 0) + List benIdsToFetch = entities.stream() + .filter(e -> e.getName() == null && e.getBenId() != null && e.getBenId() > 0) + .map(IncentiveActivityRecord::getBenId) + .distinct() + .collect(Collectors.toList()); + + // Step 4: Bulk fetch all beneficiary names in ONE query instead of 3 queries per record + Map benIdToNameMap = new HashMap<>(); + if (!benIdsToFetch.isEmpty()) { + List benDetails = beneficiaryRepo.findBenNamesByBenIds(benIdsToFetch); + for (Object[] row : benDetails) { + Long benId = ((Number) row[0]).longValue(); + String first = row[1] != null ? (String) row[1] : ""; + String last = row[2] != null ? (String) row[2] : ""; + benIdToNameMap.put(benId, (first + " " + last).trim()); + } + } + + // Step 5: Map entities to DTOs + List dtos = entities.stream().map(entry -> { + if (entry.getName() == null) { + if (entry.getBenId() != null && entry.getBenId() > 0) { + String name = benIdToNameMap.getOrDefault(entry.getBenId(), ""); + entry.setName(name); + if (isCG) { + entry.setIsEligible(true); + } + } else { + entry.setName(""); + } + if (entry.getVerifiedByUserId() != null) { + entry.setSupervisorRole(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getRoleName()); + entry.setVerifiedByUserName(userRepo.getUserRole(entry.getVerifiedByUserId()).get(0).getName()); - }else { - dto.setDescription(mapping.getDescription()); + } + if (entry.getAshaId() != null) { + if (entry.getCreatedBy() == null) { + entry.setCreatedBy(userName); + } + if (entry.getUpdatedBy() == null) { + entry.setUpdatedBy(userName); } + if (entry.getIsEligible() == null) { + entry.setIsEligible(true); + } } - }else { - dto.setGroupName(inc.getGroup()); } + return modelMapper.map(entry, IncentiveRecordDTO.class); + }).collect(Collectors.toList()); + finalDtos.addAll(dtos); + + page++; + + } while (pageResult.hasNext()); + + + + Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return gson.toJson(finalDtos); + } + + // ================= GROUPED SUMMARY ================= + @Override + public String getAllIncentivesGroupedSummary(GetBenRequestHandler request) { + + LocalDate start = LocalDate.of(request.getYear(), request.getMonth(), 1); + LocalDate end = start.withDayOfMonth(start.lengthOfMonth()); + + Timestamp startTs = Timestamp.valueOf(start.atStartOfDay()); + Timestamp endTs = Timestamp.valueOf(end.atTime(23, 59, 59)); + + Integer villageID = userRepo.getUserRole(request.getUserId()).get(0).getStateId(); + boolean isCG = villageID != null && villageID.intValue() == StateCode.CG.getStateCode(); + + List records = + recordRepo.findRecordsByAsha(request.getUserId()) + .stream() + .filter(r -> r.getCreatedDate() != null + && r.getEndDate() != null + && r.getEndDate().toLocalDateTime().getMonthValue() == request.getMonth() + && r.getEndDate().toLocalDateTime().getYear() == request.getYear() + && r.getIsClaimed()) + .toList(); + + + // Bulk fetch valid activity IDs — state wise + List activityIds = records.stream() + .map(IncentiveActivityRecord::getActivityId) + .collect(Collectors.toList()); + + Set validActivityIds = isCG + ? incentivesRepo.findValidActivityIds(activityIds, true) + : incentivesRepo.findValidActivityIds(activityIds, false); + + // Filter records based on valid activity IDs + records = records.stream() + .filter(r -> validActivityIds.contains(r.getActivityId())) + .collect(Collectors.toList()); + + Map> grouped = + records.stream().collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); + + List> result = new ArrayList<>(); + + for (var entry : grouped.entrySet()) { + + Long activityId = entry.getKey(); + List list = entry.getValue(); + + IncentiveActivity activity = + incentivesRepo.findById(activityId).orElse(null); + + if (activity == null) continue; + + long total = list.stream() + .mapToLong(r -> r.getAmount() != null ? r.getAmount() : 0) + .sum(); + + Map map = new HashMap<>(); + map.put("activityId", activityId); + map.put("activityDec", activity.getDescription()); + map.put("groupName", activity.getGroup()); + map.put("claimCount", list.size()); + map.put("totalAmount", total); + map.put("amount", activity.getRate()); + + result.add(map); + } + + return new Gson().toJson(result); + } + + @Override + public String getAllIncentivesGroupedActivity(GetBenRequestHandler request) { + try { + + LocalDate startDate = LocalDate.of(request.getYear(), request.getMonth(), 1); + LocalDate endDate = startDate.plusMonths(1); + + Timestamp startTs = Timestamp.valueOf(startDate.atStartOfDay()); + Timestamp endTs = Timestamp.valueOf(endDate.atStartOfDay()); + + List records = + recordRepo.findRecordsByAsha(request.getUserId()) + .stream() + .filter(r -> r.getActivityId() != null + && r.getActivityId().equals(request.getActivityId()) + && r.getCreatedDate() != null + && !r.getCreatedDate().before(startTs) + && r.getCreatedDate().before(endTs)) + .collect(Collectors.toList()); + + if (records.isEmpty()) { + return new Gson().toJson(new ArrayList<>()); + } + + // 🔹 Get beneficiary names + Set benIds = records.stream() + .map(IncentiveActivityRecord::getBenId) + .filter(id -> id != null && id > 0) + .collect(Collectors.toSet()); + + Map nameMap = new HashMap<>(); + + if (!benIds.isEmpty()) { + List data = beneficiaryRepo.findBenNamesByBenIds(new ArrayList<>(benIds)); + for (Object[] row : data) { + Long id = ((Number) row[0]).longValue(); + String name = (row[1] != null ? row[1] : "") + " " + + (row[2] != null ? row[2] : ""); + nameMap.put(id, name.trim()); + } + } + + // 🔹 Activity details + IncentiveActivity activity = + incentivesRepo.findById(request.getActivityId()).orElse(null); + + String groupName = activity != null ? activity.getGroup() : ""; + String description = activity != null ? activity.getDescription() : ""; + + // 🔹 Map result + List dtos = records.stream().map(r -> { + + if (r.getName() == null) { + if (r.getBenId() != null && r.getBenId() > 0) { + r.setName(nameMap.getOrDefault(r.getBenId(), "")); + } else { + r.setName(""); + } + } + + r.setGroupName(groupName); + r.setActivityDec(description); + + return modelMapper.map(r, IncentiveRecordDTO.class); - return dto; }).collect(Collectors.toList()); - Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); + return new GsonBuilder() + .setDateFormat("MMM dd, yyyy h:mm:ss a") + .create() + .toJson(dtos); - return gson.toJson(dtos); } catch (Exception e) { - e.printStackTrace(); + logger.error("Error in getAllIncentivesGroupedActivity", e); + return null; } - return null; - } @Override - public String getAllIncentivesByUserId(GetBenRequestHandler request) { + public String updateIncentive(PendingActivityDTO pendingActivityDTO) { + try { + + if (pendingActivityDTO == null) { + return "Invalid request"; + } + +// Optional optional = +// incentivePendingActivityRepository +// .findByUserIdAndModuleNameAndActivityId( +// pendingActivityDTO.getUserId(), +// pendingActivityDTO.getModuleName(), +// pendingActivityDTO.getId() +// ); +// +// if (!optional.isPresent()) { +// return "Record not found"; +// } + +// IncentivePendingActivity existing = optional.get(); + + if (pendingActivityDTO.getImages() == null || + pendingActivityDTO.getImages().isEmpty()) { + return "No images provided"; + } + + String module = pendingActivityDTO.getModuleName(); + + // 🔹 MAA MEETING + if ("MAA_MEETING".equalsIgnoreCase(module)) { + MaaMeetingRequestDTO dto = new MaaMeetingRequestDTO(); + dto.setMeetingImages( + pendingActivityDTO.getImages().toArray(new MultipartFile[0]) + ); + + //maaMeetingService.updateMeeting(dto); + return "Updated successfully"; + } + + // 🔹 HBNC + if ("HBNC".equalsIgnoreCase(module)) { +// childCareService.updateHbncFromFileUpload( +// pendingActivityDTO.getImages().toArray(new MultipartFile[0]), +// pendingActivityDTO.getId(), +// existing.getRecordId() +// ); + return "Updated successfully"; + } + + // 🔹 UWIN SESSION + if ("UWIN".equalsIgnoreCase(module)) { + UwinSessionRequestDTO dto = new UwinSessionRequestDTO(); + dto.setAttachments( + pendingActivityDTO.getImages().toArray(new MultipartFile[0]) + ); + +// uwinSessionService.updateSession( +// dto, +// existing.getRecordId(), +// pendingActivityDTO.getId() +// ); + + return "Updated successfully"; + } + + return "No matching module found"; - if(request.getVillageID()!= StateCode.CG.getStateCode()){ - checkMonthlyAshaIncentive(request.getAshaId()); + } catch (Exception e) { + logger.error("Error in updateIncentive", e); + return "Error: " + e.getMessage(); } + } + + + // ================= UPDATE CLAIM ================= + @Transactional + public String updateClaimStatus(Integer ashaId, Integer month, Integer year, Boolean isClaimed, String token) { + try { + LocalDate start = LocalDate.of(year, month, 1); + LocalDate end = start.plusMonths(1); - List dtos = new ArrayList<>(); - List entities = recordRepo.findRecordsByAsha(request.getAshaId()); - if(request.getVillageID()==StateCode.CG.getStateCode()){ - entities = entities.stream().filter(entitie-> incentivesRepo.findIncentiveMasterById(entitie.getActivityId(),true)!=null).collect(Collectors.toList()); + int updated = recordRepo.updateClaimStatusByAshaAndDateRange( + ashaId, + isClaimed, + Timestamp.valueOf(LocalDateTime.now()), + Timestamp.valueOf(start.atStartOfDay()), + Timestamp.valueOf(end.atStartOfDay()) + ); - }else { - entities = entities.stream().filter(entitie-> incentivesRepo.findIncentiveMasterById(entitie.getActivityId(),false)!=null).collect(Collectors.toList()); + return updated > 0 ? "Success" : "No records"; + } catch (Exception e) { + logger.error("Error", e); + return "Error"; } - entities.forEach(entry -> { - if(entry.getName()==null){ - if(entry.getBenId()!=0 && entry.getBenId()>0L){ - Long regId = beneficiaryRepo.getBenRegIdFromBenId(entry.getBenId()); - logger.info("rmnchBeneficiaryDetailsRmnch"+regId); - BigInteger benDetailId = beneficiaryRepo.findByBenRegIdFromMapping(BigInteger.valueOf(regId)).getBenDetailsId(); - RMNCHMBeneficiarydetail rmnchBeneficiaryDetails = beneficiaryRepo.findByBeneficiaryDetailsId(benDetailId); - String beneName = rmnchBeneficiaryDetails.getFirstName()+" "+rmnchBeneficiaryDetails.getLastName(); - entry.setName(beneName); + } - }else{ - entry.setName(""); + private void incentiveOfNcdReferal(Integer ashaId, Integer stateId) { + try { + String userName = userRepo.getUserNamedByUserId(ashaId); + String groupName = resolveGroupName(stateId); + Map activityMap = + incentivesRepo.findIncentiveMasterByNameAndGroup( + List.of("NCD_POP_ENUMERATION", "HWC_REFERRAL_10_CASES"), groupName + ).stream().collect(Collectors.toMap(IncentiveActivity::getName, Function.identity())); + + IncentiveActivity ncdPopEnumeration = activityMap.get("NCD_POP_ENUMERATION"); + + IncentiveActivity hwcReferralEnumeration = activityMap.get("HWC_REFERRAL_10_CASES"); + + CompletableFuture> benReferFuture = + CompletableFuture.supplyAsync(() -> benReferDetailsRepo.findByCreatedBy(userName)); + CompletableFuture> cbacFuture = + CompletableFuture.supplyAsync(() -> cbacIemrDetailsRepo.findByCreatedBy(userName)); + + List cbacDetailsImer = cbacFuture.get(); + + List recordsToSave = new ArrayList<>(); + + + if (ncdPopEnumeration != null && !cbacDetailsImer.isEmpty()) { + + final IncentiveActivity activity = ncdPopEnumeration; + cbacDetailsImer.forEach(cbacDetailsImer1 -> { + if(cbacDetailsImer1!=null){ + addNCDandCBACIncentiveRecord(activity, ashaId, cbacDetailsImer1.getBeneficiaryRegId(), cbacDetailsImer1.getCreatedDate(), userName); + } + }); + } + + if (hwcReferralEnumeration != null) { + logger.info("hwcReferralEnumeration :" + hwcReferralEnumeration.getDescription()); + logger.info("userName={}", userName); + + LocalDate now = LocalDate.now(); + + Long referralCount = benReferDetailsRepo.countMonthlyReferrals( + userName, + now.getMonthValue(), + now.getYear()); + + logger.info("referralCount :" + referralCount); + + + if (referralCount >= 10) { + + addHwcReferalAshaIncentiveRecord( + hwcReferralEnumeration, + ashaId, + userName + ); } + } + // ---- Single batch insert instead of N individual saves ---- + if (!recordsToSave.isEmpty()) { + recordRepo.saveAll(recordsToSave); } - dtos.add(modelMapper.map(entry, IncentiveRecordDTO.class)); + } catch (Exception e) { + logger.error("Error in incentiveOfNcdReferal for ashaId={}, stateId={}", ashaId, stateId, e); + } + } + + // Helper — record banana + private void addNCDandCBACIncentiveRecord(IncentiveActivity activity, Integer ashaId, + Long benId, Timestamp createdDate, String userName) { + + String lockKey = activity.getId() + "_" + benId + "_" + createdDate; + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + synchronized (lock){ + IncentiveActivityRecord incentiveActivityRecord = recordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId,ashaId); + if(incentiveActivityRecord==null){ + Timestamp now = Timestamp.valueOf(LocalDateTime.now()); + IncentiveActivityRecord record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(createdDate); + record.setCreatedBy(userName); + record.setStartDate(createdDate); + record.setEndDate(createdDate); + record.setUpdatedDate(now); + record.setUpdatedBy(userName); + record.setBenId(benId); + record.setAshaId(ashaId); + record.setAmount(Long.valueOf(activity.getRate())); + recordRepo.save(record); + } + lockMap.remove(lockKey, lock); + + } - }); - Gson gson = new GsonBuilder().setDateFormat("MMM dd, yyyy h:mm:ss a").create(); - return gson.toJson(dtos); } - private void checkMonthlyAshaIncentive(Integer ashaId){ - IncentiveActivity MOBILEBILLREIMB_ACTIVITY = incentivesRepo.findIncentiveMasterByNameAndGroup("MOBILE_BILL_REIMB", GroupName.OTHER_INCENTIVES.getDisplayName()); - IncentiveActivity ADDITIONAL_ASHA_INCENTIVE = incentivesRepo.findIncentiveMasterByNameAndGroup("ADDITIONAL_ASHA_INCENTIVE", GroupName.ADDITIONAL_INCENTIVE.getDisplayName()); - IncentiveActivity ASHA_MONTHLY_ROUTINE = incentivesRepo.findIncentiveMasterByNameAndGroup("ASHA_MONTHLY_ROUTINE", GroupName.ASHA_MONTHLY_ROUTINE.getDisplayName()); - if(MOBILEBILLREIMB_ACTIVITY!=null){ - addMonthlyAshaIncentiveRecord(MOBILEBILLREIMB_ACTIVITY,ashaId); + + private String resolveGroupName(Integer stateId) { + if (stateId.equals(StateCode.CG.getStateCode())) { + logger.info("State id: {}", StateCode.CG.getStateCode()); + return GroupName.ACTIVITY.getDisplayName(); } - if(ADDITIONAL_ASHA_INCENTIVE!=null){ - addMonthlyAshaIncentiveRecord(ADDITIONAL_ASHA_INCENTIVE,ashaId); + logger.info("State id: {}", stateId); + return GroupName.NCD.getDisplayName(); + } + + private void checkMonthlyAshaIncentive(Integer ashaId) { + + try { + String userName = userRepo.getUserNamedByUserId(ashaId); + + IncentiveActivity MOBILEBILLREIMB_ACTIVITY = incentivesRepo.findIncentiveMasterByNameAndGroup("MOBILE_BILL_REIMB", GroupName.OTHER_INCENTIVES.getDisplayName()); + IncentiveActivity ADDITIONAL_ASHA_INCENTIVE = incentivesRepo.findIncentiveMasterByNameAndGroup("ADDITIONAL_ASHA_INCENTIVE", GroupName.ADDITIONAL_INCENTIVE.getDisplayName()); + IncentiveActivity ASHA_MONTHLY_ROUTINE = incentivesRepo.findIncentiveMasterByNameAndGroup("ASHA_MONTHLY_ROUTINE", GroupName.ASHA_MONTHLY_ROUTINE.getDisplayName()); + if (MOBILEBILLREIMB_ACTIVITY != null) { + addMonthlyAshaIncentiveRecord(MOBILEBILLREIMB_ACTIVITY, ashaId, userName); + } + if (ADDITIONAL_ASHA_INCENTIVE != null) { + addMonthlyAshaIncentiveRecord(ADDITIONAL_ASHA_INCENTIVE, ashaId, userName); + + } + + if (ASHA_MONTHLY_ROUTINE != null) { + addMonthlyAshaIncentiveRecord(ASHA_MONTHLY_ROUTINE, ashaId, userName); + + } + } catch (Exception e) { + logger.error("Error in addMonthlyAshaIncentiveRecord", e); } - if(ASHA_MONTHLY_ROUTINE!=null){ - addMonthlyAshaIncentiveRecord(ASHA_MONTHLY_ROUTINE,ashaId); + } + + private void checkMonthlyAshaIncentiveForCg(Integer ashaId) { + try { + String userName = userRepo.getUserNamedByUserId(ashaId); + + IncentiveActivity MONTHLY_HONORARIUM = incentivesRepo.findIncentiveMasterByNameAndGroup("MONTHLY_HONORARIUM", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity MITANIN_REGISTER_5_INFO_FILL = incentivesRepo.findIncentiveMasterByNameAndGroup("MITANIN_REGISTER_5_INFO_FILL", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity MITANIN_REGISTER = incentivesRepo.findIncentiveMasterByNameAndGroup("MITANIN_REGISTER", GroupName.ACTIVITY.getDisplayName()); + if (MONTHLY_HONORARIUM != null) { + addMonthlyAshaIncentiveRecord(MONTHLY_HONORARIUM, ashaId, userName); + } + if (MITANIN_REGISTER_5_INFO_FILL != null) { + addMonthlyAshaIncentiveRecord(MITANIN_REGISTER_5_INFO_FILL, ashaId, userName); + + } + + if (MITANIN_REGISTER != null) { + addMonthlyAshaIncentiveRecord(MITANIN_REGISTER, ashaId, userName); + + } + } catch (Exception e) { + logger.error("Error in addMonthlyAshaIncentiveRecord", e); } + } - private void addMonthlyAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId){ - Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + private void addMonthlyAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId, String userName) { + try { + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + + Timestamp startOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(1).atStartOfDay()); + Timestamp endOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).atTime(23, 59, 59)); + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + 0L, + ashaId, + startOfMonth, + endOfMonth + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(timestamp); + record.setCreatedBy(userName); + record.setStartDate(timestamp); + record.setEndDate(timestamp); + record.setUpdatedDate(timestamp); + record.setUpdatedBy(userName); + record.setBenId(0L); + record.setAshaId(ashaId); + record.setIsEligible(true); + record.setIsDefaultActivity(true); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } catch (Exception e) { + logger.error("Error in addMonthlyAshaIncentiveRecord", e); + + } + + } + + private void addHwcReferalAshaIncentiveRecord(IncentiveActivity incentiveActivity, Integer ashaId, String userName) { + try { + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + + Timestamp startOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(1).atStartOfDay()); + Timestamp endOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).atTime(23, 59, 59)); + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + 0L, + ashaId, + startOfMonth, + endOfMonth + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(timestamp); + record.setCreatedBy(userName); + record.setStartDate(timestamp); + record.setEndDate(timestamp); + record.setUpdatedDate(timestamp); + record.setUpdatedBy(userName); + record.setBenId(0L); + record.setAshaId(ashaId); + record.setIsEligible(true); + record.setIsDefaultActivity(false); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } catch (Exception e) { + logger.error("Error in addMonthlyAshaIncentiveRecord", e); + + } + + } + + private void addIncentiveForIronTablets(Integer userId) { + IncentiveActivity incentiveActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("NATIONAL_IRON_PLUS", GroupName.CHILD_HEALTH.getDisplayName()); + IncentiveActivity incentiveActivityCG = incentivesRepo.findIncentiveMasterByNameAndGroup("NATIONAL_IRON_PLUS", GroupName.ACTIVITY.getDisplayName()); + + String userName = userService.getUserDetail(userId).getUserName(); + Integer stateId = userService.getUserDetail(userId).getStateId(); + if (userName != null) { + List eligibleCoupleRegisters = eligibleCoupleRegisterRepo.findByCreatedBy(userName); + List ifaFormSubmissionData = ifaFormSubmissionRepository.findByUserId(userId); + logger.info("eligibleCoupleRegisters :" + eligibleCoupleRegisters.size()); + logger.info("ifaFormSubmissionData :" + ifaFormSubmissionData.size()); + + if (!eligibleCoupleRegisters.isEmpty() && !ifaFormSubmissionData.isEmpty()) { + int percentage = (int) (((double) ifaFormSubmissionData.size() + / eligibleCoupleRegisters.size()) * 100); + + logger.info("IFA Count : {}", ifaFormSubmissionData.size()); + logger.info("Eligible Couple Count : {}", eligibleCoupleRegisters.size()); + logger.info("Percentage : {}", percentage); + + if (percentage >= 50) { + + if (stateId.equals(StateCode.AM.getStateCode())) { + addIFAIncentive( + ifaFormSubmissionData.get(ifaFormSubmissionData.size() - 1), + incentiveActivityAM, + userId, + userName); + } + + if (stateId.equals(StateCode.CG.getStateCode())) { + addIFAIncentive( + ifaFormSubmissionData.get(ifaFormSubmissionData.size() - 1), + incentiveActivityCG, + userId, + userName); + } + } + } + + } + + + } + + private void addIFAIncentive(IFAFormSubmissionData ifaFormSubmissionData, IncentiveActivity incentiveActivityAM, Integer userId, String userName) { Timestamp startOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(1).atStartOfDay()); Timestamp endOfMonth = Timestamp.valueOf(LocalDate.now().withDayOfMonth(LocalDate.now().lengthOfMonth()).atTime(23, 59, 59)); - IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( - incentiveActivity.getId(), - startOfMonth, - endOfMonth, - 0L, - ashaId - ); - - - if (record == null) { - record = new IncentiveActivityRecord(); - record.setActivityId(incentiveActivity.getId()); - record.setCreatedDate(timestamp); - record.setCreatedBy(userRepo.getUserNamedByUserId(ashaId)); - record.setStartDate(timestamp); - record.setEndDate(timestamp); - record.setUpdatedDate(timestamp); - record.setUpdatedBy(userRepo.getUserNamedByUserId(ashaId)); - record.setBenId(0L); - record.setAshaId(ashaId); - record.setAmount(Long.valueOf(incentiveActivity.getRate())); - recordRepo.save(record); + String lockKey = incentiveActivityAM.getId() + "_" + 0 + "_" + startOfMonth; + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now()); + + + logger.info("IFA incentive"); + synchronized (lock){ + IncentiveActivityRecord incentiveActivityRecord = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivityAM.getId(), + 0L, + userId, + startOfMonth, + endOfMonth + ); + if (incentiveActivityRecord == null) { + incentiveActivityRecord = new IncentiveActivityRecord(); + incentiveActivityRecord.setActivityId(incentiveActivityAM.getId()); + incentiveActivityRecord.setCreatedDate(timestamp); + incentiveActivityRecord.setStartDate(timestamp); + incentiveActivityRecord.setEndDate(timestamp); + incentiveActivityRecord.setUpdatedDate(timestamp); + incentiveActivityRecord.setUpdatedBy(ifaFormSubmissionData.getUserName()); + incentiveActivityRecord.setCreatedBy(ifaFormSubmissionData.getUserName()); + incentiveActivityRecord.setBenId(0L); + incentiveActivityRecord.setAshaId(userId); + incentiveActivityRecord.setAmount(Long.valueOf(incentiveActivityAM.getRate())); + recordRepo.save(incentiveActivityRecord); + logger.info("saved IFA incentive"); + + } + } + lockMap.remove(lockKey, lock); + + } diff --git a/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java index 03af282a..bd040990 100644 --- a/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/InfantServiceImpl.java @@ -98,7 +98,7 @@ private void checkAndGenerateIncentive(List infantList) { } private void addIsSncuIncentive(IncentiveActivity activity, Long benId, String createdBy, Timestamp createdDate) { - IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId); + IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(activity.getId(),createdDate,benId,userServiceRoleRepo.getUserIdByName(createdBy)); if(incentiveActivityRecord==null){ incentiveActivityRecord = new IncentiveActivityRecord(); diff --git a/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java index 175c3666..ac4f7437 100644 --- a/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MalariaFollowUpServiceImpl.java @@ -1,14 +1,22 @@ package com.iemr.flw.service.impl; +import com.iemr.flw.controller.CoupleController; import com.iemr.flw.domain.iemr.MalariaFollowUp; import com.iemr.flw.dto.iemr.MalariaFollowListUpDTO; import com.iemr.flw.dto.iemr.MalariaFollowUpDTO; import com.iemr.flw.repo.iemr.MalariaFollowUpRepository; +import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.MalariaFollowUpService; +import com.iemr.flw.utils.JwtUtil; +import io.jsonwebtoken.Jwt; +import org.checkerframework.checker.units.qual.A; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.sql.Timestamp; import java.util.Date; import java.util.List; import java.util.stream.Collectors; @@ -19,30 +27,49 @@ public class MalariaFollowUpServiceImpl implements MalariaFollowUpService { @Autowired private MalariaFollowUpRepository repository; - public Boolean saveFollowUp(MalariaFollowUpDTO malariaFollowUpDTO) { + @Autowired + private IncentiveLogicService incentiveLogicService; + + private final Logger logger = LoggerFactory.getLogger(MalariaFollowUpServiceImpl.class); + + @Autowired + private JwtUtil jwtUtil; + + public Boolean saveFollowUp(MalariaFollowUpDTO malariaFollowUpDTO,String token) { + try { + for(MalariaFollowListUpDTO dto : malariaFollowUpDTO.getMalariaFollowListUp()){ + if (dto.getTreatmentStartDate().after(new Date())) { + return false; + } - for(MalariaFollowListUpDTO dto : malariaFollowUpDTO.getMalariaFollowListUp()){ - if (dto.getTreatmentStartDate().after(new Date())) { - return false; - } + if (dto.getTreatmentCompletionDate() != null && + dto.getTreatmentCompletionDate().before(dto.getTreatmentStartDate())) { + return false; + } - if (dto.getTreatmentCompletionDate() != null && - dto.getTreatmentCompletionDate().before(dto.getTreatmentStartDate())) { - return false; - } - if (dto.getReferralDate() != null && - dto.getReferralDate().before(dto.getTreatmentStartDate())) { - return false; - } + dto.setUserId(jwtUtil.extractUserId(token)); + MalariaFollowUp entity = new MalariaFollowUp(); + BeanUtils.copyProperties(dto, entity); + entity.setModifiedBy(jwtUtil.extractUsername(token)); + repository.save(entity); + if(entity!=null){ + incentiveLogicService.incentiveForMalariaFollowUp( + entity.getBenId(), + new Timestamp(entity.getTreatmentStartDate().getTime()), + new Timestamp(entity.getTreatmentCompletionDate().getTime()), + entity.getUserId() + ); + } + return true; + } + }catch (Exception e){ + logger.error("Exception saveFollowUp: "+ e.getMessage()); + return false; + } - MalariaFollowUp entity = new MalariaFollowUp(); - BeanUtils.copyProperties(dto, entity); - repository.save(entity); - return true; - } return false; } @@ -50,6 +77,8 @@ public List getByUserId(Integer userId) { return repository.findByUserId(userId).stream().map(entity -> { MalariaFollowListUpDTO dto = new MalariaFollowListUpDTO(); BeanUtils.copyProperties(entity, dto); + dto.setUpdateDate(entity.getLastModDate()); + dto.setUpdatedBy(entity.getModifiedBy()); return dto; }).collect(Collectors.toList()); } diff --git a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java index 53ba1d28..23973862 100644 --- a/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/MaternalHealthServiceImpl.java @@ -5,19 +5,31 @@ import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.IncentiveService; import com.iemr.flw.service.MaternalHealthService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.exception.IEMRException; +import jakarta.transaction.Transactional; import org.modelmapper.ModelMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @Service @@ -58,6 +70,12 @@ public class MaternalHealthServiceImpl implements MaternalHealthService { @Autowired private IncentiveRecordRepo recordRepo; + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private IncentiveLogicService incentiveLogicService; + ObjectMapper mapper = new ObjectMapper(); @@ -67,10 +85,16 @@ public class MaternalHealthServiceImpl implements MaternalHealthService { @Autowired private SMSServiceImpl smsServiceImpl; + @Autowired + private AncCounsellingCareRepo ancCounsellingCareRepo; + public static final List PNC_PERIODS = Arrays.asList("1st Day", "3rd Day", "7th Day", "14th Day", "21st Day", "28th Day", "42nd Day"); + private final ConcurrentHashMap lockMap = new ConcurrentHashMap<>(); + + @Override public String registerPregnantWoman(List pregnantWomanDTOs) { @@ -122,39 +146,68 @@ public List getANCVisits(GetBenRequestHandler dto) { try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); List ancVisits = ancVisitRepo.getANCForPW(user, dto.getFromDate(), dto.getToDate()); + checkAndAddIncentives(ancVisits, dto.getAshaId()); + return ancVisits.stream() .map(anc -> mapper.convertValue(anc, ANCVisitDTO.class)) .collect(Collectors.toList()); } catch (Exception e) { - logger.error(e.getMessage()); + logger.error("ANC VISIT :---------------------" + e.getMessage()); } return null; } @Override - public String saveANCVisit(List ancVisitDTOs) { + public String saveANCVisit(List ancVisitDTOs, Integer userId) { try { + + logger.info("ANC save process started. Total records: {}", ancVisitDTOs.size()); + List ancList = new ArrayList<>(); List ancCareList = new ArrayList<>(); + ancVisitDTOs.forEach(it -> { - ANCVisit ancVisit = + + logger.info("Processing Beneficiary Id: {} ANC Visit: {}", it.getBenId(), it.getAncVisit()); + logger.info("Processing Beneficiary Id: {} ANC Visit: {}", it.getBenId(), it.getIsPaiucdId()); + + List ancVisitList = ancVisitRepo.findANCVisitByBenIdAndAncVisitAndIsActive(it.getBenId(), it.getAncVisit(), true); + ANCVisit ancVisit = new ANCVisit(); + if (!ancVisitList.isEmpty()) { + ancVisit = ancVisitList.get(0); + } + logger.info("ANC visit fetch completed"); if (ancVisit != null) { + + logger.info("Existing ANC visit found for BenId: {}", it.getBenId()); + Long id = ancVisit.getId(); modelMapper.map(it, ancVisit); ancVisit.setId(id); + } else { + + logger.info("New ANC visit will be created for BenId: {}", it.getBenId()); + ancVisit = new ANCVisit(); modelMapper.map(it, ancVisit); ancVisit.setId(null); Long benRegId = beneficiaryRepo.getRegIDFromBenId(it.getBenId()); + logger.info("Beneficiary Reg Id fetched: {}", benRegId); + // Saving data in BenVisitDetails table - PregnantWomanRegister pwr = pregnantWomanRegisterRepo.findPregnantWomanRegisterByBenIdAndIsActive(it.getBenId(), true); + PregnantWomanRegister pwr = pregnantWomanRegisterRepo + .findPregnantWomanRegisterByBenIdAndIsActive(it.getBenId(), true); + + logger.info("PregnantWomanRegister fetched"); + BenVisitDetail benVisitDetail = new BenVisitDetail(); modelMapper.map(it, benVisitDetail); + benVisitDetail.setBeneficiaryRegId(benRegId); benVisitDetail.setVisitCategory("ANC"); benVisitDetail.setVisitReason("Follow Up"); @@ -163,37 +216,72 @@ public String saveANCVisit(List ancVisitDTOs) { benVisitDetail.setModifiedBy(it.getUpdatedBy()); benVisitDetail.setLastModDate(it.getUpdatedDate()); benVisitDetail.setProviderServiceMapID(it.getProviderServiceMapID()); + if (benVisitDetail.getCreatedDate() == null) + benVisitDetail.setCreatedDate(new java.sql.Timestamp(System.currentTimeMillis())); + + logger.info("Saving BenVisitDetail"); + benVisitDetail = benVisitDetailsRepo.save(benVisitDetail); + logger.info("BenVisitDetail saved with id: {}", benVisitDetail.getBenVisitId()); + // Saving Data in AncCare table AncCare ancCare = new AncCare(); modelMapper.map(it, ancCare); + ancCare.setBenVisitId(benVisitDetail.getBenVisitId()); ancCare.setBeneficiaryRegId(benRegId); + if (pwr != null) { + + logger.info("LMP found calculating EDD"); + ancCare.setLastMenstrualPeriodLmp(pwr.getLmpDate()); + Calendar cal = Calendar.getInstance(); cal.setTime(pwr.getLmpDate()); cal.add(Calendar.DAY_OF_WEEK, 280); + ancCare.setExpectedDateofDelivery(new Timestamp(cal.getTime().getTime())); } + ancCare.setTrimesterNumber(it.getAncVisit().shortValue()); ancCare.setModifiedBy(it.getUpdatedBy()); ancCare.setLastModDate(it.getUpdatedDate()); ancCare.setProcessed("N"); + ancCareList.add(ancCare); + + logger.info("AncCare added to list"); } + ancList.add(ancVisit); + logger.info("ANCVisit added to list"); + }); + logger.info("Saving ANCVisit list"); + ancVisitRepo.saveAll(ancList); + + logger.info("ANCVisit saved successfully"); + + logger.info("Saving AncCare list"); + ancCareRepo.saveAll(ancCareList); - checkAndAddIncentives(ancList); + + logger.info("AncCare saved successfully"); + logger.info("ANC visit details saved"); + checkAndAddIncentives(ancList, userId); + return "no of anc details saved: " + ancList.size(); + } catch (Exception e) { - logger.info("Saving ANC visit details failed with error : " + e.getMessage()); - logger.info("Saving ANC visit details failed with error : " + e); + + logger.error("Saving ANC visit details failed with error : {}", e.getMessage()); + logger.error("Full exception : ", e); + } return null; } @@ -232,6 +320,7 @@ public String savePmsmaRecords(List pmsmaDTOs) { }); pmsmaRepo.saveAll(pmsmaList); logger.info("PMSMA details saved"); + checkAndAddHighRisk(pmsmaList); return "No. of PMSMA records saved: " + pmsmaList.size(); @@ -268,7 +357,7 @@ private void checkAndAddHighRisk(List pmsmaList) { private void addIncentiveForHighRisk(IncentiveActivity incentiveActivity, PMSMA pmsma) { IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), pmsma.getCreatedDate(), pmsma.getBenId()); + .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), pmsma.getCreatedDate(), pmsma.getBenId(),userRepo.getUserIdByName(pmsma.getCreatedBy())); // get bene details if (record == null) { @@ -291,7 +380,7 @@ record = new IncentiveActivityRecord(); public List getPNCVisits(GetBenRequestHandler dto) { try { String user = beneficiaryRepo.getUserName(dto.getAshaId()); - List pncVisits = pncVisitRepo.getPNCForPW(user, dto.getFromDate(), dto.getToDate()); + List pncVisits = pncVisitRepo.getPNCForPW(user); return pncVisits.stream() .map(pnc -> mapper.convertValue(pnc, PNCVisitDTO.class)) .collect(Collectors.toList()); @@ -331,6 +420,8 @@ public String savePNCVisit(List pncVisitDTOs) { benVisitDetail.setProcessed("N"); benVisitDetail.setModifiedBy(it.getUpdatedBy()); benVisitDetail.setLastModDate(it.getUpdatedDate()); + if (benVisitDetail.getCreatedDate() == null) + benVisitDetail.setCreatedDate(new java.sql.Timestamp(System.currentTimeMillis())); benVisitDetail = benVisitDetailsRepo.save(benVisitDetail); // Saving Data in AncCare table @@ -343,7 +434,7 @@ public String savePNCVisit(List pncVisitDTOs) { pncCare.setLastModDate(it.getUpdatedDate()); pncCare.setProcessed("N"); pncCareList.add(pncCare); - checkAndAddAntaraIncentive(pncList, pncVisit); + checkAndAddAntaraIncentive(pncVisit); } pncList.add(pncVisit); }); @@ -357,218 +448,431 @@ public String savePNCVisit(List pncVisitDTOs) { return null; } - private void checkAndAddAntaraIncentive(List recordList, PNCVisit ect) { - Integer userId = userRepo.getUserIdByName(ect.getCreatedBy()); - logger.info("ContraceptionMethod:" + ect.getContraceptionMethod()); + @Override + @Transactional + public String saveANCVisitQuestions(List dtos, String authorization) throws IEMRException { + Integer userId = jwtUtil.extractUserId(authorization); + String userName = userRepo.getUserNamedByUserId(userId); - if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("MALE STERILIZATION")) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + List entities = new ArrayList<>(); - IncentiveActivity maleSterilizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); + for (AncCounsellingCareDTO dto : dtos) { - IncentiveActivity maleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); - if (maleSterilizationActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, maleSterilizationActivityAM); - } - if (maleSterilizationActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, maleSterilizationActivityCH); + if (!StringUtils.hasText(dto.getVisitDate())) { + throw new IllegalArgumentException("visitDate is mandatory"); } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { - - IncentiveActivity femaleSterilizationActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); - - IncentiveActivity femaleSterilizationActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - if (femaleSterilizationActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, femaleSterilizationActivityAM); + AncCounsellingCareListDTO fields = dto.getFields(); + if (fields == null) { + throw new IllegalArgumentException("fields object is mandatory"); } - if (femaleSterilizationActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, femaleSterilizationActivityCH); + LocalDate visitDate; + try { + visitDate = LocalDate.parse(dto.getVisitDate(), formatter); + } catch (DateTimeParseException e) { + throw new IllegalArgumentException("Invalid visitDate format, expected dd-MM-yyyy"); } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("MiniLap")) { - IncentiveActivity miniLapActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MINILAP", GroupName.FAMILY_PLANNING.getDisplayName()); - if (miniLapActivity != null) { - addIncenticeRecord(recordList, ect, userId, miniLapActivity); + LocalDate homeVisitDate; + try { + homeVisitDate = StringUtils.hasText(fields.getHomeVisitDate()) + ? LocalDate.parse(fields.getHomeVisitDate(), formatter) + : visitDate; // ✅ fallback + } catch (DateTimeParseException e) { + throw new IllegalArgumentException("Invalid home_visit_date format, expected dd-MM-yyyy"); } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("Condom")) { - IncentiveActivity comdomActivity = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", GroupName.FAMILY_PLANNING.getDisplayName()); - if (comdomActivity != null) { - addIncenticeRecord(recordList, ect, userId, comdomActivity); - } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD) WITHIN 48 HRS OF DELIVERY")) { + AncCounsellingCare entity = new AncCounsellingCare(); + entity.setBeneficiaryId(dto.getBeneficiaryId()); + entity.setAncVisitId(0L); + entity.setVisitDate(visitDate); + entity.setHomeVisitDate(homeVisitDate); + + entity.setSelectAll(yesNoToBoolean(fields.getSelectAll())); + entity.setSwelling(yesNoToBoolean(fields.getSwelling())); + entity.setHighBp(yesNoToBoolean(fields.getHighBp())); + entity.setConvulsions(yesNoToBoolean(fields.getConvulsions())); + entity.setAnemia(yesNoToBoolean(fields.getAnemia())); + entity.setReducedFetalMovement(yesNoToBoolean(fields.getReducedFetalMovement())); + entity.setAgeRisk(yesNoToBoolean(fields.getAgeRisk())); + entity.setChildGap(yesNoToBoolean(fields.getChildGap())); + entity.setShortHeight(yesNoToBoolean(fields.getShortHeight())); + entity.setPrePregWeight(yesNoToBoolean(fields.getPrePregWeight())); + entity.setBleeding(yesNoToBoolean(fields.getBleeding())); + entity.setMiscarriageHistory(yesNoToBoolean(fields.getMiscarriageHistory())); + entity.setFourPlusDelivery(yesNoToBoolean(fields.getFourPlusDelivery())); + entity.setFirstDelivery(yesNoToBoolean(fields.getFirstDelivery())); + entity.setTwinPregnancy(yesNoToBoolean(fields.getTwinPregnancy())); + entity.setCSectionHistory(yesNoToBoolean(fields.getCSectionHistory())); + entity.setPreExistingDisease(yesNoToBoolean(fields.getPreExistingDisease())); + entity.setFeverMalaria(yesNoToBoolean(fields.getFeverMalaria())); + entity.setJaundice(yesNoToBoolean(fields.getJaundice())); + entity.setSickleCell(yesNoToBoolean(fields.getSickleCell())); + entity.setProlongedLabor(yesNoToBoolean(fields.getProlongedLabor())); + entity.setMalpresentation(yesNoToBoolean(fields.getMalpresentation())); + + entity.setUserId(userId); + entity.setCreatedBy(userName); + entity.setUpdatedBy(userName); + + entities.add(entity); + } - IncentiveActivity PPIUCDActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + ancCounsellingCareRepo.saveAll(entities); - IncentiveActivity PPIUCDActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.ACTIVITY.getDisplayName()); - if (PPIUCDActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, PPIUCDActivityAM); - } + return "ANC Counselling & Care data saved successfully"; + } - if (PPIUCDActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, PPIUCDActivityCH); - } - } else if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)")) { - IncentiveActivity ppsActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.FAMILY_PLANNING.getDisplayName()); + @Override + public List getANCCounselling(GetBenRequestHandler requestDTO) { + + List entities = + ancCounsellingCareRepo.findAllByUserId(requestDTO.getAshaId()); + + List responseDTOList = new ArrayList<>(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + + for (AncCounsellingCare entity : entities) { + + AncCounsellingCareResponseDTO responseDTO = new AncCounsellingCareResponseDTO(); + responseDTO.setFormId("anc_form_001"); + responseDTO.setBeneficiaryId(entity.getBeneficiaryId()); // Update with actual value + responseDTO.setVisitDate(entity.getVisitDate().format(formatter)); // Format visit.getVisitDate() + + // 🔹 fields map + Map fields = new HashMap<>(); + + fields.put("home_visit_date", + entity.getHomeVisitDate() != null + ? entity.getHomeVisitDate().format(formatter) + : null); + + fields.put("select_all", booleanToYesNo(entity.getSelectAll())); + fields.put("swelling", booleanToYesNo(entity.getSwelling())); + fields.put("high_bp", booleanToYesNo(entity.getHighBp())); + fields.put("convulsions", booleanToYesNo(entity.getConvulsions())); + fields.put("anemia", booleanToYesNo(entity.getAnemia())); + fields.put("reduced_fetal_movement", booleanToYesNo(entity.getReducedFetalMovement())); + fields.put("age_risk", booleanToYesNo(entity.getAgeRisk())); + fields.put("child_gap", booleanToYesNo(entity.getChildGap())); + fields.put("short_height", booleanToYesNo(entity.getShortHeight())); + fields.put("pre_preg_weight", booleanToYesNo(entity.getPrePregWeight())); + fields.put("bleeding", booleanToYesNo(entity.getBleeding())); + fields.put("miscarriage_history", booleanToYesNo(entity.getMiscarriageHistory())); + fields.put("four_plus_delivery", booleanToYesNo(entity.getFourPlusDelivery())); + fields.put("first_delivery", booleanToYesNo(entity.getFirstDelivery())); + fields.put("twin_pregnancy", booleanToYesNo(entity.getTwinPregnancy())); + fields.put("c_section_history", booleanToYesNo(entity.getCSectionHistory())); + fields.put("pre_existing_disease", booleanToYesNo(entity.getPreExistingDisease())); + fields.put("fever_malaria", booleanToYesNo(entity.getFeverMalaria())); + fields.put("jaundice", booleanToYesNo(entity.getJaundice())); + fields.put("sickle_cell", booleanToYesNo(entity.getSickleCell())); + fields.put("prolonged_labor", booleanToYesNo(entity.getProlongedLabor())); + fields.put("malpresentation", booleanToYesNo(entity.getMalpresentation())); + + responseDTO.setFields(fields); + responseDTOList.add(responseDTO); - IncentiveActivity ppsActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.ACTIVITY.getDisplayName()); - if (ppsActivityAM != null) { - addIncenticeRecord(recordList, ect, userId, ppsActivityAM); - } - if (ppsActivityCH != null) { - addIncenticeRecord(recordList, ect, userId, ppsActivityCH); - } } + return responseDTOList; } - private void addIncenticeRecord(List recordList, PNCVisit ect, Integer userId, IncentiveActivity antaraActivity) { - IncentiveActivityRecord record = recordRepo - .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getCreatedDate(), ect.getBenId()); - // get bene details + private String booleanToYesNo(Boolean value) { + return Boolean.TRUE.equals(value) ? "Yes" : "No"; + } - if (record == null) { - record = new IncentiveActivityRecord(); - record.setActivityId(antaraActivity.getId()); - record.setCreatedDate(ect.getPncDate()); - record.setCreatedBy(ect.getCreatedBy()); - record.setStartDate(ect.getPncDate()); - record.setEndDate(ect.getPncDate()); - record.setUpdatedDate(ect.getPncDate()); - record.setUpdatedBy(ect.getCreatedBy()); - record.setBenId(ect.getBenId()); - record.setAshaId(userId); - record.setAmount(Long.valueOf(antaraActivity.getRate())); - recordRepo.save(record); - } + + private Boolean yesNoToBoolean(String value) { + return "Yes".equalsIgnoreCase(value); } - private void checkAndAddIncentives(List ancList) { + private void checkAndAddAntaraIncentive(PNCVisit ect) { + Integer userId = userRepo.getUserIdByName(ect.getCreatedBy()); + Integer stateId = userRepo.getUserRole(userId).get(0).getStateId(); + logger.info("ContraceptionMethod:" + ect.getContraceptionMethod()); - IncentiveActivity anc1Activity = - incentivesRepo.findIncentiveMasterByNameAndGroup("ANC_REGISTRATION_1ST_TRIM", GroupName.MATERNAL_HEALTH.getDisplayName()); + // logic for assam + if (stateId.equals(StateCode.AM.getStateCode())) { + if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("MALE STERILIZATION")) { - IncentiveActivity ancFullActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FULL_ANC", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity maleSterilizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); - IncentiveActivity ancFullActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("ANC_FOUR_CHECKUPS_SUPPORT", GroupName.ACTIVITY.getDisplayName()); + if (maleSterilizationActivityAM != null) { + addIncenticeRecord(ect, userId, maleSterilizationActivityAM); + } - IncentiveActivity comprehensiveAbortionActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("COMPREHENSIVE_ABORTION_CARE", GroupName.MATERNAL_HEALTH.getDisplayName()); - IncentiveActivity comprehensiveAbortionActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("COMPREHENSIVE_ABORTION_CARE", GroupName.ACTIVITY.getDisplayName()); - IncentiveActivity identifiedHrpActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("EPMSMA_HRP_IDENTIFIED", GroupName.MATERNAL_HEALTH.getDisplayName()); - IncentiveActivity identifiedHrpActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("EPMSMA_HRP_IDENTIFIED", GroupName.ACTIVITY.getDisplayName()); + } + if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { - IncentiveActivity paiucdActivityAM = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PAIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + IncentiveActivity femaleSterilizationActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.FAMILY_PLANNING.getDisplayName()); + if (femaleSterilizationActivityAM != null) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityAM); + } - IncentiveActivity paiucdActivityCH = - incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PAIUCD", GroupName.ACTIVITY.getDisplayName()); + } + if (ect.getContraceptionMethod() != null && (ect.getContraceptionMethod().equals("MiniLap") || ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)"))) { - ancList.forEach(ancVisit -> { - if (paiucdActivityAM != null) { - if (ancVisit.getIsPaiucd()!= null) { - if (ancVisit.getIsPaiucd().equals("Yes")) { - recordAncRelatedIncentive(paiucdActivityAM, ancVisit); + IncentiveActivity miniLapActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.FAMILY_PLANNING.getDisplayName()); + if (miniLapActivity != null) { + addIncenticeRecord(ect, userId, miniLapActivity); + } + } + if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("Condom")) { - } + IncentiveActivity comdomActivity = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_CONDOM", GroupName.FAMILY_PLANNING.getDisplayName()); + if (comdomActivity != null) { + addIncenticeRecord(ect, userId, comdomActivity); + } + } + if (ect.getContraceptionMethod() != null && ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD) WITHIN 48 HRS OF DELIVERY")) { + + IncentiveActivity PPIUCDActivityAM = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + + if (PPIUCDActivityAM != null) { + addIncenticeRecord(ect, userId, PPIUCDActivityAM); } } - if (paiucdActivityCH != null) { - if (ancVisit.getIsPaiucd()!= null) { - if (ancVisit.getIsPaiucd().equals("Yes")) { + } + // logic for cg + if (stateId.equals(StateCode.CG.getStateCode())) { + if (ect.getAnyContraceptionMethod() != null) { + if (ect.getAnyContraceptionMethod()) { + IncentiveActivity femaleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_FEMALE_STER", GroupName.ACTIVITY.getDisplayName()); - recordAncRelatedIncentive(paiucdActivityCH, ancVisit); + IncentiveActivity PPIUCDActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPIUCD", GroupName.ACTIVITY.getDisplayName()); + + IncentiveActivity maleSterilizationActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_MALE_STER", GroupName.ACTIVITY.getDisplayName()); + + + if (PPIUCDActivityCH != null) { + if (ect.getContraceptionMethod().equals("POST PARTUM IUCD (PPIUCD)")) { + addIncenticeRecord(ect, userId, PPIUCDActivityCH); + + } } - } - } - if (anc1Activity != null) { - if (ancVisit.getAncVisit() != null) { + if (femaleSterilizationActivityCH != null) { + if (ect.getContraceptionMethod().equals("FEMALE STERILIZATION")) { + addIncenticeRecord(ect, userId, femaleSterilizationActivityCH); - if (ancVisit.getAncVisit() == 1) { - recordAncRelatedIncentive(anc1Activity, ancVisit); + } + } + + + if (maleSterilizationActivityCH != null) { + if (ect.getContraceptionMethod().equals("MALE STERILIZATION")) { + addIncenticeRecord(ect, userId, maleSterilizationActivityCH); + + } } } + } - if (ancFullActivityAM != null) { - if (ancVisit.getAncVisit() == 4 || ancVisit.getAncVisit() == 2 || ancVisit.getAncVisit() == 3) { - recordAncRelatedIncentive(ancFullActivityAM, ancVisit); + + if (ect.getMotherDangerSign() != null + && !ect.getMotherDangerSign().isEmpty() + && ect.getPncPeriod() == 42) { + IncentiveActivity highRiskPostpartumCareActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_CARE", GroupName.ACTIVITY.getDisplayName()); + if (highRiskPostpartumCareActivityCH != null) { + addIncenticeRecord(ect, userId, highRiskPostpartumCareActivityCH); + } } - if (ancFullActivityCH != null) { - if (ancVisit.getAncVisit() != null) { - if (ancVisit.getAncVisit() == 4) { - recordAncRelatedIncentive(ancFullActivityCH, ancVisit); - } + if (ect.getPncPeriod() == 42) { + IncentiveActivity highRiskPostpartumHealthCareActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("HIGH_RISK_POSTPARTUM_HEALTH_CHECK", GroupName.ACTIVITY.getDisplayName()); + + if (highRiskPostpartumHealthCareActivityCH != null) { + addIncenticeRecord(ect, userId, highRiskPostpartumHealthCareActivityCH); + } + } - if (comprehensiveAbortionActivityAM != null) { - if (ancVisit.getIsAborted() != null) { - if (ancVisit.getIsAborted()) { - recordAncRelatedIncentive(comprehensiveAbortionActivityAM, ancVisit); + if (ect.getPncPeriod() == 1 || ect.getPncPeriod() == 3 || ect.getPncPeriod() == 7) { + + if ((ect.getContraceptionMethod().equals("POST PARTUM STERILIZATION (PPS)") + || ect.getContraceptionMethod().equals("MiniLap")) + && ect.getSterilisationDate() != null) { + IncentiveActivity ppsActivityCH = + incentivesRepo.findIncentiveMasterByNameAndGroup("FP_PPS", GroupName.ACTIVITY.getDisplayName()); + if (ppsActivityCH != null) { + + addIncenticeRecord(ect, userId, ppsActivityCH); + } } + } + + } + + + } + + + @Transactional + private void addIncenticeRecord(PNCVisit ect, Integer userId, IncentiveActivity antaraActivity) { + + String lockKey = antaraActivity.getId() + "_" + ect.getBenId() + "_" + ect.getPncDate(); + + Object lock = lockMap.computeIfAbsent(lockKey, k -> new Object()); + synchronized (lock) { + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(antaraActivity.getId(), ect.getPncDate(), ect.getBenId(),userId); + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(antaraActivity.getId()); + record.setCreatedDate(ect.getPncDate()); + record.setCreatedBy(ect.getCreatedBy()); + record.setStartDate(ect.getPncDate()); + record.setEndDate(ect.getPncDate()); + record.setUpdatedDate(ect.getPncDate()); + record.setUpdatedBy(ect.getCreatedBy()); + record.setBenId(ect.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(antaraActivity.getRate())); + recordRepo.save(record); } + } + + lockMap.remove(lockKey, lock); + } + + + private void checkAndAddIncentives(List ancList, Integer userId) { - if (comprehensiveAbortionActivityCH != null) { - if (ancVisit.getIsAborted() != null) { - if (ancVisit.getIsAborted()) { - recordAncRelatedIncentive(comprehensiveAbortionActivityCH, ancVisit); + Integer stateId = userRepo.getUserRole(userId).get(0).getStateId(); + + + // ✅ State 5 — Assam + if (stateId.equals(5)) { + IncentiveActivity anc1Activity = incentivesRepo.findIncentiveMasterByNameAndGroup( + "ANC_REGISTRATION_1ST_TRIM", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity ancFullActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FULL_ANC", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity identifiedHrpActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("EPMSMA_HRP_IDENTIFIED", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity comprehensiveAbortionActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "COMPREHENSIVE_ABORTION_CARE", GroupName.MATERNAL_HEALTH.getDisplayName()); + IncentiveActivity paiucdActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_PAIUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + + IncentiveActivity iucdActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_IUCD", GroupName.FAMILY_PLANNING.getDisplayName()); + ancList.forEach(ancVisit -> { + if(ancVisit.getIsAborted()){ + if (paiucdActivityAM != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==2 && + ancVisit.getIsPaiucd().toString().contains("Tubectomy")) { + recordAncRelatedIncentive(paiucdActivityAM, ancVisit); + } + if (iucdActivityAM != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==1 && + ancVisit.getIsPaiucd().toString().contains("Copper-T")) { + recordAncRelatedIncentive(iucdActivityAM, ancVisit); } } - } - if (identifiedHrpActivityAM != null) { - if (ancVisit.getIsHrpConfirmed() != null) { - if (ancVisit.getIsHrpConfirmed()) { - recordAncRelatedIncentive(identifiedHrpActivityAM, ancVisit); - } + + + if (anc1Activity != null && ancVisit.getAncVisit() != null + && ancVisit.getAncVisit() == 1) { + recordAncFirstTRIMIncentive(anc1Activity, ancVisit); + } + + if (ancFullActivityAM != null && ancVisit.getAncVisit() != null + && ancVisit.getAncVisit() == 4) { + recordFullAncIncentive(ancFullActivityAM, ancVisit); + } + + + if (comprehensiveAbortionActivityAM != null && ancVisit.getIsAborted() != null + && ancVisit.getIsAborted()) { + recordAncRelatedIncentive(comprehensiveAbortionActivityAM, ancVisit); + } + + + if (identifiedHrpActivityAM != null && ancVisit.getIsHrpConfirmed() != null + && ancVisit.getIsHrpConfirmed()) { + recordAncRelatedIncentive(identifiedHrpActivityAM, ancVisit); } - } - if (identifiedHrpActivityCH != null) { - if (ancVisit.getIsHrpConfirmed() != null) { - if (ancVisit.getIsHrpConfirmed()) { - recordAncRelatedIncentive(identifiedHrpActivityCH, ancVisit); + }); + } + + // ✅ State 8 + if (stateId.equals(8)) { + + IncentiveActivity ancFullActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "ANC_FOUR_CHECKUPS_SUPPORT", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity comprehensiveAbortionActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "COMPREHENSIVE_ABORTION_CARE", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity identifiedHrpActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "EPMSMA_HRP_IDENTIFIED", GroupName.ACTIVITY.getDisplayName()); + IncentiveActivity paiucdActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_PAIUCD", GroupName.ACTIVITY.getDisplayName()); + + IncentiveActivity iucdActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup( + "FP_IUCD", GroupName.ACTIVITY.getDisplayName()); + + ancList.forEach(ancVisit -> { + + + if (ancVisit.getIsAborted()) { + if (paiucdActivityCH != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==2 && + ancVisit.getIsPaiucd().toString().contains("Tubectomy")) { + recordAncRelatedIncentive(paiucdActivityCH, ancVisit); + } + if (iucdActivityCH != null && ancVisit.getIsPaiucdId() != null && ancVisit.getIsPaiucdId()==1 + && ancVisit.getIsPaiucd().toString().contains("Copper-T")) { + recordAncRelatedIncentive(iucdActivityCH, ancVisit); } } - } - }); + if (ancFullActivityCH != null && ancVisit.getAncVisit() != null + && ancVisit.getAncVisit() == 4) { + recordAncRelatedIncentive(ancFullActivityCH, ancVisit); + } + + + if (identifiedHrpActivityCH != null && ancVisit.getIsHrpConfirmed() != null + && ancVisit.getIsHrpConfirmed()) { + recordAncRelatedIncentive(identifiedHrpActivityCH, ancVisit); + } + }); + } } private void recordAncRelatedIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { - IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), ancVisit.getCreatedDate(), ancVisit.getBenId()); Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), ancVisit.getCreatedDate(), ancVisit.getBenId(),userId); + if (record == null) { record = new IncentiveActivityRecord(); record.setActivityId(incentiveActivity.getId()); @@ -586,6 +890,74 @@ record = new IncentiveActivityRecord(); } + private void recordAncFirstTRIMIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { + Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); + + if (ancVisit.getAncDate() == null || ancVisit.getLmpDate() == null) { + return; + } + + LocalDate ancLocalDate = ancVisit.getAncDate().toLocalDateTime().toLocalDate(); + LocalDate lmpLocalDate = ancVisit.getLmpDate().toLocalDateTime().toLocalDate(); + + long weeksBetween = ChronoUnit.WEEKS.between(lmpLocalDate, ancLocalDate); + + if (weeksBetween < 0 || weeksBetween >= 12) { + return; + } + + IncentiveActivityRecord record = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + ancVisit.getCreatedDate(), + ancVisit.getBenId(),userId + ); + + + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(ancVisit.getLmpDate()); + record.setCreatedBy(ancVisit.getCreatedBy()); + record.setUpdatedDate(ancVisit.getLmpDate()); + record.setUpdatedBy(ancVisit.getCreatedBy()); + record.setStartDate(ancVisit.getLmpDate()); + record.setEndDate(ancVisit.getLmpDate()); + record.setBenId(ancVisit.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } + } + + private void recordFullAncIncentive(IncentiveActivity incentiveActivity, ANCVisit ancVisit) { + Integer userId = userRepo.getUserIdByName(ancVisit.getCreatedBy()); + if (userId == null) { + return; + } + IncentiveActivityRecord existRecord = recordRepo.findRecordByActivityIdCreatedDateBenId( + incentiveActivity.getId(), + ancVisit.getAncDate(), + ancVisit.getBenId(),userId + ); + + + if (existRecord != null) { + return; + } + + IncentiveActivityRecord record = new IncentiveActivityRecord(); + record.setActivityId(incentiveActivity.getId()); + record.setCreatedDate(ancVisit.getAncDate()); + record.setCreatedBy(ancVisit.getCreatedBy()); + record.setUpdatedDate(ancVisit.getAncDate()); + record.setUpdatedBy(ancVisit.getCreatedBy()); + record.setStartDate(ancVisit.getAncDate()); + record.setEndDate(ancVisit.getAncDate()); + record.setBenId(ancVisit.getBenId()); + record.setAshaId(userId); + record.setAmount(Long.valueOf(incentiveActivity.getRate())); + recordRepo.save(record); + } public void sendAncDueTomorrowNotifications(String ashaId) { try { diff --git a/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java b/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java index a5b6dd77..21d0da45 100644 --- a/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java +++ b/src/main/java/com/iemr/flw/service/impl/NotificationSchedulerService.java @@ -1,19 +1,13 @@ package com.iemr.flw.service.impl; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.service.EmployeeMasterInter; -import com.iemr.flw.service.impl.ChildCareServiceImpl; -import com.iemr.flw.service.impl.MaternalHealthServiceImpl; import com.iemr.flw.utils.CookieUtil; -import jakarta.annotation.PostConstruct; -import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; @Service public class NotificationSchedulerService { @@ -61,7 +55,7 @@ public void triggerAncRemindersForAllAsha() { @Scheduled(cron = "0 0 9 * * *") public void trigerTomorrowImmunizationReminders() { - for(M_User m_user: employeeMasterInter.getAllUsers()){ + for(User m_user: employeeMasterInter.getAllUsers()){ childCareService.getTomorrowImmunizationReminders(m_user.getUserID()); } diff --git a/src/main/java/com/iemr/flw/service/impl/SammelanServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SammelanServiceImpl.java index 53497981..e0460fe8 100644 --- a/src/main/java/com/iemr/flw/service/impl/SammelanServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/SammelanServiceImpl.java @@ -51,6 +51,8 @@ public class SammelanServiceImpl implements SammelanService { @Autowired private IncentivesRepo incentivesRepo; + @Autowired + private UpdateIncentivePendindDocService updateIncentivePendindDocService; @Override @@ -62,36 +64,36 @@ public SammelanResponseDTO submitSammelan(SammelanRequestDTO sammelanRequestDTO) // Save Sammelan record record = new SammelanRecord(); record.setAshaId(sammelanRequestDTO.getAshaId()); - logger.info("Meeting Date:"+sammelanRequestDTO.getDate()); + logger.info("Meeting Date:" + sammelanRequestDTO.getDate()); Timestamp timestamp = new Timestamp(sammelanRequestDTO.getDate()); record.setMeetingDate(timestamp); record.setPlace(sammelanRequestDTO.getPlace()); record.setParticipants(sammelanRequestDTO.getParticipants()); - if (sammelanRequestDTO.getSammelanImages() != null && sammelanRequestDTO.getSammelanImages().length > 0) { - List base64Images = Arrays.stream(sammelanRequestDTO.getSammelanImages()) - .filter(file -> !file.isEmpty()) - .map(file -> { - try { - return Base64.getEncoder().encodeToString(file.getBytes()); - } catch (IOException e) { - throw new RuntimeException("Error converting image to Base64", e); - } - }) - .collect(Collectors.toList()); - - String imagesJson = objectMapper.writeValueAsString(base64Images); - record .setAttachments(imagesJson); - } + if (sammelanRequestDTO.getSammelanImages() != null && sammelanRequestDTO.getSammelanImages().length > 0) { + List base64Images = Arrays.stream(sammelanRequestDTO.getSammelanImages()) + .filter(file -> !file.isEmpty()) + .map(file -> { + try { + return Base64.getEncoder().encodeToString(file.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Error converting image to Base64", e); + } + }) + .collect(Collectors.toList()); - if(record!=null){ - record = recordRepo.save(record); - checkIncentive(record); + String imagesJson = objectMapper.writeValueAsString(base64Images); + record.setAttachments(imagesJson); + } + + if (record != null) { + record = recordRepo.save(record); + checkIncentive(record); - } - // Prepare Response DTO + } + // Prepare Response DTO response.setId(record.getId()); response.setAshaId(record.getAshaId()); Timestamp ts = Timestamp.valueOf(record.getMeetingDate().toLocalDateTime()); @@ -103,7 +105,7 @@ record = recordRepo.save(record); } catch (Exception e) { - logger.info("SammelanRecord Exception: "+e.getMessage()); + logger.info("SammelanRecord Exception: " + e.getMessage()); } return response; @@ -112,31 +114,43 @@ record = recordRepo.save(record); private void checkIncentive(SammelanRecord record) { IncentiveActivity incentiveActivity = incentivesRepo.findIncentiveMasterByNameAndGroup("FP_SAAS_BAHU", GroupName.FAMILY_PLANNING.getDisplayName()); - logger.info("SammelanRecord: "+incentiveActivity.getRate()); - if(incentiveActivity!=null){ - addSammelanIncentive(incentiveActivity,record); + logger.info("SammelanRecord: " + incentiveActivity.getRate()); + if (incentiveActivity != null) { + addSammelanIncentive(incentiveActivity, record); } } private void addSammelanIncentive(IncentiveActivity incentiveActivity, SammelanRecord record) { - IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo .findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), record.getMeetingDate(), 0L,record.getAshaId()); + String userName = userRepo.getUserNamedByUserId(record.getAshaId()); + IncentiveActivityRecord incentiveActivityRecord = incentiveRecordRepo.findRecordByActivityIdCreatedDateBenId(incentiveActivity.getId(), record.getMeetingDate(), 0L, record.getAshaId()); try { if (incentiveActivityRecord == null) { incentiveActivityRecord = new IncentiveActivityRecord(); incentiveActivityRecord.setActivityId(incentiveActivity.getId()); incentiveActivityRecord.setCreatedDate(record.getMeetingDate()); - incentiveActivityRecord.setCreatedBy(userRepo.getUserNamedByUserId(record.getAshaId())); + incentiveActivityRecord.setCreatedBy(userName); incentiveActivityRecord.setStartDate(record.getMeetingDate()); incentiveActivityRecord.setEndDate(record.getMeetingDate()); incentiveActivityRecord.setUpdatedDate(record.getMeetingDate()); - incentiveActivityRecord.setUpdatedBy(userRepo.getUserNamedByUserId(record.getAshaId())); + incentiveActivityRecord.setUpdatedBy(userName); incentiveActivityRecord.setBenId(0L); incentiveActivityRecord.setAshaId(record.getAshaId()); incentiveActivityRecord.setAmount(Long.valueOf(incentiveActivity.getRate())); - incentiveRecordRepo.save(incentiveActivityRecord); + if (record.getAttachments() != null) { + incentiveActivityRecord.setIsEligible(true); + incentiveRecordRepo.save(incentiveActivityRecord); + + } else { + incentiveActivityRecord.setIsEligible(false); + IncentiveActivityRecord activityRecord = incentiveRecordRepo.save(incentiveActivityRecord); + if (activityRecord != null) { + updateIncentivePendindDocService.updatePendingActivity(record.getAshaId(), record.getId(), activityRecord.getActivityId(), incentiveActivity.getId()); + + } + } } - }catch (Exception e){ - logger.info("SammelanRecord save Record: ",e); + } catch (Exception e) { + logger.info("SammelanRecord save Record: ", e); } diff --git a/src/main/java/com/iemr/flw/service/impl/SmsSchedulerService.java b/src/main/java/com/iemr/flw/service/impl/SmsSchedulerService.java index 637d011a..90b57fdd 100644 --- a/src/main/java/com/iemr/flw/service/impl/SmsSchedulerService.java +++ b/src/main/java/com/iemr/flw/service/impl/SmsSchedulerService.java @@ -2,22 +2,16 @@ import com.iemr.flw.domain.identity.RMNCHBeneficiaryDetailsRmnch; import com.iemr.flw.domain.iemr.ANCVisit; -import com.iemr.flw.domain.iemr.M_User; -import com.iemr.flw.dto.iemr.ANCVisitDTO; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.ANCVisitRepo; import com.iemr.flw.service.EmployeeMasterInter; import com.iemr.flw.utils.CookieUtil; -import jakarta.annotation.PostConstruct; -import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; import java.math.BigInteger; import java.sql.Timestamp; @@ -25,7 +19,6 @@ import java.time.ZoneId; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; @Service public class SmsSchedulerService { @@ -94,7 +87,7 @@ public void sendAncReminders() { @Scheduled(cron = "0 0 9 * * *") public void trigerTomorrowImmunizationReminders() { - for (M_User m_user : employeeMasterInter.getAllUsers()) { + for (User m_user : employeeMasterInter.getAllUsers()) { childCareService.getTomorrowImmunizationReminders(m_user.getUserID()); } diff --git a/src/main/java/com/iemr/flw/service/impl/StopTBServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/StopTBServiceImpl.java new file mode 100644 index 00000000..10016c4a --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/StopTBServiceImpl.java @@ -0,0 +1,767 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.domain.identity.RMNCHMBeneficiarydetail; +import com.iemr.flw.domain.identity.RMNCHMBeneficiarymapping; +import com.iemr.flw.domain.iemr.BenAnthropometryDetail; +import com.iemr.flw.domain.iemr.BenChiefComplaint; +import com.iemr.flw.domain.iemr.BenFlowStatus; +import com.iemr.flw.domain.iemr.BenPhysicalVitalDetail; +import com.iemr.flw.domain.iemr.BenReferDetails; +import com.iemr.flw.domain.iemr.BenVisitDetail; +import com.iemr.flw.domain.iemr.PhyGeneralExamination; +import com.iemr.flw.domain.iemr.PrescribedDrugDetail; +import com.iemr.flw.domain.iemr.PrescriptionDetail; +import com.iemr.flw.domain.iemr.StopTBDiagnostics; +import com.iemr.flw.domain.iemr.StopTBGeneralExamination; +import com.iemr.flw.domain.iemr.StopTBGeneralOpd; +import com.iemr.flw.domain.iemr.TBScreening; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.BenAnthropometryRepo; +import com.iemr.flw.repo.iemr.BenChiefComplaintRepo; +import com.iemr.flw.repo.iemr.BenFlowStatusRepo; +import com.iemr.flw.repo.iemr.BenPhysicalVitalRepo; +import com.iemr.flw.repo.iemr.BenReferDetailsRepo; +import com.iemr.flw.repo.iemr.PhyGeneralExaminationRepo; +import com.iemr.flw.repo.iemr.PrescribedDrugDetailRepo; +import com.iemr.flw.repo.iemr.PrescriptionDetailRepo; +import com.iemr.flw.repo.iemr.StopTBDiagnosticsRepo; +import com.iemr.flw.repo.iemr.StopTBGeneralExaminationRepo; +import com.iemr.flw.repo.iemr.StopTBGeneralOpdRepo; +import com.iemr.flw.repo.iemr.TBScreeningRepo; +import com.iemr.flw.service.CampConfigService; +import com.iemr.flw.service.StopTBService; +import com.iemr.flw.service.TBStopVisitService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigInteger; +import java.sql.Timestamp; +import java.util.*; + +@Service +public class StopTBServiceImpl implements StopTBService { + + private final Logger logger = LoggerFactory.getLogger(StopTBServiceImpl.class); + + @Autowired + private CampConfigService campConfigService; + + @Autowired + private BenFlowStatusRepo benFlowStatusRepo; + + @Autowired + private BeneficiaryRepo beneficiaryRepo; + + @Autowired + private StopTBGeneralExaminationRepo generalExaminationRepo; + + @Autowired + private TBScreeningRepo tbScreeningRepo; + + @Autowired + private StopTBGeneralOpdRepo generalOpdRepo; + + @Autowired + private StopTBDiagnosticsRepo diagnosticsRepo; + + @Autowired + private TBStopVisitService tbStopVisitService; + + @Autowired + private BenAnthropometryRepo benAnthropometryRepo; + + @Autowired + private BenPhysicalVitalRepo benPhysicalVitalRepo; + + @Autowired + private PhyGeneralExaminationRepo phyGeneralExaminationRepo; + + @Autowired + private BenChiefComplaintRepo benChiefComplaintRepo; + + @Autowired + private PrescriptionDetailRepo prescriptionDetailRepo; + + @Autowired + private PrescribedDrugDetailRepo prescribedDrugDetailRepo; + + @Autowired + private BenReferDetailsRepo benReferDetailsRepo; + + // ── Nurse: General Examination ──────────────────────────────────────────── + + @Override + @Transactional + public List> saveGeneralExamination(List> dataList) throws Exception { + List> results = new ArrayList<>(); + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + for (Map data : dataList) { + Long beneficiaryRegID = getLong(data, "beneficiaryRegID"); + if (beneficiaryRegID == null) throw new Exception("beneficiaryRegID is required"); + + Integer providerServiceMapID = getInt(data, "providerServiceMapID"); + String createdBy = getString(data, "createdBy"); + BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, providerServiceMapID, + createdBy, vanID, parkingPlaceID); + + StopTBGeneralExamination exam = generalExaminationRepo.findByBeneficiaryRegIDAndVisitCode(beneficiaryRegID, visit.getVisitCode()); + if (exam == null) exam = new StopTBGeneralExamination(); + boolean isNew = exam.getId() == null; + + exam.setBeneficiaryRegID(beneficiaryRegID); + exam.setVisitCode(visit.getVisitCode()); + exam.setBenVisitID(visit.getBenVisitId()); + exam.setProviderServiceMapID(providerServiceMapID); + exam.setPulseRate(getInt(data, "pulseRate")); + exam.setSystolicBP(getInt(data, "systolicBP")); + exam.setDiastolicBP(getInt(data, "diastolicBP")); + exam.setRandomBloodSugar(getDouble(data, "randomBloodSugar")); + exam.setPallorId(getInt(data, "pallorId")); + exam.setPallor(getString(data, "pallor")); + exam.setIcterusId(getInt(data, "icterusId")); + exam.setIcterus(getString(data, "icterus")); + exam.setLymphadenopathyId(getInt(data, "lymphadenopathyId")); + exam.setLymphadenopathy(getString(data, "lymphadenopathy")); + exam.setOedemaId(getInt(data, "oedemaId")); + exam.setOedema(getString(data, "oedema")); + exam.setCyanosisId(getInt(data, "cyanosisId")); + exam.setCyanosis(getString(data, "cyanosis")); + exam.setClubbingId(getInt(data, "clubbingId")); + exam.setClubbing(getString(data, "clubbing")); + exam.setKeyPopulationRiskFactorIds(toJsonString(data.get("keyPopulationRiskFactorIds"))); + exam.setKeyPopulationRiskFactors(toJsonString(data.get("keyPopulationRiskFactors"))); + exam.setHivStatusId(getInt(data, "hivStatusId")); + exam.setHivStatus(getString(data, "hivStatus")); + exam.setCreatedBy(getString(data, "createdBy")); + exam.setModifiedBy(getString(data, "createdBy")); + exam.setDeleted(false); + exam.setReferralToHWCNeeded(getBool(data, "referralToHWCNeeded")); + if (exam.getVanID() == null && vanID != null) { exam.setVanID(vanID); exam.setParkingPlaceID(parkingPlaceID); } + exam.setProcessed("N"); + + generalExaminationRepo.save(exam); + if (isNew) { + generalExaminationRepo.updateVanSerialNo(exam.getId()); + dualWriteExamToStandardTables(exam, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); + } + + Map result = new HashMap<>(); + result.put("beneficiaryRegID", beneficiaryRegID); + result.put("referralToHWCNeeded", exam.getReferralToHWCNeeded()); + results.add(result); + } + return results; + } + + private boolean calculateReferralNeeded(StopTBGeneralExamination e) { + if (e.getPulseRate() != null && (e.getPulseRate() < 60 || e.getPulseRate() > 90)) return true; + if (e.getSystolicBP() != null && (e.getSystolicBP() >= 140 || e.getSystolicBP() < 90)) return true; + if (e.getDiastolicBP() != null && (e.getDiastolicBP() >= 90 || e.getDiastolicBP() < 60)) return true; + if (e.getRandomBloodSugar() != null && e.getRandomBloodSugar() >= 100) return true; + return false; + } + + @Override + public Map getAllGeneralExaminations(Integer providerServiceMapID, Integer villageID) throws Exception { + List list = (villageID != null) + ? generalExaminationRepo.findAllByProviderServiceMapIDAndVillageID(providerServiceMapID, villageID) + : generalExaminationRepo.findAllByProviderServiceMapID(providerServiceMapID); + List> items = new ArrayList<>(); + for (StopTBGeneralExamination e : list) items.add(examToMap(e)); + Map result = new HashMap<>(); + result.put("data", items); + result.put("count", items.size()); + return result; + } + + private Map examToMap(StopTBGeneralExamination e) { + Map m = new LinkedHashMap<>(); + m.put("id", e.getId()); + m.put("beneficiaryRegID", e.getBeneficiaryRegID()); + m.put("providerServiceMapID", e.getProviderServiceMapID()); + m.put("pulseRate", e.getPulseRate()); + m.put("systolicBP", e.getSystolicBP()); + m.put("diastolicBP", e.getDiastolicBP()); + m.put("randomBloodSugar", e.getRandomBloodSugar()); + m.put("pallorId", e.getPallorId()); + m.put("pallor", e.getPallor()); + m.put("icterusId", e.getIcterusId()); + m.put("icterus", e.getIcterus()); + m.put("lymphadenopathyId", e.getLymphadenopathyId()); + m.put("lymphadenopathy", e.getLymphadenopathy()); + m.put("oedemaId", e.getOedemaId()); + m.put("oedema", e.getOedema()); + m.put("cyanosisId", e.getCyanosisId()); + m.put("cyanosis", e.getCyanosis()); + m.put("clubbingId", e.getClubbingId()); + m.put("clubbing", e.getClubbing()); + m.put("keyPopulationRiskFactorIds", e.getKeyPopulationRiskFactorIds()); + m.put("keyPopulationRiskFactors", e.getKeyPopulationRiskFactors()); + m.put("hivStatusId", e.getHivStatusId()); + m.put("hivStatus", e.getHivStatus()); + m.put("referralToHWCNeeded", e.getReferralToHWCNeeded()); + m.put("createdBy", e.getCreatedBy()); + m.put("createdDate", e.getCreatedDate()); + m.put("updateDate", e.getLastModDate()); + m.put("updatedBy", e.getModifiedBy()); + return m; + } + + // ── Nurse: TB Screening ─────────────────────────────────────────────────── + + @Override + @Transactional + public List> saveNurseTBScreening(List> dataList) throws Exception { + List> results = new ArrayList<>(); + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + for (Map data : dataList) { + Long beneficiaryRegID = getLong(data, "beneficiaryRegID"); + if (beneficiaryRegID == null) throw new Exception("beneficiaryRegID is required"); + + Integer providerServiceMapID = getInt(data, "providerServiceMapID"); + String createdBy = getString(data, "createdBy"); + BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, providerServiceMapID, + createdBy, vanID, parkingPlaceID); + + TBScreening screening = tbScreeningRepo.findByBenRegIDAndVisitCode(beneficiaryRegID, visit.getVisitCode()); + if (screening == null) screening = new TBScreening(); + boolean isNew = screening.getId() == null; + + screening.setBenRegID(beneficiaryRegID); + screening.setVisitCode(visit.getVisitCode()); + screening.setProviderServiceMapID(providerServiceMapID); + screening.setCoughMoreThan2Weeks(getBool(data, "coughMoreThan2Weeks")); + screening.setBloodInSputum(getBool(data, "bloodInSputum")); + screening.setFeverMoreThan2Weeks(getBool(data, "feverMoreThan2Weeks")); + screening.setLossOfWeight(getBool(data, "lossOfWeight")); + screening.setNightSweats(getBool(data, "nightSweats")); + screening.setHistoryOfTb(getBool(data, "historyOfTb")); + screening.setTakingAntiTBDrugs(getBool(data, "takingAntiTBDrugs")); + screening.setFamilySufferingFromTB(getBool(data, "familySufferingFromTB")); + screening.setRiseOfFever(getBool(data, "riseOfFever")); + screening.setLossOfAppetite(getBool(data, "lossOfAppetite")); + screening.setContactWithTBPatient(getBool(data, "contactWithTBPatient")); + screening.setKeyPopulationRiskFactorIds(toJsonString(data.get("keyPopulationRiskFactorIds"))); + screening.setKeyPopulationRiskFactors(toJsonString(data.get("keyPopulationRiskFactors"))); + screening.setHivStatusId(getInt(data, "hivStatusId")); + screening.setHivStatus(getString(data, "hivStatus")); + String symptomaticInput = getString(data, "symptomatic"); + if ("Yes".equalsIgnoreCase(symptomaticInput)) { + screening.setSympotomatic(null); + screening.setAsymptomatic("Yes"); + } else if ("No".equalsIgnoreCase(symptomaticInput)) { + screening.setSympotomatic("Yes"); + screening.setAsymptomatic(null); + } else { + screening.setSympotomatic(null); + screening.setAsymptomatic(null); + } + screening.setReferredForDigitalChestXray(getBool(data, "referredForDigitalChestXray")); + screening.setReferredForSputumCollection(getBool(data, "referredForSputumCollection")); + screening.setSputumSampleSubmittedAt(getString(data, "sputumSampleSubmittedAt")); + screening.setRecommendedForTruenat(getBool(data, "recommendedForTruenat")); + screening.setRecommendedForLiquidCulture(getBool(data, "recommendedForLiquidCulture")); + screening.setTestDenialReasons(getString(data, "testDenialReasons")); + screening.setCreatedBy(getString(data, "createdBy")); + screening.setModifiedBy(getString(data, "createdBy")); + // PRD: date is user-provided, mandatory, not editable once submitted + if (screening.getVisitDate() == null) { + Timestamp provided = getTimestamp(data, "visitDate"); + screening.setVisitDate(provided != null ? provided : new Timestamp(System.currentTimeMillis())); + } + if (screening.getVanID() == null && vanID != null) { screening.setVanID(vanID); screening.setParkingPlaceID(parkingPlaceID); } + screening.setProcessed("N"); + + tbScreeningRepo.save(screening); + if (isNew) tbScreeningRepo.updateVanSerialNo(screening.getId()); + + Map result = new HashMap<>(); + result.put("beneficiaryRegID", beneficiaryRegID); + results.add(result); + } + return results; + } + + @Override + public Map getAllNurseTBScreenings(Integer providerServiceMapID, Integer villageID) throws Exception { + List list = (villageID != null) + ? tbScreeningRepo.findAllByProviderServiceMapIDAndVillageID(providerServiceMapID, villageID) + : tbScreeningRepo.findAllByProviderServiceMapID(providerServiceMapID); + List> items = new ArrayList<>(); + for (TBScreening s : list) items.add(screeningToMap(s)); + Map result = new HashMap<>(); + result.put("data", items); + result.put("count", items.size()); + return result; + } + + private Map screeningToMap(TBScreening s) { + Map m = new LinkedHashMap<>(); + m.put("id", s.getId()); + m.put("beneficiaryRegID", s.getBenRegID()); + m.put("providerServiceMapID", s.getProviderServiceMapID()); + m.put("coughMoreThan2Weeks", s.getCoughMoreThan2Weeks()); + m.put("bloodInSputum", s.getBloodInSputum()); + m.put("feverMoreThan2Weeks", s.getFeverMoreThan2Weeks()); + m.put("lossOfWeight", s.getLossOfWeight()); + m.put("nightSweats", s.getNightSweats()); + m.put("historyOfTb", s.getHistoryOfTb()); + m.put("takingAntiTBDrugs", s.getTakingAntiTBDrugs()); + m.put("familySufferingFromTB", s.getFamilySufferingFromTB()); + m.put("riseOfFever", s.getRiseOfFever()); + m.put("lossOfAppetite", s.getLossOfAppetite()); + m.put("contactWithTBPatient", s.getContactWithTBPatient()); + m.put("keyPopulationRiskFactorIds", s.getKeyPopulationRiskFactorIds()); + m.put("keyPopulationRiskFactors", s.getKeyPopulationRiskFactors()); + m.put("hivStatusId", s.getHivStatusId()); + m.put("hivStatus", s.getHivStatus()); + if ("Yes".equalsIgnoreCase(s.getAsymptomatic())) { + m.put("symptomatic", "Yes"); + } else if ("Yes".equalsIgnoreCase(s.getSympotomatic())) { + m.put("symptomatic", "No"); + } else { + m.put("symptomatic", null); + } + m.put("referredForDigitalChestXray", s.getReferredForDigitalChestXray()); + m.put("referredForSputumCollection", s.getReferredForSputumCollection()); + m.put("sputumSampleSubmittedAt", s.getSputumSampleSubmittedAt()); + m.put("recommendedForTruenat", s.getRecommendedForTruenat()); + m.put("recommendedForLiquidCulture", s.getRecommendedForLiquidCulture()); + m.put("testDenialReasons", s.getTestDenialReasons()); + m.put("createdBy", s.getCreatedBy()); + m.put("visitDate", s.getVisitDate()); + m.put("updateDate", s.getLastModDate()); + m.put("updatedBy", s.getModifiedBy()); + return m; + } + + // ── Nurse: General OPD ──────────────────────────────────────────────────── + + @Override + @Transactional + public List> saveGeneralOpd(List> dataList) throws Exception { + List> results = new ArrayList<>(); + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + for (Map data : dataList) { + Long beneficiaryRegID = getLong(data, "beneficiaryRegID"); + if (beneficiaryRegID == null) throw new Exception("beneficiaryRegID is required"); + + Integer providerServiceMapID = getInt(data, "providerServiceMapID"); + String createdBy = getString(data, "createdBy"); + BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, providerServiceMapID, + createdBy, vanID, parkingPlaceID); + + StopTBGeneralOpd opd = generalOpdRepo.findByBenRegIDAndVisitCode(beneficiaryRegID, visit.getVisitCode()); + if (opd == null) opd = new StopTBGeneralOpd(); + boolean isNew = opd.getId() == null; + + opd.setBenRegID(beneficiaryRegID); + opd.setVisitCode(visit.getVisitCode()); + opd.setBenVisitID(visit.getBenVisitId()); + opd.setProviderServiceMapID(providerServiceMapID); + opd.setChiefComplaint(toJsonString(data.get("chiefComplaint"))); + opd.setMedication(getString(data, "medication")); + opd.setDosage(getString(data, "dosage")); + opd.setFrequency(getString(data, "frequency")); + opd.setDuration(getString(data, "duration")); + opd.setNotes(getString(data, "notes")); + opd.setCreatedBy(getString(data, "createdBy")); + opd.setModifiedBy(getString(data, "createdBy")); + opd.setDeleted(false); + if (opd.getVanID() == null && vanID != null) { opd.setVanID(vanID); opd.setParkingPlaceID(parkingPlaceID); } + opd.setProcessed("N"); + + generalOpdRepo.save(opd); + if (isNew) { + generalOpdRepo.updateVanSerialNo(opd.getId()); + dualWriteOpdToStandardTables(opd, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); + } + + Map result = new HashMap<>(); + result.put("beneficiaryRegID", beneficiaryRegID); + results.add(result); + } + return results; + } + + @Override + public Map getAllGeneralOpd(Integer providerServiceMapID, Integer villageID) throws Exception { + List list = (villageID != null) + ? generalOpdRepo.findAllByProviderServiceMapIDAndVillageID(providerServiceMapID, villageID) + : generalOpdRepo.findAllByProviderServiceMapID(providerServiceMapID); + List> items = new ArrayList<>(); + for (StopTBGeneralOpd o : list) items.add(opdToMap(o)); + Map result = new HashMap<>(); + result.put("data", items); + result.put("count", items.size()); + return result; + } + + private Map opdToMap(StopTBGeneralOpd o) { + Map m = new LinkedHashMap<>(); + m.put("id", o.getId()); + m.put("beneficiaryRegID", o.getBenRegID()); + m.put("providerServiceMapID", o.getProviderServiceMapID()); + m.put("chiefComplaint", o.getChiefComplaint()); + m.put("medication", o.getMedication()); + m.put("dosage", o.getDosage()); + m.put("frequency", o.getFrequency()); + m.put("duration", o.getDuration()); + m.put("notes", o.getNotes()); + m.put("createdBy", o.getCreatedBy()); + m.put("createdDate", o.getCreatedDate()); + m.put("updateDate", o.getLastModDate()); + m.put("updatedBy", o.getModifiedBy()); + return m; + } + + // ── Nurse: Diagnostics ──────────────────────────────────────────────────── + + @Override + @Transactional + public List> saveDiagnostics(List> dataList) throws Exception { + List> results = new ArrayList<>(); + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + for (Map data : dataList) { + Long benRegID = getLong(data, "benRegID"); + if (benRegID == null) throw new Exception("benRegID is required"); + + StopTBDiagnostics diag = diagnosticsRepo.findByBenRegID(benRegID); + if (diag == null) diag = new StopTBDiagnostics(); + boolean isNew = diag.getId() == null; + + diag.setBenRegID(benRegID); + diag.setProviderServiceMapID(getInt(data, "providerServiceMapID")); + + // PRD: date is user-provided, not editable once submitted + if (diag.getVisitDate() == null) { + Timestamp provided = getTimestamp(data, "visitDate"); + diag.setVisitDate(provided != null ? provided : new Timestamp(System.currentTimeMillis())); + } + + diag.setNikshayId(getString(data, "nikshayId")); + + diag.setIsReferredForDigitalChestXray(getBool(data, "isReferredForDigitalChestXray")); + diag.setReasonForDenialChestXray(getString(data, "reasonForDenialChestXray")); + diag.setReasonForDenialChestXrayOther(getString(data, "reasonForDenialChestXrayOther")); + diag.setIsDigitalChestXrayConducted(getBool(data, "isDigitalChestXrayConducted")); + diag.setReasonNotConductedChestXray(getString(data, "reasonNotConductedChestXray")); + diag.setReasonNotConductedChestXrayOther(getString(data, "reasonNotConductedChestXrayOther")); + diag.setDigitalChestXrayResult(getString(data, "digitalChestXrayResult")); + + diag.setIsReferredForSputumCollection(getBool(data, "isReferredForSputumCollection")); + diag.setReasonForDenialSputum(getString(data, "reasonForDenialSputum")); + diag.setReasonForDenialSputumOther(getString(data, "reasonForDenialSputumOther")); + diag.setSputumSubmittedAt(getString(data, "sputumSubmittedAt")); + + diag.setIsTruenatConducted(getBool(data, "isTruenatConducted")); + diag.setReasonNotConductedNaat(getString(data, "reasonNotConductedNaat")); + diag.setReasonNotConductedNaatOther(getString(data, "reasonNotConductedNaatOther")); + diag.setTruenatResult(getString(data, "truenatResult")); + + diag.setRecommendedForLiquidCulture(getBool(data, "recommendedForLiquidCulture")); + // PRD: liquid culture result can be updated after submission (results come after 40-45 days) + if (data.containsKey("liquidCultureResult")) { + diag.setLiquidCultureResult(getString(data, "liquidCultureResult")); + } + diag.setCreatedBy(getString(data, "createdBy")); + diag.setModifiedBy(getString(data, "createdBy")); + diag.setDeleted(false); + if (diag.getVanID() == null && vanID != null) { diag.setVanID(vanID); diag.setParkingPlaceID(parkingPlaceID); } + diag.setProcessed("N"); + + diagnosticsRepo.save(diag); + if (isNew) diagnosticsRepo.updateVanSerialNo(diag.getId()); + + Map result = new HashMap<>(); + result.put("benRegID", benRegID); + results.add(result); + } + return results; + } + + @Override + public Map getAllDiagnostics(Integer providerServiceMapID, Integer villageID) throws Exception { + List list = (villageID != null) + ? diagnosticsRepo.findAllByProviderServiceMapIDAndVillageID(providerServiceMapID, villageID) + : diagnosticsRepo.findAllByProviderServiceMapID(providerServiceMapID); + List> items = new ArrayList<>(); + for (StopTBDiagnostics d : list) items.add(diagnosticsToMap(d)); + Map result = new HashMap<>(); + result.put("data", items); + result.put("count", items.size()); + return result; + } + + private Map diagnosticsToMap(StopTBDiagnostics d) { + Map m = new LinkedHashMap<>(); + m.put("id", d.getId()); + m.put("benRegID", d.getBenRegID()); + m.put("providerServiceMapID", d.getProviderServiceMapID()); + m.put("visitDate", d.getVisitDate()); + m.put("nikshayId", d.getNikshayId()); + m.put("isReferredForDigitalChestXray", d.getIsReferredForDigitalChestXray()); + m.put("reasonForDenialChestXray", d.getReasonForDenialChestXray()); + m.put("reasonForDenialChestXrayOther", d.getReasonForDenialChestXrayOther()); + m.put("isDigitalChestXrayConducted", d.getIsDigitalChestXrayConducted()); + m.put("reasonNotConductedChestXray", d.getReasonNotConductedChestXray()); + m.put("reasonNotConductedChestXrayOther", d.getReasonNotConductedChestXrayOther()); + m.put("digitalChestXrayResult", d.getDigitalChestXrayResult()); + m.put("isReferredForSputumCollection", d.getIsReferredForSputumCollection()); + m.put("reasonForDenialSputum", d.getReasonForDenialSputum()); + m.put("reasonForDenialSputumOther", d.getReasonForDenialSputumOther()); + m.put("sputumSubmittedAt", d.getSputumSubmittedAt()); + m.put("isTruenatConducted", d.getIsTruenatConducted()); + m.put("reasonNotConductedNaat", d.getReasonNotConductedNaat()); + m.put("reasonNotConductedNaatOther", d.getReasonNotConductedNaatOther()); + m.put("truenatResult", d.getTruenatResult()); + m.put("recommendedForLiquidCulture", d.getRecommendedForLiquidCulture()); + m.put("liquidCultureResult", d.getLiquidCultureResult()); + m.put("createdBy", d.getCreatedBy()); + m.put("createdDate", d.getCreatedDate()); + m.put("updateDate", d.getLastModDate()); + m.put("updatedBy", d.getModifiedBy()); + return m; + } + + // ── Standard table dual-writes ──────────────────────────────────────────── + + private Map getRegistrationExtras(Long beneficiaryRegID) { + try { + RMNCHMBeneficiarymapping mapping = beneficiaryRepo.getById(BigInteger.valueOf(beneficiaryRegID)); + RMNCHMBeneficiarydetail detail = (mapping != null && mapping.getBenDetailsId() != null) + ? beneficiaryRepo.getDetailsById(mapping.getBenDetailsId()) + : null; + if (detail != null && detail.getOtherFields() != null && !detail.getOtherFields().isEmpty()) { + return new ObjectMapper().readValue(detail.getOtherFields(), Map.class); + } + } catch (Exception e) { + logger.warn("Cannot read otherFields for benRegID: " + beneficiaryRegID); + } + return Collections.emptyMap(); + } + + private void dualWriteExamToStandardTables(StopTBGeneralExamination exam, Long beneficiaryRegID, + BenVisitDetail visit, String createdBy, Integer vanID, Integer parkingPlaceID) { + try { + Map extras = getRegistrationExtras(beneficiaryRegID); + writeAnthropometry(extras, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); + writeVitals(exam, extras, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); + writePhyGeneralExam(exam, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); + if (Boolean.TRUE.equals(exam.getReferralToHWCNeeded())) { + writeReferral(beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); + } + } catch (Exception e) { + logger.error("Dual-write exam to standard tables failed for benRegID: " + beneficiaryRegID, e); + } + } + + private void writeAnthropometry(Map extras, Long beneficiaryRegID, + BenVisitDetail visit, String createdBy, Integer vanID, Integer parkingPlaceID) { + try { + BenAnthropometryDetail a = new BenAnthropometryDetail(); + a.setBeneficiaryRegID(beneficiaryRegID); + a.setBenVisitID(visit.getBenVisitId()); + a.setVisitCode(visit.getVisitCode()); + a.setProviderServiceMapID(visit.getProviderServiceMapID()); + a.setCreatedBy(createdBy); + a.setVanID(vanID); + a.setParkingPlaceID(parkingPlaceID); + Object h = extras.get("height"); + Object w = extras.get("weight"); + Object b = extras.get("bmi"); + if (h instanceof Number) a.setHeightCm(((Number) h).doubleValue()); + if (w instanceof Number) a.setWeightKg(((Number) w).doubleValue()); + if (b instanceof Number) a.setBmi(((Number) b).doubleValue()); + benAnthropometryRepo.save(a); + } catch (Exception e) { + logger.error("writeAnthropometry failed for benRegID: " + beneficiaryRegID, e); + } + } + + private void writeVitals(StopTBGeneralExamination exam, Map extras, + Long beneficiaryRegID, BenVisitDetail visit, String createdBy, Integer vanID, Integer parkingPlaceID) { + try { + BenPhysicalVitalDetail v = new BenPhysicalVitalDetail(); + v.setBeneficiaryRegID(beneficiaryRegID); + v.setBenVisitID(visit.getBenVisitId()); + v.setVisitCode(visit.getVisitCode()); + v.setProviderServiceMapID(visit.getProviderServiceMapID()); + v.setCreatedBy(createdBy); + v.setVanID(vanID); + v.setParkingPlaceID(parkingPlaceID); + Object t = extras.get("temperatureValue"); + if (t instanceof Number) v.setTemperature(((Number) t).doubleValue()); + if (exam.getPulseRate() != null) v.setPulseRate(exam.getPulseRate().shortValue()); + if (exam.getSystolicBP() != null) v.setSystolicBP(exam.getSystolicBP().shortValue()); + if (exam.getDiastolicBP() != null) v.setDiastolicBP(exam.getDiastolicBP().shortValue()); + if (exam.getRandomBloodSugar() != null) v.setBloodGlucoseRandom(exam.getRandomBloodSugar().shortValue()); + benPhysicalVitalRepo.save(v); + } catch (Exception e) { + logger.error("writeVitals failed for benRegID: " + beneficiaryRegID, e); + } + } + + private void writePhyGeneralExam(StopTBGeneralExamination exam, Long beneficiaryRegID, + BenVisitDetail visit, String createdBy, Integer vanID, Integer parkingPlaceID) { + try { + PhyGeneralExamination g = new PhyGeneralExamination(); + g.setBeneficiaryRegID(beneficiaryRegID); + g.setBenVisitID(visit.getBenVisitId()); + g.setVisitCode(visit.getVisitCode()); + g.setProviderServiceMapID(visit.getProviderServiceMapID()); + g.setCreatedBy(createdBy); + g.setVanID(vanID); + g.setParkingPlaceID(parkingPlaceID); + g.setPallor(exam.getPallor()); + g.setJaundice(exam.getIcterus()); + g.setCyanosis(exam.getCyanosis()); + g.setClubbing(exam.getClubbing()); + g.setLymphadenopathy(exam.getLymphadenopathy()); + g.setEdema(exam.getOedema()); + phyGeneralExaminationRepo.save(g); + } catch (Exception e) { + logger.error("writePhyGeneralExam failed for benRegID: " + beneficiaryRegID, e); + } + } + + private void writeReferral(Long beneficiaryRegID, BenVisitDetail visit, + String createdBy, Integer vanID, Integer parkingPlaceID) { + try { + BenReferDetails r = new BenReferDetails(); + r.setBeneficiaryRegID(beneficiaryRegID); + r.setBenVisitID(visit.getBenVisitId()); + r.setVisitCode(visit.getVisitCode()); + r.setProviderServiceMapID(visit.getProviderServiceMapID()); + r.setCreatedBy(createdBy); + r.setVanID(vanID); + r.setParkingPlaceID(parkingPlaceID); + r.setReferredToInstituteName("HWC"); + r.setReferralReason("Stop TB Referral"); + benReferDetailsRepo.save(r); + } catch (Exception e) { + logger.error("writeReferral failed for benRegID: " + beneficiaryRegID, e); + } + } + + private void dualWriteOpdToStandardTables(StopTBGeneralOpd opd, Long beneficiaryRegID, + BenVisitDetail visit, String createdBy, Integer vanID, Integer parkingPlaceID) { + try { + writeChiefComplaint(opd.getChiefComplaint(), beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); + writePrescription(opd, beneficiaryRegID, visit, createdBy, vanID, parkingPlaceID); + } catch (Exception e) { + logger.error("Dual-write OPD to standard tables failed for benRegID: " + beneficiaryRegID, e); + } + } + + private void writeChiefComplaint(String complaint, Long beneficiaryRegID, BenVisitDetail visit, + String createdBy, Integer vanID, Integer parkingPlaceID) { + if (complaint == null || complaint.isBlank()) return; + try { + BenChiefComplaint c = new BenChiefComplaint(); + c.setBeneficiaryRegID(beneficiaryRegID); + c.setBenVisitID(visit.getBenVisitId()); + c.setVisitCode(visit.getVisitCode()); + c.setProviderServiceMapID(visit.getProviderServiceMapID()); + c.setCreatedBy(createdBy); + c.setVanID(vanID); + c.setParkingPlaceID(parkingPlaceID); + c.setChiefComplaint(complaint); + benChiefComplaintRepo.save(c); + } catch (Exception e) { + logger.error("writeChiefComplaint failed for benRegID: " + beneficiaryRegID, e); + } + } + + private void writePrescription(StopTBGeneralOpd opd, Long beneficiaryRegID, BenVisitDetail visit, + String createdBy, Integer vanID, Integer parkingPlaceID) { + if (opd.getMedication() == null || opd.getMedication().isBlank()) return; + try { + PrescriptionDetail p = new PrescriptionDetail(); + p.setBeneficiaryRegID(beneficiaryRegID); + p.setBenVisitID(visit.getBenVisitId()); + p.setVisitCode(visit.getVisitCode()); + p.setProviderServiceMapID(visit.getProviderServiceMapID()); + p.setCreatedBy(createdBy); + p.setVanID(vanID); + p.setParkingPlaceID(parkingPlaceID); + p.setInstruction(opd.getNotes()); + p = prescriptionDetailRepo.save(p); + + PrescribedDrugDetail d = new PrescribedDrugDetail(); + d.setBeneficiaryRegID(beneficiaryRegID); + d.setBenVisitID(visit.getBenVisitId()); + d.setVisitCode(visit.getVisitCode()); + d.setProviderServiceMapID(visit.getProviderServiceMapID()); + d.setCreatedBy(createdBy); + d.setVanID(vanID); + d.setParkingPlaceID(parkingPlaceID); + d.setPrescriptionID(p.getPrescriptionID()); + d.setDrugName(opd.getMedication()); + d.setDose(opd.getDosage()); + d.setFrequency(opd.getFrequency()); + d.setDuration(opd.getDuration()); + prescribedDrugDetailRepo.save(d); + } catch (Exception e) { + logger.error("writePrescription failed for benRegID: " + beneficiaryRegID, e); + } + } + + // ── Helpers ─────────────────────────────────────────────────────────────── + + private String toJsonString(Object value) { + if (value == null) return null; + if (value instanceof String) return (String) value; + return new com.google.gson.Gson().toJson(value); + } + + private String getString(Map m, String key) { + Object v = m.get(key); + return v != null ? v.toString() : null; + } + + private Long getLong(Map m, String key) { + Object v = m.get(key); + if (v == null) return null; + if (v instanceof Number) return ((Number) v).longValue(); + try { return Long.parseLong(v.toString()); } catch (Exception e) { return null; } + } + + private Integer getInt(Map m, String key) { + Object v = m.get(key); + if (v == null) return null; + if (v instanceof Number) return ((Number) v).intValue(); + try { return Integer.parseInt(v.toString()); } catch (Exception e) { return null; } + } + + private Double getDouble(Map m, String key) { + Object v = m.get(key); + if (v == null) return null; + if (v instanceof Number) return ((Number) v).doubleValue(); + try { return Double.parseDouble(v.toString()); } catch (Exception e) { return null; } + } + + private Boolean getBool(Map m, String key) { + Object v = m.get(key); + if (v == null) return null; + if (v instanceof Boolean) return (Boolean) v; + return Boolean.parseBoolean(v.toString()); + } + + private Timestamp getTimestamp(Map m, String key) { + Object v = m.get(key); + if (v == null) return null; + if (v instanceof Number) return new Timestamp(((Number) v).longValue()); + try { return new Timestamp(Long.parseLong(v.toString())); } catch (Exception e) { return null; } + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java new file mode 100644 index 00000000..771810e2 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/SupervisorDashboardServiceImpl.java @@ -0,0 +1,437 @@ +package com.iemr.flw.service.impl; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.dto.iemr.UserServiceRoleDTO; +import com.iemr.flw.masterEnum.IncentiveApprovalStatus; +import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.UserService; +import com.iemr.flw.utils.JwtUtil; +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.iemr.flw.service.SupervisorDashboardService; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class SupervisorDashboardServiceImpl implements SupervisorDashboardService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired + private SupervisorDashboardRepo dashboardRepo; + + @Autowired + private AshaSupervisorLoginRepo ashaSupervisorLoginRepo; + + @Autowired + private FacilityLoginRepo facilityLoginRepo; + + @Autowired + private IncentiveRecordRepo incentiveRecordRepo; + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserService userService; + + @Override + public String getSupervisorDashboard(Integer supervisorUserID, Integer month, Integer year) { + JSONObject result = new JSONObject(); + + // 1. Supervisor user details + List supervisorRows = dashboardRepo.getSupervisorUserDetails(supervisorUserID); + if (supervisorRows != null && !supervisorRows.isEmpty()) { + Object[] sRow = supervisorRows.get(0); + JSONObject supervisor = new JSONObject(); + supervisor.put("userId", sRow[0]); + supervisor.put("fullName", fullName(sRow[1], sRow[2])); + supervisor.put("employeeId", str(sRow[3]).isEmpty() ? JSONObject.NULL : str(sRow[3])); + supervisor.put("mobile", str(sRow[4]).isEmpty() ? JSONObject.NULL : str(sRow[4])); + supervisor.put("gender", str(sRow[5]).isEmpty() ? JSONObject.NULL : str(sRow[5])); + result.put("supervisor", supervisor); + } + + // 2. Get all ASHAs with facility info + List ashaRows = dashboardRepo.getAshasWithFacilityInfo(supervisorUserID); + if (ashaRows == null || ashaRows.isEmpty()) { + result.put("totalAshaCount", 0); + result.put("incentiveSummary", buildEmptyIncentiveSummary()); + result.put("facilities", new JSONArray()); + return result.toString(); + } + + // Collect distinct facility IDs and ASHA IDs + Set facilityIDSet = new HashSet<>(); + Set ashaIDSet = new HashSet<>(); + for (Object[] row : ashaRows) { + if (row[3] != null) + facilityIDSet.add((Integer) row[3]); + if (row[0] != null) + ashaIDSet.add((Integer) row[0]); + } + List facilityIDs = new ArrayList<>(facilityIDSet); + List ashaIDs = new ArrayList<>(ashaIDSet); + + result.put("totalAshaCount", ashaIDs.size()); + + // 3. Location from first facility + List facilityRows = dashboardRepo.getFacilityDetails(facilityIDs); + if (facilityRows != null && !facilityRows.isEmpty()) { + Object[] fRow = facilityRows.get(0); + JSONObject location = new JSONObject(); + location.put("state", str(fRow[2])); + location.put("district", str(fRow[3])); + location.put("blockOrUlb", str(fRow[4])); + location.put("locationType", str(fRow[5])); + result.put("location", location); + } + + // 4. Build village map (facilityID -> villages) + Map> villageMap = new HashMap<>(); + List villageRows = dashboardRepo.getVillagesForFacilities(facilityIDs); + if (villageRows != null) { + for (Object[] vRow : villageRows) { + Integer facID = (Integer) vRow[0]; + JSONObject village = new JSONObject(); + village.put("villageId", vRow[1]); + village.put("villageName", str(vRow[2])); + villageMap.computeIfAbsent(facID, k -> new ArrayList<>()).add(village); + } + } + + // 5. Get incentive status per ASHA (verified, rejected, pending, totalAmount) + long overallVerified = 0, overallRejected = 0, overallPending = 0; + long overallUnclaimed = 0; + + try { + logger.info("Month: {}", month); + logger.info("Year: {}", year); + + LocalDate startLocalDate = LocalDate.of(year, month, 1); + LocalDate endLocalDate = startLocalDate.plusMonths(1); + + logger.info("startLocalDate {}", startLocalDate); + logger.info("endLocalDate {}", endLocalDate); + + Timestamp startDate = Timestamp.valueOf(startLocalDate.atStartOfDay()); + Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + logger.info("Asha ID" + ashaIDs); + + List statusRows = dashboardRepo.getIncentiveStatusByAshaIds(ashaIDs, startDate, endDate); + if (statusRows != null) { + for (Object[] sRow : statusRows) { + long verified = ((Number) sRow[2]).longValue(); + long rejected = ((Number) sRow[3]).longValue(); + long pending = ((Number) sRow[4]).longValue(); + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + } + } + List unclaimedRows = dashboardRepo.getUnclaimedCountByAshaIds(ashaIDs, startDate, endDate); + if (unclaimedRows != null) { + for (Object[] uRow : unclaimedRows) { + long count = ((Number) uRow[1]).longValue(); + if (count > 0) overallUnclaimed += 1; + } + } + } catch (Exception e) { + logger.error("Error fetching incentive status: " + e.getMessage(), e); + } + + + + // Overall incentive summary across all ASHAs + JSONObject overallSummary = new JSONObject(); + overallSummary.put("verified", overallVerified); + overallSummary.put("rejected", overallRejected); + overallSummary.put("pending", overallPending); + overallSummary.put("overDue", 0); + overallSummary.put("unclaimed", overallUnclaimed); + result.put("incentiveSummary", overallSummary); + + // 7. Build facilities array with nested ASHAs + Map> ashasByFacility = new HashMap<>(); + for (Object[] row : ashaRows) { + Integer facID = (Integer) row[3]; + ashasByFacility.computeIfAbsent(facID, k -> new ArrayList<>()).add(row); + } + + Map facilityDetailsMap = new HashMap<>(); + if (facilityRows != null) { + for (Object[] fRow : facilityRows) { + facilityDetailsMap.put((Integer) fRow[0], fRow); + } + } + + JSONArray facilitiesArray = new JSONArray(); + for (Integer facID : facilityIDs) { + JSONObject facility = new JSONObject(); + facility.put("facilityId", facID); + + Object[] fDetails = facilityDetailsMap.get(facID); + if (fDetails != null) { + facility.put("facilityName", str(fDetails[1])); + facility.put("facilityType", str(fDetails[6])); + } + + + // ASHAs at this facility + JSONArray ashasArray = new JSONArray(); + List facAshaRows = ashasByFacility.get(facID); + if (facAshaRows != null) { + for (Object[] row : facAshaRows) { + Integer ashaId = (Integer) row[0]; + JSONObject asha = new JSONObject(); + asha.put("userId", ashaId); + asha.put("fullName", fullName(row[1], row[2])); + asha.put("employeeId", str(row[6]).isEmpty() ? JSONObject.NULL : str(row[6])); + asha.put("mobile", str(row[7]).isEmpty() ? JSONObject.NULL : str(row[7])); + asha.put("gender", str(row[8]).isEmpty() ? JSONObject.NULL : str(row[8])); + + ashasArray.put(asha); + } + } + + facility.put("ashaCount", ashasArray.length()); + facilitiesArray.put(facility); + } + + result.put("facilities", facilitiesArray); + return result.toString(); + } + + @Override + public Map getAshasAtFacility(Integer supervisorId, Integer facilityId, + Integer month, Integer year, Integer approvalStatusID) { + List rows; + logger.info("approvalStatusID:" + approvalStatusID); + + List superVisorRow = ashaSupervisorLoginRepo.getAllMappedAshas(supervisorId); + + List> ashaList = new ArrayList<>(); + + LocalDate startLocalDate = LocalDate.of(year, month, 1); + LocalDate endLocalDate = startLocalDate.plusMonths(1); + + Timestamp startDate = Timestamp.valueOf(startLocalDate.atStartOfDay()); + Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + + if (facilityId.equals(0)) { + rows = ashaSupervisorLoginRepo.getAshasAtFacility( + supervisorId, approvalStatusID, startDate, endDate); + } else { + rows = ashaSupervisorLoginRepo.getAshasAtFacility( + supervisorId, facilityId, approvalStatusID, startDate, endDate); + } + + long overallVerified = 0, overallRejected = 0, overallPending = 0; + + String facilityName = ""; + String facilityType = ""; + Integer facilityID = null; + + for (Object[] row : superVisorRow) { + facilityID = (Integer) row[3]; + facilityName = str(row[4]); + facilityType = str(row[5]); + } + + for (Object[] row : rows) { + + Map asha = new HashMap<>(); + + Integer ashaId = ((Number) row[0]).intValue(); + + List countList = incentiveRecordRepo.getStatusCountByAshaId(ashaId, startDate, endDate); + Long totalAmount = null; + if (userService.getUserDetail(ashaId) != null) { + Integer stateCode = userService.getUserDetail(ashaId).getStateId(); + totalAmount = incentiveRecordRepo.getTotalAmountByAsha( + ashaId, startDate, endDate, approvalStatusID, stateCode); + + } + + + List incentiveActivityRecord = + incentiveRecordRepo.getRecordsByAsha(ashaId, startDate, endDate) + .stream() + .filter(r -> approvalStatusID == 0 || + approvalStatusID.equals(r.getApprovalStatus())) + .collect(Collectors.toList()); + List> activityList = new ArrayList<>(); + for (IncentiveActivityRecord record : incentiveActivityRecord) { + Map activity = new HashMap<>(); + activity.put("reason", record.getReason()); + activity.put("otherReason", record.getOtherReason()); + activity.put("approvalDate", record.getApprovalDate()); + activity.put("approvalStatus", record.getApprovalStatus()); + if(record.getVerifiedByUserId()!=null){ + activity.put("verifiedByUserName", userService.getUserDetail(record.getVerifiedByUserId()).getName()); + + } + activity.put("verifiedByUserId", record.getVerifiedByUserId()); + activity.put("isClaimed", record.getIsClaimed()); + activity.put("claimedDate", record.getCalimedDate()); + + UserServiceRoleDTO roles = userService.getUserDetail(record.getVerifiedByUserId()); + activity.put("role", (roles != null ) ? roles.getRoleName() : null); + + activityList.add(activity); + } + + asha.put("facilityId", facilityID); + asha.put("facilityName", facilityName); + asha.put("facilityType", facilityType); + asha.put("userId", row[0]); + asha.put("fullName", fullName(row[1], row[2])); + asha.put("employeeId", str(row[3]).isEmpty() ? null : str(row[3])); + asha.put("mobile", str(row[4]).isEmpty() ? null : str(row[4])); + asha.put("gender", str(row[5]).isEmpty() ? null : str(row[5])); + asha.put("totalAmount", totalAmount); + asha.put("activities", activityList); + + long pending = 0, verified = 0, rejected = 0; + if (countList != null && !countList.isEmpty()) { + Object[] counts = countList.get(0); + verified = counts[0] != null ? ((Number) counts[0]).longValue() : 0; + pending = counts[1] != null ? ((Number) counts[1]).longValue() : 0; + rejected = counts[2] != null ? ((Number) counts[2]).longValue() : 0; + } + + if (verified > 0) overallVerified += 1; + if (rejected > 0) overallRejected += 1; + if (pending > 0) overallPending += 1; + + asha.put("pending", pending); + asha.put("verified", verified); + asha.put("rejected", rejected); + + int approvalStatus = 0; + + if (!activityList.isEmpty()) { + approvalStatus = (int) activityList.get(0).get("approvalStatus"); + } + if (pending == 0 && verified == 0 && rejected == 0) continue; + if (approvalStatusID.equals(0)) { + asha.put("approvalStatus", approvalStatus); + + } else { + asha.put("approvalStatus", approvalStatusID); + + } + + ashaList.add(asha); + } + + Map response = new HashMap<>(); + + Map approvalStatus = new HashMap<>(); + approvalStatus.put("verified", overallVerified); + approvalStatus.put("pending", overallPending); + approvalStatus.put("rejected", overallRejected); + + response.put("approvalStatus", approvalStatus); + response.put("data", ashaList); + response.put("statusCode", 200); + + return response; + } + + private String getGroupNameByState(Integer stateCode) { + switch (stateCode) { + case 5: + return "! ACTIVITY"; + default: + return "ACTIVITY"; + } + } + + @Transactional + public int updateApprovalStatus(Integer ashaId, + Integer month, + Integer year, + Integer approvalStatus, + String incentiveIds, + String reason, + String otherReason, + String token) { + try { + Timestamp approvalDate = Timestamp.valueOf(LocalDateTime.now()); + + LocalDate startLocalDate = LocalDate.of(year, month, 1); + LocalDate endLocalDate = startLocalDate.plusMonths(1); + + Timestamp startDate = Timestamp.valueOf(startLocalDate.atStartOfDay()); + Timestamp endDate = Timestamp.valueOf(endLocalDate.atStartOfDay()); + + Integer ashaSupervisorUserId = jwtUtil.extractUserId(token); + logger.info("Asha Supervisor User Id : {}", ashaSupervisorUserId); + String ashaSupervisorUsername = userService.getUserDetail(ashaSupervisorUserId).getUserName(); + + if (approvalStatus.equals(IncentiveApprovalStatus.REJECTED.getCode())) { + int totalUpdated = 0; + + totalUpdated += incentiveRecordRepo.updateApprovalStatusById( + approvalStatus, + ashaSupervisorUserId, + ashaSupervisorUsername, + reason, + approvalDate, + otherReason + ); + + return totalUpdated; + } + + return incentiveRecordRepo.updateApprovalStatusByAshaAndDateRange( + ashaId, + approvalStatus, + startDate, + endDate, + approvalDate, + ashaSupervisorUserId, + ashaSupervisorUsername + ); + + } catch (Exception e) { + logger.error("Update claim :" + e.getMessage()); + e.printStackTrace(); + return 0; + } + } + + private JSONObject buildEmptyIncentiveSummary() { + JSONObject summary = new JSONObject(); + summary.put("verified", 0); + summary.put("rejected", 0); + summary.put("pending", 0); + summary.put("totalAmount", 0); + return summary; + } + + private String str(Object val) { + return val != null ? val.toString() : ""; + } + + private String fullName(Object first, Object last) { + return (str(first) + " " + str(last)).trim(); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java new file mode 100644 index 00000000..f9240c5c --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/TBConfirmedCaseServiceImpl.java @@ -0,0 +1,250 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.iemr.flw.domain.iemr.DynamicForm; +import com.iemr.flw.domain.iemr.TBConfirmedCaseDTO; +import com.iemr.flw.domain.iemr.TBConfirmedCase; +import com.iemr.flw.domain.iemr.BenVisitDetail; +import com.iemr.flw.dto.iemr.TBConfirmedCasesResponseDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; +import com.iemr.flw.repo.iemr.DynamicFormRepo; +import com.iemr.flw.repo.iemr.FormResponseRepo; +import com.iemr.flw.repo.iemr.TBConfirmedTreatmentRepository; +import com.iemr.flw.seeder.TbCounsellingFormSeeder; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.CampConfigService; +import com.iemr.flw.service.TBConfirmedCaseService; +import com.iemr.flw.service.TBStopVisitService; +import com.iemr.flw.utils.JwtUtil; +import com.iemr.flw.utils.LocalDateAdapter; +import com.iemr.flw.utils.response.OutputResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +public class TBConfirmedCaseServiceImpl implements TBConfirmedCaseService { + + private static final Logger logger = LoggerFactory.getLogger(TBConfirmedCaseServiceImpl.class); + + private final TBConfirmedTreatmentRepository repository; + private final FormResponseRepo formResponseRepo; + private final DynamicFormRepo dynamicFormRepo; + + @Autowired + private IncentiveLogicService incentiveLogicService; + + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private CampConfigService campConfigService; + + @Autowired + private TBStopVisitService tbStopVisitService; + + @Autowired + private BeneficiaryRepo beneficiaryRepo; + + public TBConfirmedCaseServiceImpl(TBConfirmedTreatmentRepository repository, + FormResponseRepo formResponseRepo, + DynamicFormRepo dynamicFormRepo) { + this.repository = repository; + this.formResponseRepo = formResponseRepo; + this.dynamicFormRepo = dynamicFormRepo; + } + + @Override + public String save(List request, String authorisation) throws Exception { + OutputResponse response = new OutputResponse(); + + try { + if (request != null) { + logger.info("Saving TB confirmed case: " + request); + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + + for(TBConfirmedCaseDTO dto:request){ + String modifiedBy = jwtUtil.extractUsername(authorisation); + Long beneficiaryRegID = beneficiaryRepo.getRegIDFromBenId(dto.getBenId()); + BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, null, + modifiedBy, vanID, parkingPlaceID); + + List existing = repository.findByBenIdAndVisitCode(dto.getBenId(), visit.getVisitCode()); + boolean isNew = existing.isEmpty(); + TBConfirmedCase entity = isNew ? new TBConfirmedCase() : existing.get(0); + entity.setBenId(dto.getBenId()); + entity.setVisitCode(visit.getVisitCode()); + entity.setUserId(jwtUtil.extractUserId(authorisation)); + entity.setModifiedBy(modifiedBy); + entity.setRegimenType(dto.getRegimenType()); + entity.setTreatmentStartDate(dto.getTreatmentStartDate()); + entity.setExpectedTreatmentCompletionDate(dto.getExpectedTreatmentCompletionDate()); + entity.setFollowUpDate(dto.getFollowUpDate()); + entity.setMonthlyFollowUpDone(dto.getMonthlyFollowUpDone()); + entity.setAdherenceToMedicines(dto.getAdherenceToMedicines()); + entity.setAnyDiscomfort(dto.getAnyDiscomfort()); + entity.setTreatmentCompleted(dto.getTreatmentCompleted()); + entity.setActualTreatmentCompletionDate(dto.getActualTreatmentCompletionDate()); + entity.setTreatmentOutcome(dto.getTreatmentOutcome()); + entity.setDateOfDeath(dto.getDateOfDeath()); + entity.setPlaceOfDeath(dto.getPlaceOfDeath()); + entity.setReasonForDeath(dto.getReasonForDeath()); + entity.setReasonForNotCompleting(dto.getReasonForNotCompleting()); + if (entity.getVanID() == null && vanID != null) { entity.setVanID(vanID); entity.setParkingPlaceID(parkingPlaceID); } + entity.setProcessed("N"); + if(entity!=null){ + TBConfirmedCase saved = repository.save(entity); + if (isNew) repository.updateVanSerialNo(saved.getId()); + checkIncentive(entity); + } + } + + response.setResponse("TB Confirmed case saved successfully"); + + } else { + response.setError(500, "Invalid/NULL request obj"); + } + } catch (Exception e) { + logger.error("Error saving TB confirmed case", e); + response.setError(5000, "Error saving TB confirmed case: " + e.getMessage()); + } + + return response.toString(); + } + + private void checkIncentive(TBConfirmedCase entity){ + String regimen = entity.getRegimenType(); + + boolean isDrTb = + "Shorter Regimen (9–12 Months)".equalsIgnoreCase(regimen) + || "Longer Regimen (18–24 Months)".equalsIgnoreCase(regimen); + + if (Boolean.TRUE.equals(entity.getTreatmentCompleted()) + && entity.getExpectedTreatmentCompletionDate() != null) { + + + if (isDrTb) { + incentiveLogicService.incentiveForTbFollowUpIsDrTb( + entity.getBenId(), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + entity.getUserId() + ); + } else { + incentiveLogicService.incentiveForTbFollowUp( + entity.getBenId(), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + Timestamp.valueOf(entity.getExpectedTreatmentCompletionDate().atStartOfDay()), + entity.getUserId() + ); + + } + + } + } + + @Override + public String getByBenId(Long benId, String authorisation) throws Exception { + OutputResponse response = new OutputResponse(); + + try { + List list = repository.findByBenId(benId); + + if (list != null && !list.isEmpty()) { + List dtoList = list.stream() + .map(this::toDTO) + .collect(Collectors.toList()); + + response.setResponse(dtoList.toString()); + list.forEach(this::checkIncentive); + + } else { + response.setError(404, "No record found for benId: " + benId); + } + + } catch (Exception e) { + logger.error("Error getting TB confirmed case by benId", e); + response.setError(5000, "Error getting TB confirmed case: " + e.getMessage()); + } + + return response.toString(); + } + + @Override + public String getByUserId(String authorisation) throws Exception { + Integer userId = jwtUtil.extractUserId(authorisation); + List list = repository.findByUserId(userId); + return buildTbConfirmedCasesResponse(userId, list); + } + + @Override + public String getByProviderServiceMapId(Integer providerServiceMapID, Integer villageID) throws Exception { + List list = repository.getByProviderServiceMapIdAndVillageId(providerServiceMapID, villageID); + return buildTbConfirmedCasesResponse(null, list); + } + + private String buildTbConfirmedCasesResponse(Integer userId, List list) { + List dtoList = list.stream().map(this::toDTO).collect(Collectors.toList()); + + List benIds = dtoList.stream().map(TBConfirmedCaseDTO::getBenId).collect(Collectors.toList()); + Set counselledBenIds = Collections.emptySet(); + if (!benIds.isEmpty()) { + Optional counsellingForm = dynamicFormRepo.findByFormUuid(TbCounsellingFormSeeder.FORM_UUID); + if (counsellingForm.isPresent()) { + counselledBenIds = new HashSet<>(formResponseRepo.findCounselledBenIds(benIds, counsellingForm.get().getFormId(), "COMPLETE")); + } + } + final Set counselled = counselledBenIds; + dtoList.forEach(dto -> dto.setCounselled(counselled.contains(dto.getBenId()))); + + Map response = new java.util.HashMap<>(); + response.put("userId", userId); + response.put("tbConfirmedCases", dtoList); + Gson gson = new GsonBuilder() + .registerTypeAdapter(LocalDate.class, new LocalDateAdapter()) + .setDateFormat("MMM dd, yyyy h:mm:ss a") + .create(); + return gson.toJson(response); + } + + // Utility: convert entity -> DTO + private TBConfirmedCaseDTO toDTO(TBConfirmedCase entity) { + TBConfirmedCaseDTO dto = new TBConfirmedCaseDTO(); + + dto.setId(entity.getId()); + dto.setBenId(entity.getBenId()); + dto.setUserId(entity.getUserId()); + dto.setRegimenType(entity.getRegimenType()); + dto.setTreatmentStartDate(entity.getTreatmentStartDate()); + dto.setExpectedTreatmentCompletionDate(entity.getExpectedTreatmentCompletionDate()); + dto.setFollowUpDate(entity.getFollowUpDate()); + dto.setMonthlyFollowUpDone(entity.getMonthlyFollowUpDone()); + dto.setAdherenceToMedicines(entity.getAdherenceToMedicines()); + dto.setAnyDiscomfort(entity.getAnyDiscomfort()); + dto.setTreatmentCompleted(entity.getTreatmentCompleted()); + dto.setActualTreatmentCompletionDate(entity.getActualTreatmentCompletionDate()); + dto.setTreatmentOutcome(entity.getTreatmentOutcome()); + dto.setDateOfDeath(entity.getDateOfDeath()); + dto.setPlaceOfDeath(entity.getPlaceOfDeath()); + dto.setReasonForDeath(entity.getReasonForDeath()); + dto.setReasonForNotCompleting(entity.getReasonForNotCompleting()); + dto.setUpdateDate(entity.getLastModDate()); + dto.setUpdatedBy(entity.getModifiedBy()); + + return dto; + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java index b6210169..a6c217b8 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBScreeningServiceImpl.java @@ -55,16 +55,21 @@ public String save(TBScreeningRequestDTO requestDTO) throws Exception { @Override public String getByUserId(GetBenRequestHandler request) { - List dtos = new ArrayList<>(); - List tbScreeningList = tbScreeningRepo.getByUserId(request.getAshaId(), request.getFromDate(), request.getToDate()); - tbScreeningList.forEach(tbScreening -> dtos.add(modelMapper.map(tbScreening, TBScreeningDTO.class))); - TBScreeningRequestDTO tbScreeningRequestDTO = new TBScreeningRequestDTO(); - tbScreeningRequestDTO.setTbScreeningList(dtos); - tbScreeningRequestDTO.setUserId(request.getAshaId()); - Gson gson = new GsonBuilder() - .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format - .create(); - return gson.toJson(tbScreeningRequestDTO); + try { + List dtos = new ArrayList<>(); + List tbScreeningList = tbScreeningRepo.getByUserId(request.getAshaId()); + tbScreeningList.forEach(tbScreening -> dtos.add(modelMapper.map(tbScreening, TBScreeningDTO.class))); + TBScreeningRequestDTO tbScreeningRequestDTO = new TBScreeningRequestDTO(); + tbScreeningRequestDTO.setTbScreeningList(dtos); + tbScreeningRequestDTO.setUserId(request.getAshaId()); + Gson gson = new GsonBuilder() + .setDateFormat("MMM dd, yyyy h:mm:ss a") // Set the desired date format + .create(); + return gson.toJson(tbScreeningRequestDTO); + }catch (Exception e){ + logger.error("TBScreening Exception:"+e.getMessage()); + } + return null; } } diff --git a/src/main/java/com/iemr/flw/service/impl/TBStopVisitServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBStopVisitServiceImpl.java new file mode 100644 index 00000000..4f36b8b4 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/TBStopVisitServiceImpl.java @@ -0,0 +1,61 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.BenVisitDetail; +import com.iemr.flw.repo.iemr.BenVisitDetailsRepo; +import com.iemr.flw.service.TBStopVisitService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.sql.Timestamp; +import java.time.LocalDate; + +@Service +public class TBStopVisitServiceImpl implements TBStopVisitService { + + @Autowired + private BenVisitDetailsRepo benVisitDetailsRepo; + + @Override + @Transactional + public BenVisitDetail getOrCreateVisitForToday(Long beneficiaryRegID, Integer providerServiceMapID, + String createdBy, Integer vanID, Integer parkingPlaceID) { + LocalDate today = LocalDate.now(); + Timestamp dayStart = Timestamp.valueOf(today.atStartOfDay()); + Timestamp dayEnd = Timestamp.valueOf(today.plusDays(1).atStartOfDay()); + + BenVisitDetail existing = benVisitDetailsRepo.findStopTBVisitForToday(beneficiaryRegID, dayStart, dayEnd); + if (existing != null) return existing; + + Integer visitCount = benVisitDetailsRepo.countStopTBVisits(beneficiaryRegID); + short visitNo = (short) ((visitCount != null ? visitCount : 0) + 1); + + BenVisitDetail visit = new BenVisitDetail(); + visit.setBeneficiaryRegId(beneficiaryRegID); + visit.setVisitNo(visitNo); + visit.setVisitCategory("Stop TB"); + visit.setVisitReason("Screening"); + visit.setVisitDateTime(new Timestamp(System.currentTimeMillis())); + visit.setProviderServiceMapID(providerServiceMapID); + visit.setCreatedBy(createdBy); + visit.setCreatedDate(new Timestamp(System.currentTimeMillis())); + visit.setVanId(vanID); + visit.setParkingPlaceId(parkingPlaceID); + visit.setDeleted(false); + visit.setProcessed("N"); + visit = benVisitDetailsRepo.save(visit); + + // VisitCode: sessionID(1) + vanID(5-digit) + benVisitId(8-digit) — MMU formula + long visitCode = generateVisitCode(visit.getBenVisitId(), vanID != null ? vanID : 1); + visit.setVisitCode(visitCode); + // saveAndFlush ensures the VisitCode UPDATE reaches DB before child tables (e.g. t_benchiefcomplaint) + // insert with FK on VisitCode — same transaction, lazy flush otherwise causes FK violation + return benVisitDetailsRepo.saveAndFlush(visit); + } + + private long generateVisitCode(long visitId, int vanID) { + String vanStr = String.format("%05d", vanID); + String visitStr = String.format("%08d", visitId); + return Long.parseLong("1" + vanStr + visitStr); + } +} diff --git a/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java index 1b972be6..cc0abdd0 100644 --- a/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/TBSuspectedServiceImpl.java @@ -2,11 +2,16 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.iemr.flw.domain.iemr.BenVisitDetail; import com.iemr.flw.domain.iemr.TBSuspected; import com.iemr.flw.dto.identity.GetBenRequestHandler; import com.iemr.flw.dto.iemr.TBSuspectedDTO; import com.iemr.flw.dto.iemr.TBSuspectedRequestDTO; +import com.iemr.flw.repo.identity.BeneficiaryRepo; import com.iemr.flw.repo.iemr.TBSuspectedRepo; +import com.iemr.flw.service.IncentiveLogicService; +import com.iemr.flw.service.CampConfigService; +import com.iemr.flw.service.TBStopVisitService; import com.iemr.flw.service.TBSuspectedService; import org.modelmapper.ModelMapper; import org.slf4j.Logger; @@ -24,6 +29,15 @@ public class TBSuspectedServiceImpl implements TBSuspectedService { private final ModelMapper modelMapper = new ModelMapper(); @Autowired private TBSuspectedRepo tbSuspectedRepo; + @Autowired + private CampConfigService campConfigService; + @Autowired + private TBStopVisitService tbStopVisitService; + @Autowired + private BeneficiaryRepo beneficiaryRepo; + + @Autowired + private IncentiveLogicService incentiveLogicService; @Override public String getByBenId(Long benId, String authorisation) throws Exception { @@ -32,10 +46,15 @@ public String getByBenId(Long benId, String authorisation) throws Exception { @Override public String save(TBSuspectedRequestDTO requestDTO) throws Exception { - requestDTO.getTbSuspectedList().forEach(tbSuspectedDTO -> - { + Integer vanID = campConfigService.getVanID(); + Integer parkingPlaceID = campConfigService.getParkingPlaceID(); + for (TBSuspectedDTO tbSuspectedDTO : requestDTO.getTbSuspectedList()) { + Long beneficiaryRegID = beneficiaryRepo.getRegIDFromBenId(tbSuspectedDTO.getBenId()); + BenVisitDetail visit = tbStopVisitService.getOrCreateVisitForToday(beneficiaryRegID, null, + requestDTO.getUserId() != null ? requestDTO.getUserId().toString() : null, vanID, parkingPlaceID); + TBSuspected tbSuspected = - tbSuspectedRepo.getByUserIdAndBenId(tbSuspectedDTO.getBenId(), requestDTO.getUserId()); + tbSuspectedRepo.getByUserIdAndBenIdAndVisitCode(tbSuspectedDTO.getBenId(), requestDTO.getUserId(), visit.getVisitCode()); if (tbSuspected == null) { tbSuspected = new TBSuspected(); @@ -48,16 +67,43 @@ public String save(TBSuspectedRequestDTO requestDTO) throws Exception { } tbSuspected.setUserId(requestDTO.getUserId()); + tbSuspected.setVisitCode(visit.getVisitCode()); + if (tbSuspected.getVanID() == null && vanID != null) { tbSuspected.setVanID(vanID); tbSuspected.setParkingPlaceID(parkingPlaceID); } + tbSuspected.setProcessed("N"); tbSuspectedRepo.save(tbSuspected); - }); + tbSuspectedRepo.updateVanSerialNo(tbSuspected.getId()); + if(tbSuspected!=null){ + if(tbSuspected.getIsConfirmed()){ + incentiveLogicService.incentiveForTbSuspected(tbSuspected.getBenId(),tbSuspected.getVisitDate(),tbSuspected.getVisitDate(),tbSuspected.getUserId()); + + } + + } + } return "no of tb suspected items saved:" + requestDTO.getTbSuspectedList().size(); } @Override public String getByUserId(GetBenRequestHandler request) { List dtos = new ArrayList<>(); - List tbSuspectedList = tbSuspectedRepo.getByUserId(request.getAshaId(), request.getFromDate(), request.getToDate()); - tbSuspectedList.forEach(tbSuspected -> dtos.add(modelMapper.map(tbSuspected, TBSuspectedDTO.class))); + List tbSuspectedList = request.getProviderServiceMapID() != null + ? tbSuspectedRepo.getByProviderServiceMapIdAndVillageId(request.getProviderServiceMapID(), request.getVillageID()) + : tbSuspectedRepo.getByUserId(request.getAshaId(), request.getFromDate(), request.getToDate()); + for (TBSuspected tbSuspected : tbSuspectedList) { + TBSuspectedDTO dto = modelMapper.map(tbSuspected, TBSuspectedDTO.class); + dto.setUpdateDate(tbSuspected.getLastModDate()); + dto.setUpdatedBy(tbSuspected.getModifiedBy()); + dtos.add(dto); + + if (tbSuspected != null && Boolean.TRUE.equals(tbSuspected.getIsConfirmed())) { + incentiveLogicService.incentiveForTbSuspected( + tbSuspected.getBenId(), + tbSuspected.getVisitDate(), + tbSuspected.getVisitDate(), + tbSuspected.getUserId() + ); + } + } TBSuspectedRequestDTO tbSuspectedRequestDTO = new TBSuspectedRequestDTO(); tbSuspectedRequestDTO.setTbSuspectedList(dtos); tbSuspectedRequestDTO.setUserId(request.getAshaId()); diff --git a/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java new file mode 100644 index 00000000..c45f18e1 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/UTPReronaPaymentJob.java @@ -0,0 +1,195 @@ +package com.iemr.flw.service.impl; + +import com.google.gson.Gson; +import com.iemr.flw.domain.iemr.IncentiveActivity; +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.dto.iemr.PaymentItem; +import com.iemr.flw.dto.iemr.PaymentRequest; +import com.iemr.flw.dto.iemr.Period; +import com.iemr.flw.dto.iemr.VerifiedBy; +import com.iemr.flw.repo.iemr.IncentiveRecordRepo; +import com.iemr.flw.repo.iemr.IncentivesRepo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class UTPReronaPaymentJob { + + @Autowired + private IncentiveRecordRepo recordRepo; + + @Autowired + private IncentivesRepo incentivesRepo; + + @Autowired + private UtpreronaPaymentIntegrationImpl paymentService; + + // Runs automatically on 1st of every month at midnight + @Scheduled(cron = "0 0 0 1 * *") + public void sendMonthlyPayments() { + triggerPayment(); + } + + // ✅ Separate method — call this for immediate testing + public void triggerPayment() { + + LocalDate today = LocalDate.now(); + +// ✅ Current month ka data — testing ke liye + LocalDate firstDay = today.withDayOfMonth(1); // Mar 1, 2026 + LocalDate lastDay = today; // Mar 11, 2026 (aaj) + + String periodStart = firstDay.format(DateTimeFormatter.ISO_DATE); + String periodEnd = lastDay.format(DateTimeFormatter.ISO_DATE); + + Timestamp startTs = Timestamp.valueOf(firstDay.atStartOfDay()); // 2026-03-01 00:00:00 + Timestamp endTs = Timestamp.valueOf(lastDay.plusDays(1).atStartOfDay()); // 2026-03-12 00:00:00 + + log.info("========================================"); + log.info("UTP Rerona Payment Job Started"); + log.info("Period: {} to {}", periodStart, periodEnd); + log.info("Start Timestamp: {}", startTs); + log.info("End Timestamp: {}", endTs); + log.info("========================================"); + + List allAshaIds = recordRepo.findDistinctAshaIdsByDateRange(startTs, endTs); + log.info("Total ASHAs found: {}", allAshaIds.size()); + + int success = 0, failed = 0, skipped = 0; + + for (Integer ashaId : allAshaIds) { + try { + log.info("----------------------------------------"); + log.info("Processing ASHA ID: {}", ashaId); + + // Fetch claimed and approved records for this ASHA + List entities = recordRepo + .findClaimedApprovedRecordsByAshaAndDateRange(ashaId, startTs, endTs); + + if (entities == null || entities.isEmpty()) { + log.warn("ASHA {} — No records found, skipping", ashaId); + skipped++; + continue; + } + + log.info("ASHA {} — Total records fetched: {}", ashaId, entities.size()); + + // Collect all unique activity IDs + Set activityIds = entities.stream() + .filter(e -> e.getActivityId() != null) + .map(IncentiveActivityRecord::getActivityId) + .collect(Collectors.toSet()); + + log.info("ASHA {} — Unique activity IDs: {}", ashaId, activityIds); + + // Fetch activity master data for all activity IDs at once + Map activityMap = incentivesRepo.findAllById(activityIds) + .stream() + .filter(a -> a.getIsDeleted() == null || !a.getIsDeleted()) + .collect(Collectors.toMap(IncentiveActivity::getId, a -> a)); + + // Group records by activity ID + Map> groupedByActivity = entities.stream() + .filter(e -> e.getActivityId() != null) + .collect(Collectors.groupingBy(IncentiveActivityRecord::getActivityId)); + + // Build items list from grouped records + List items = new ArrayList<>(); + + for (Map.Entry> entry : groupedByActivity.entrySet()) { + Long activityId = entry.getKey(); + List records = entry.getValue(); + + IncentiveActivity activity = activityMap.get(activityId); + if (activity == null) { + log.warn("ASHA {} — Activity ID {} not found in master, skipping", ashaId, activityId); + continue; + } + + // Calculate total incentive amount for this activity + Long totalAmount = records.stream() + .mapToLong(r -> r.getAmount() != null ? r.getAmount() : 0L) + .sum(); + + + String stateActivityCode = activity.getStateActivityCode() != null + ? String.valueOf(activity.getStateActivityCode()) + : null; + + if (stateActivityCode == null) { + log.warn("ASHA {} — ActivityId {} stateActivityCode null, skipping", ashaId, activityId); + continue; // ✅ Is item ko request mein add hi mat karo + } + + PaymentItem item = new PaymentItem(); + item.setActivityCode(stateActivityCode); + item.setCount(String.valueOf(records.size())); + item.setIncentiveAmount(String.valueOf(totalAmount)); + items.add(item); + + + + log.info("ASHA {} — Activity: {} | Count: {} | Total Amount: {}", + ashaId, activityId, records.size(), totalAmount); + } + + if (items.isEmpty()) { + log.warn("ASHA {} — No valid items found, skipping", ashaId); + skipped++; + continue; + } + + // Get verified by details from first record + IncentiveActivityRecord firstRecord = entities.get(0); + VerifiedBy verifiedBy = new VerifiedBy(); + verifiedBy.setEmployeeId(firstRecord.getVerifiedByUserId() != null + ? String.valueOf(firstRecord.getVerifiedByUserId()) : ""); + verifiedBy.setName(firstRecord.getVerifiedByUserName() != null + ? firstRecord.getVerifiedByUserName() : ""); + + // Build period object + Period period = new Period(); + period.setStart(periodStart); + period.setEnd(periodEnd); + + // Build final payment request + PaymentRequest paymentRequest = new PaymentRequest( + UUID.randomUUID().toString(), + "AMRIT", + period, + ashaId.toString(), + OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME), + verifiedBy, + items + ); + + // Log full request before sending + log.info("ASHA {} — Request Payload: {}", ashaId, new Gson().toJson(paymentRequest)); + + // Send payment request to API + paymentService.sendPaymentRequest(paymentRequest); + + log.info("ASHA {} — Payment sent successfully", ashaId); + success++; + + } catch (Exception e) { + log.error("ASHA {} — Payment failed: {}", ashaId, e.getMessage(), e); + failed++; + } + } + + log.info("========================================"); + log.info("Job Complete | Success: {} | Failed: {} | Skipped: {}", success, failed, skipped); + log.info("========================================"); + } +} \ No newline at end of file diff --git a/src/main/java/com/iemr/flw/service/impl/UpdateIncentivePendindDocService.java b/src/main/java/com/iemr/flw/service/impl/UpdateIncentivePendindDocService.java new file mode 100644 index 00000000..bfda259f --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/UpdateIncentivePendindDocService.java @@ -0,0 +1,48 @@ +package com.iemr.flw.service.impl; + +import com.iemr.flw.domain.iemr.IncentiveActivityRecord; +import com.iemr.flw.domain.iemr.IncentivePendingActivity; +import com.iemr.flw.repo.iemr.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +public class UpdateIncentivePendindDocService { + @Autowired + private IncentivesRepo incentivesRepo; + + @Autowired + private UserServiceRoleRepo userRepo; + + @Autowired + private IncentiveRecordRepo recordRepo; + + @Autowired + private IncentivePendingActivityRepository incentivePendingActivityRepository; + + public void updateIncentive(Long id) { + + Optional optionalRecord = recordRepo.findById(id); + + if (optionalRecord.isPresent()) { + IncentiveActivityRecord record = optionalRecord.get(); + record.setIsEligible(true); + recordRepo.save(record); + } + } + + public void updatePendingActivity(Integer userId, Long recordId, Long activityId, Long mIncentiveId) { + IncentivePendingActivity incentivePendingActivity = new IncentivePendingActivity(); + incentivePendingActivity.setActivityId(activityId); + incentivePendingActivity.setRecordId(recordId); + incentivePendingActivity.setUserId(userId); + incentivePendingActivity.setMincentiveId(mIncentiveId); + if (incentivePendingActivity != null) { + incentivePendingActivityRepository.save(incentivePendingActivity); + } + + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java index 4e680a1d..52d3eefb 100644 --- a/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/UserServiceImpl.java @@ -8,16 +8,114 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.stream.Collectors; + @Service public class UserServiceImpl implements UserService { private final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); + @Autowired private UserServiceRoleRepo userServiceRoleRepo; + @Autowired + private FacilityDataService facilityDataService; + public UserServiceRoleDTO getUserDetail(Integer userId) { logger.info("calling getUserRole for userId: " + userId); UserServiceRoleDTO userRole = userServiceRoleRepo.getUserRole(userId).get(0); + userRole.setFacilityData(facilityDataService.buildFacilityData(userId, userRole.getRoleName())); + + // Stop TB / Nikshay — additive only. This naturally returns nothing for + // any user whose rows don't have NikshayTUID set, i.e. every non-Stop-TB + // user. Fetched first so the district-by-block patch below can tell + // Stop TB users apart and skip them. + List nikshayRows = userServiceRoleRepo.getNikshayMappingRows(userId, userRole.getProviderServiceMapId()); + boolean isStopTBUser = nikshayRows != null && !nikshayRows.isEmpty(); + + // Stop TB's BlockId holds a Nikshay TU ID, not an AMRIT BlockID - + // joining it against m_districtblock/m_district (what + // getDistrictByBlockId does) would resolve to whatever AMRIT + // district happens to share that same numeric ID by coincidence, + // not real data. Skip this patch for Stop TB users. + if (!isStopTBUser && userRole.getWorkingDistrictId() == null && userRole.getBlockId() != null) { + List districtResults = userServiceRoleRepo.getDistrictByBlockId(userRole.getBlockId()); + if (districtResults != null && !districtResults.isEmpty()) { + Object[] district = districtResults.get(0); + if (district != null && district.length == 2) { + userRole.setWorkingDistrictId(((Number) district[0]).intValue()); + userRole.setWorkingDistrictName((String) district[1]); + } + } + } + + if (isStopTBUser) { + TreeSet tuIds = new TreeSet<>(); + TreeSet facilityIds = new TreeSet<>(); + Integer districtId = null; + for (Object[] row : nikshayRows) { + addCsvIds((String) row[0], tuIds); + addCsvIds((String) row[1], facilityIds); + if (districtId == null && row[2] != null) { + districtId = ((Number) row[2]).intValue(); + } + } + + Map tuNames = tuIds.isEmpty() ? Map.of() + : toIdNameMap(userServiceRoleRepo.findNikshayTuNames(tuIds)); + Map facilityNames = facilityIds.isEmpty() ? Map.of() + : toIdNameMap(userServiceRoleRepo.findNikshayFacilityNames(facilityIds)); + + userRole.setTuId(joinIds(tuIds)); + userRole.setTuName(joinNames(tuIds, tuNames)); + userRole.setHealthFacilityId(joinIds(facilityIds)); + userRole.setHealthFacilityName(joinNames(facilityIds, facilityNames)); + + // Stop TB never sets WorkingLocationID, so workingDistrictId/Name + // (derived from it) are always null. DistrictID sits directly on + // the mapping row instead - Stop TB has no "work location" + // indirection layer the way other servicelines do, so read it + // straight from there rather than trying to derive it. + if (districtId != null) { + userRole.setWorkingDistrictId(districtId); + userRole.setWorkingDistrictName(userServiceRoleRepo.findNikshayDistrictName(districtId)); + } + } + return userRole; } + + private void addCsvIds(String csv, Collection target) { + if (csv == null || csv.isBlank()) { + return; + } + for (String id : csv.split(",")) { + try { + target.add(Integer.valueOf(id.trim())); + } catch (NumberFormatException ignored) { + // skip malformed entries rather than fail the whole login + } + } + } + + private Map toIdNameMap(List rows) { + Map map = new HashMap<>(); + for (Object[] row : rows) { + map.put(((Number) row[0]).intValue(), (String) row[1]); + } + return map; + } + + private String joinIds(Collection ids) { + return ids.stream().map(String::valueOf).collect(Collectors.joining(",")); + } + + private String joinNames(Collection ids, Map names) { + return ids.stream().map(id -> names.getOrDefault(id, "")).collect(Collectors.joining(",")); + } } diff --git a/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java b/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java new file mode 100644 index 00000000..f0e5a554 --- /dev/null +++ b/src/main/java/com/iemr/flw/service/impl/UtpreronaPaymentIntegrationImpl.java @@ -0,0 +1,66 @@ +package com.iemr.flw.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.flw.dto.iemr.PaymentRequest; +import io.swagger.v3.oas.models.responses.ApiResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +@Service +public class UtpreronaPaymentIntegrationImpl { +// @Value("${ssdPortalUrl}") + private String API_URL = "https://nhmssd.assam.gov.in/APPMS_2024_25/api/utpreronaPayment.php"; + private String API_KEY = "41202fa384eab2725a17bbac58cf708bf04cd1dd5175010941606156dc36d6b5"; + private static final int TIMEOUT_SECONDS = 30; + + private final HttpClient httpClient; + private final ObjectMapper objectMapper; + + public UtpreronaPaymentIntegrationImpl() { + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(TIMEOUT_SECONDS)) + .build(); + this.objectMapper = new ObjectMapper(); + } + + public ApiResponse sendPaymentRequest(PaymentRequest paymentRequest) + throws IOException, InterruptedException { + + String jsonBody = objectMapper.writeValueAsString(paymentRequest); + System.out.println("Sending Request:"); + System.out.println(objectMapper.writerWithDefaultPrettyPrinter() + .writeValueAsString(paymentRequest)); + + HttpRequest httpRequest = HttpRequest.newBuilder() + .uri(URI.create(API_URL)) + .timeout(Duration.ofSeconds(TIMEOUT_SECONDS)) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .header("x-api-key", API_KEY) + .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) + .build(); + + HttpResponse httpResponse = httpClient.send( + httpRequest, + HttpResponse.BodyHandlers.ofString() + ); + + System.out.println("Response Status: " + httpResponse.statusCode()); + System.out.println("Response Body: " + httpResponse.body()); + + if (httpResponse.statusCode() == 200) { + return objectMapper.readValue(httpResponse.body(), ApiResponse.class); + } else { + throw new IOException("API Error - Status: " + httpResponse.statusCode() + + " | Body: " + httpResponse.body()); + } + } + +} diff --git a/src/main/java/com/iemr/flw/service/impl/UwinSessionServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/UwinSessionServiceImpl.java index bb2a944c..d91d0c6f 100644 --- a/src/main/java/com/iemr/flw/service/impl/UwinSessionServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/UwinSessionServiceImpl.java @@ -8,6 +8,7 @@ import com.iemr.flw.dto.iemr.UwinSessionRequestDTO; import com.iemr.flw.dto.iemr.UwinSessionResponseDTO; import com.iemr.flw.masterEnum.GroupName; +import com.iemr.flw.masterEnum.StateCode; import com.iemr.flw.repo.iemr.IncentiveRecordRepo; import com.iemr.flw.repo.iemr.IncentivesRepo; import com.iemr.flw.repo.iemr.UserServiceRoleRepo; @@ -40,6 +41,9 @@ public class UwinSessionServiceImpl implements UwinSessionService { @Autowired private IncentiveRecordRepo recordRepo; + @Autowired + private UpdateIncentivePendindDocService updateIncentivePendindDocService; + @Override public UwinSessionResponseDTO saveSession(UwinSessionRequestDTO req) throws Exception { @@ -72,6 +76,7 @@ public UwinSessionResponseDTO saveSession(UwinSessionRequestDTO req) throws Exce session.setAshaId(req.getAshaId()); session.setDate(req.getDate()); session.setPlace(req.getPlace()); + session.setSessionDate(req.getDate()); session.setParticipants(req.getParticipants()); session.setCreatedBy(req.getCreatedBy()); if (req.getAttachments() != null && req.getAttachments().length > 0) { @@ -102,8 +107,45 @@ public UwinSessionResponseDTO saveSession(UwinSessionRequestDTO req) throws Exce dto.setParticipants(session.getParticipants()); dto.setAttachments(Collections.singletonList(session.getAttachmentsJson())); + return dto; } + @Override + public UwinSession updateSession(UwinSessionRequestDTO req, Long recordId, Long activityId) throws Exception { + Optional optionalUwinSession = repo.findById(recordId); + + if (optionalUwinSession.isPresent()) { + UwinSession session = optionalUwinSession.get(); // ✅ Use existing session + + // Update fields if present in request + if (req.getPlace() != null) session.setPlace(req.getPlace()); + if (req.getParticipants() != null) session.setParticipants(req.getParticipants()); + if (req.getDate() != null) session.setDate(req.getDate()); + + // Update attachments if present + if (req.getAttachments() != null && req.getAttachments().length > 0) { + List base64Images = Arrays.stream(req.getAttachments()) + .filter(file -> !file.isEmpty()) + .map(file -> { + try { + return Base64.getEncoder().encodeToString(file.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Error converting image to Base64", e); + } + }) + .collect(Collectors.toList()); + + String imagesJson = objectMapper.writeValueAsString(base64Images); + session.setAttachmentsJson(imagesJson); + + } + + repo.save(session); // ✅ Save updated session + return session; + } else { + throw new RuntimeException("Session not found for id: " + recordId); + } + } @Override public List getSessionsByAsha(Integer ashaId) throws Exception { @@ -130,9 +172,9 @@ public List getSessionsByAsha(Integer ashaId) throws Exc private void checkAndAddIncentive(UwinSession session) { IncentiveActivity incentiveActivityAM = incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_MOBILIZATION_SESSIONS", GroupName.IMMUNIZATION.getDisplayName()); IncentiveActivity incentiveActivityCH = incentivesRepo.findIncentiveMasterByNameAndGroup("CHILD_MOBILIZATION_SESSIONS", GroupName.ACTIVITY.getDisplayName()); + Integer stateId = userRepo.getUserRole(session.getAshaId()).get(0).getStateId(); - - if(incentiveActivityAM!=null){ + if(incentiveActivityAM!=null && stateId!=null && stateId.equals(StateCode.AM.getStateCode())){ IncentiveActivityRecord record = recordRepo .findRecordByActivityIdCreatedDateBenId(incentiveActivityAM.getId(), session.getDate(), 0L,session.getAshaId()); if (record == null) { @@ -147,11 +189,27 @@ record = new IncentiveActivityRecord(); record.setBenId(0L); record.setAshaId(session.getAshaId()); record.setAmount(Long.valueOf(incentiveActivityAM.getRate())); + record.setIsEligible(true); recordRepo.save(record); + + +// if(session.getAttachmentsJson()!=null){ +// record.setIsEligible(true); +// recordRepo.save(record); +// +// }else { +// record.setIsEligible(false); +// IncentiveActivityRecord incentiveActivityRecord = recordRepo.save(record); +// if(incentiveActivityRecord!=null){ +// updateIncentivePendindDocService.updatePendingActivity(session.getAshaId(),session.getId(),incentiveActivityRecord.getId(),incentiveActivityAM.getId()); +// +// } +// } + } } - if(incentiveActivityCH!=null){ + if(incentiveActivityCH!=null && stateId!=null && stateId.equals(StateCode.CG.getStateCode())){ IncentiveActivityRecord record = recordRepo .findRecordByActivityIdCreatedDateBenId(incentiveActivityCH.getId(), session.getDate(), 0L,session.getAshaId()); if (record == null) { @@ -166,6 +224,14 @@ record = new IncentiveActivityRecord(); record.setBenId(0L); record.setAshaId(session.getAshaId()); record.setAmount(Long.valueOf(incentiveActivityCH.getRate())); + record.setIsEligible(true); + +// if(session.getAttachmentsJson()!=null){ +// record.setIsEligible(true); +// }else { +// record.setIsEligible(false); +// updateIncentivePendindDocService.updatePendingActivity(session.getAshaId(),session.getId(),record.getId(),incentiveActivityCH.getId()); +// } recordRepo.save(record); } } diff --git a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java index 71bbdbad..7f1104d1 100644 --- a/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java +++ b/src/main/java/com/iemr/flw/service/impl/VillageLevelFormServiceImpl.java @@ -24,11 +24,11 @@ */ package com.iemr.flw.service.impl; -import com.iemr.flw.controller.CoupleController; import com.iemr.flw.domain.iemr.*; import com.iemr.flw.dto.iemr.*; import com.iemr.flw.masterEnum.GroupName; import com.iemr.flw.repo.iemr.*; +import com.iemr.flw.service.IncentiveLogicService; import com.iemr.flw.service.VillageLevelFormService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,8 +37,10 @@ import java.sql.Timestamp; import java.time.LocalDate; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Collections; +import java.util.Date; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -70,6 +72,9 @@ public class VillageLevelFormServiceImpl implements VillageLevelFormService { @Autowired private AHDFormRepo ahdFormRepo; + @Autowired + private IncentiveLogicService incentiveLogicService; + @Override public Boolean saveForm(VhndDto dto) { @@ -132,11 +137,20 @@ private Boolean saveVhncFormData(VhncFormDTO vhncFormDTO, Integer userID) { vhncForm.setImage2(vhncFormDTO.getImage2()); vhncForm.setImage1(vhncFormDTO.getImage1()); vhncForm.setPlace(vhncFormDTO.getPlace()); + vhncForm.setVillageName(vhncFormDTO.getVillageName()); + vhncForm.setAnm(vhncFormDTO.getAnm()); + vhncForm.setAww(vhncFormDTO.getAww()); + vhncForm.setNoOfPragnentWoment(vhncFormDTO.getNoOfPragnentWoment()); + vhncForm.setNoOfLactingMother(vhncFormDTO.getNoOfLactingMother()); + vhncForm.setNoOfCommittee(vhncFormDTO.getNoOfCommittee()); + vhncForm.setFollowupPrevius(vhncFormDTO.getFollowupPrevius()); + vhncForm.setNoOfBeneficiariesAttended(vhncFormDTO.getNoOfBeneficiariesAttended()); vhncForm.setFormType("VHNC"); vhncFormRepo.save(vhncForm); - checkAndAddIncentives(vhncForm.getVhncDate(), Math.toIntExact(vhncForm.getUserId()), "VHSNC_MEETING", vhncForm.getCreatedBy()); + + checkVhncIncentive(vhncForm.getCreatedDate(),Math.toIntExact(vhncForm.getUserId())); return true; } @@ -149,10 +163,15 @@ private Boolean savePhcForm(PhcReviewMeetingFormDTO dto, Integer userID) { phcReviewForm.setPlace(dto.getPlace()); phcReviewForm.setNoOfBeneficiariesAttended(dto.getNoOfBeneficiariesAttended()); phcReviewForm.setImage1(dto.getImage1()); + phcReviewForm.setVillageName(dto.getVillageName()); + phcReviewForm.setMitaninActivityCheckList(dto.getMitaninActivityCheckList()); + phcReviewForm.setPlaceId(dto.getPlaceId()); + phcReviewForm.setMitaninHistory(dto.getMitaninHistory()); phcReviewForm.setImage2(dto.getImage2()); phcReviewForm.setFormType("PHC"); phcReviewFormRepo.save(phcReviewForm); - checkAndAddIncentives(phcReviewForm.getPhcReviewDate(), Math.toIntExact(phcReviewForm.getUserId()), "CLUSTER_MEETING", phcReviewForm.getCreatedBy()); + + checkPhcMeetingIncentive(phcReviewForm.getCreatedDate(),Math.toIntExact(phcReviewForm.getUserId())); return true; } @@ -198,18 +217,182 @@ private Boolean saveVhndFormData(VHNDFormDTO vhndFormDTO, Integer userID) { VHNDForm vhndForm = new VHNDForm(); vhndForm.setUserId(userID); vhndForm.setVhndDate(vhndFormDTO.getVhndDate()); - vhndForm.setImage2(vhndFormDTO.getImage2()); - vhndForm.setImage1(vhndFormDTO.getImage1()); - vhndForm.setPlace(vhndFormDTO.getPlace()); - vhndForm.setNoOfBeneficiariesAttended(vhndFormDTO.getNoOfBeneficiariesAttended()); + vhndForm.setImage2(vhndFormDTO.getImage2() != null ? vhndFormDTO.getImage2() : ""); + vhndForm.setImage1(vhndFormDTO.getImage1() != null ? vhndFormDTO.getImage1() : ""); + vhndForm.setPlace(vhndFormDTO.getPlace() != null ? vhndFormDTO.getPlace() : ""); + + vhndForm.setNoOfBeneficiariesAttended( + vhndFormDTO.getNoOfBeneficiariesAttended() != null + ? vhndFormDTO.getNoOfBeneficiariesAttended() + : 0); + + vhndForm.setPregnantWomenAnc( + vhndFormDTO.getPregnantWomenAnc() != null + ? vhndFormDTO.getPregnantWomenAnc() + : null); + + vhndForm.setLactatingMothersPnc( + vhndFormDTO.getLactatingMothersPnc() != null + ? vhndFormDTO.getLactatingMothersPnc() + : null); + + vhndForm.setChildrenImmunization( + vhndFormDTO.getChildrenImmunization() != null + ? vhndFormDTO.getChildrenImmunization() + : null); + + vhndForm.setSelectAllEducation( + vhndFormDTO.getSelectAllEducation() != null + ? vhndFormDTO.getSelectAllEducation() + : false); + + vhndForm.setKnowledgeBalancedDiet( + vhndFormDTO.getKnowledgeBalancedDiet() != null + ? vhndFormDTO.getKnowledgeBalancedDiet() + : null); + + vhndForm.setCareDuringPregnancy( + vhndFormDTO.getCareDuringPregnancy() != null + ? vhndFormDTO.getCareDuringPregnancy() + : null); + + vhndForm.setImportanceBreastfeeding( + vhndFormDTO.getImportanceBreastfeeding() != null + ? vhndFormDTO.getImportanceBreastfeeding() + : null); + + vhndForm.setComplementaryFeeding( + vhndFormDTO.getComplementaryFeeding() != null + ? vhndFormDTO.getComplementaryFeeding() + : null); + + vhndForm.setHygieneSanitation( + vhndFormDTO.getHygieneSanitation() != null + ? vhndFormDTO.getHygieneSanitation() + : null); + + vhndForm.setFamilyPlanningHealthcare( + vhndFormDTO.getFamilyPlanningHealthcare() != null + ? vhndFormDTO.getFamilyPlanningHealthcare() + : null); vhndForm.setFormType("VHND"); vhndRepo.save(vhndForm); - checkAndAddIncentives(vhndForm.getVhndDate(), vhndForm.getUserId(), "VHND_PARTICIPATION", vhndForm.getCreatedBy()); + + + checkVhndIncentive(vhndForm.getCreatedDate(),vhndForm.getUserId()); + return true; } + private void checkVhndIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("VHND_PARTICIPATION", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + + private void checkPhcMeetingIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("CLUSTER_MEETING", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + + + private void checkVhncIncentive(Timestamp startTimestamp, Integer userId){ + + try { + IncentiveActivity activity = incentivesRepo.findIncentiveMasterByNameAndGroup("VHSNC_MEETING", GroupName.ACTIVITY.getDisplayName()); + if(activity!=null){ + IncentiveActivityRecord record = recordRepo + .findRecordByActivityIdCreatedDateBenId(activity.getId(), startTimestamp, 0L,userId); + if (record == null) { + record = new IncentiveActivityRecord(); + record.setActivityId(activity.getId()); + record.setCreatedDate(startTimestamp); + record.setCreatedBy(userRepo.getUserNamedByUserId(userId)); + record.setStartDate(startTimestamp); + record.setEndDate(startTimestamp); + record.setUpdatedDate(startTimestamp); + record.setUpdatedBy(userRepo.getUserNamedByUserId(userId)); + record.setAshaId(userId); + record.setBenId(0L); + record.setAmount(Long.valueOf(activity.getRate())); + record.setIsEligible(true); + recordRepo.save(record); + + } + } + + + + } catch (Exception e) { + logger.error("Process Incentive Exception: ", e); + + + } + + } + + @Override public List getAll(GetVillageLevelRequestHandler getVillageLevelRequestHandler) { if (Objects.equals(getVillageLevelRequestHandler.getFormType(), "VHND")) { @@ -244,6 +427,8 @@ public List getAll(GetVillageLevelRequestHandler getVillageLev private void checkAndAddIncentives(String date, Integer userID, String formType, String createdBY) { + String userName = userRepo.getUserNamedByUserId(userID); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy"); // Parse to LocalDate @@ -265,11 +450,11 @@ private void checkAndAddIncentives(String date, Integer userID, String formType, record = new IncentiveActivityRecord(); record.setActivityId(villageFormEntryActivityAM.getId()); record.setCreatedDate(timestamp); - record.setCreatedBy(userRepo.getUserNamedByUserId(userID)); + record.setCreatedBy(userName); record.setStartDate(timestamp); record.setEndDate(timestamp); record.setUpdatedDate(timestamp); - record.setUpdatedBy(userRepo.getUserNamedByUserId(userID)); + record.setUpdatedBy(userName); record.setAshaId(userID); record.setBenId(0L); record.setAmount(Long.valueOf(villageFormEntryActivityAM.getRate())); @@ -277,7 +462,6 @@ record = new IncentiveActivityRecord(); } } - if (villageFormEntryActivityCH != null) { IncentiveActivityRecord record = recordRepo .findRecordByActivityIdCreatedDateBenId(villageFormEntryActivityCH.getId(), timestamp, 0L,userID); @@ -285,12 +469,12 @@ record = new IncentiveActivityRecord(); record = new IncentiveActivityRecord(); record.setActivityId(villageFormEntryActivityCH.getId()); record.setCreatedDate(timestamp); - record.setCreatedBy(userRepo.getUserNamedByUserId(userID)); + record.setCreatedBy(userName); record.setStartDate(timestamp); record.setEndDate(timestamp); record.setBenId(0L); record.setUpdatedDate(timestamp); - record.setUpdatedBy(userRepo.getUserNamedByUserId(userID)); + record.setUpdatedBy(userName); record.setAshaId(userID); record.setAmount(Long.valueOf(villageFormEntryActivityCH.getRate())); recordRepo.save(record); diff --git a/src/main/java/com/iemr/flw/utils/JwtAuthenticationUtil.java b/src/main/java/com/iemr/flw/utils/JwtAuthenticationUtil.java index 9144ca3b..c44c41da 100644 --- a/src/main/java/com/iemr/flw/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/flw/utils/JwtAuthenticationUtil.java @@ -11,7 +11,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; import com.iemr.flw.repo.iemr.EmployeeMasterRepo; import com.iemr.flw.utils.exception.IEMRException; @@ -75,25 +75,25 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { String userId = claims.get("userId", String.class); // Check if user data is present in Redis - M_User user = getUserFromCache(userId); + User user = getUserFromCache(userId); if (user == null) { // If not in Redis, fetch from DB and cache the result user = fetchUserFromDB(userId); } if (user == null) { - throw new IEMRException("Invalid User ID."); + throw new IEMRException("Invalid User ID or user is deactivated please contact to admin."); } return true; // Valid userId and JWT token } catch (Exception e) { logger.error("Validation failed: " + e.getMessage(), e); - throw new IEMRException("Validation error: " + e.getMessage(), e); + throw new IEMRException("Validation error: Authentication failed", e); } } - private M_User getUserFromCache(String userId) { + private User getUserFromCache(String userId) { String redisKey = "user_" + userId; // The Redis key format - M_User user = (M_User) redisTemplate.opsForValue().get(redisKey); + User user = (User) redisTemplate.opsForValue().get(redisKey); if (user == null) { logger.warn("User not found in Redis. Will try to fetch from DB."); @@ -104,15 +104,15 @@ private M_User getUserFromCache(String userId) { return user; // Returns null if not found } - private M_User fetchUserFromDB(String userId) { + private User fetchUserFromDB(String userId) { // This method will only be called if the user is not found in Redis. String redisKey = "user_" + userId; // Redis key format // Fetch user from DB - M_User user = userLoginRepo.getUserByUserID(Integer.parseInt(userId)); + User user = userLoginRepo.findUserByUserID(Integer.parseInt(userId)); if (user != null) { - M_User userHash = new M_User(); + User userHash = new User(); userHash.setUserID(user.getUserID()); userHash.setUserName(user.getUserName()); diff --git a/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java index fcefd712..9cf022f0 100644 --- a/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/flw/utils/JwtUserIdValidationFilter.java @@ -116,7 +116,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo } catch (Exception e) { logger.error("Authorization error: ", e); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: Authentication failed"); } } @@ -152,7 +152,9 @@ private boolean shouldSkipPath(String path, String contextPath) { return path.equals(contextPath + "/user/userAuthenticate") || path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession") || path.startsWith(contextPath + "/swagger-ui") || path.startsWith(contextPath + "/v3/api-docs") - || path.startsWith(contextPath + "/public"); + || path.startsWith(contextPath + "/public") + || path.equals(contextPath + "/health") + || path.equals(contextPath + "/version"); } private String getJwtTokenFromCookies(HttpServletRequest request) { diff --git a/src/main/java/com/iemr/flw/utils/JwtUtil.java b/src/main/java/com/iemr/flw/utils/JwtUtil.java index 7107d738..ab15e464 100644 --- a/src/main/java/com/iemr/flw/utils/JwtUtil.java +++ b/src/main/java/com/iemr/flw/utils/JwtUtil.java @@ -90,13 +90,4 @@ private Claims extractAllClaims(String token) { .getPayload(); } - public String getUserNameFromStorage() { - return userName; - - } - - public void setUserNameFromStorage(String loginUserName) { - this.userName = loginUserName; - - } } diff --git a/src/main/java/com/iemr/flw/utils/LocalDateAdapter.java b/src/main/java/com/iemr/flw/utils/LocalDateAdapter.java new file mode 100644 index 00000000..d0081c29 --- /dev/null +++ b/src/main/java/com/iemr/flw/utils/LocalDateAdapter.java @@ -0,0 +1,20 @@ +package com.iemr.flw.utils; + +import com.google.gson.*; +import java.lang.reflect.Type; +import java.time.LocalDate; + +public class LocalDateAdapter + implements JsonSerializer, JsonDeserializer { + + @Override + public JsonElement serialize(LocalDate src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.toString()); // yyyy-MM-dd + } + + @Override + public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + return LocalDate.parse(json.getAsString()); + } +} diff --git a/src/main/java/com/iemr/flw/utils/PathTraversalFilter.java b/src/main/java/com/iemr/flw/utils/PathTraversalFilter.java new file mode 100644 index 00000000..e63012bc --- /dev/null +++ b/src/main/java/com/iemr/flw/utils/PathTraversalFilter.java @@ -0,0 +1,56 @@ +package com.iemr.flw.utils; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; + +@Component +@Order(1) +public class PathTraversalFilter implements Filter { + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) + throws IOException, ServletException { + + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + String uri = request.getRequestURI(); + + // Decode once to catch %2e%2e and similar encoded variants + String decodedUri = URLDecoder.decode(uri, StandardCharsets.UTF_8); + + if (containsTraversalPattern(uri) || containsTraversalPattern(decodedUri)) { + logger.warn("Path traversal attempt blocked: {}", uri); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid request path"); + return; + } + + chain.doFilter(servletRequest, servletResponse); + } + + private boolean containsTraversalPattern(String path) { + if (path == null) return false; + String normalized = path.toLowerCase(); + return normalized.contains("../") + || normalized.contains("..\\") + || normalized.contains("..;") + || normalized.contains("%2e%2e") + || normalized.contains("%252e") // double-encoded + || normalized.endsWith(".."); + } +} diff --git a/src/main/java/com/iemr/flw/utils/http/HTTPRequestInterceptor.java b/src/main/java/com/iemr/flw/utils/http/HTTPRequestInterceptor.java index 884d9905..5c5aaf23 100644 --- a/src/main/java/com/iemr/flw/utils/http/HTTPRequestInterceptor.java +++ b/src/main/java/com/iemr/flw/utils/http/HTTPRequestInterceptor.java @@ -93,7 +93,7 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons if (remoteAddress == null || remoteAddress.trim().length() == 0) { remoteAddress = request.getRemoteAddr(); } -// validator.checkKeyExists(authorization, remoteAddress); + validator.checkKeyExists(authorization, remoteAddress); break; } } catch (Exception e) { diff --git a/src/main/java/com/iemr/flw/utils/redis/RedisConfig.java b/src/main/java/com/iemr/flw/utils/redis/RedisConfig.java index 0a279319..98acde7a 100644 --- a/src/main/java/com/iemr/flw/utils/redis/RedisConfig.java +++ b/src/main/java/com/iemr/flw/utils/redis/RedisConfig.java @@ -7,7 +7,7 @@ import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; -import com.iemr.flw.domain.iemr.M_User; +import com.iemr.flw.domain.iemr.User; @Configuration public class RedisConfig { @@ -20,7 +20,7 @@ public RedisTemplate redisTemplate(RedisConnectionFactory factor template.setKeySerializer(new StringRedisSerializer()); // Use Jackson2JsonRedisSerializer for values (Users objects) - Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(M_User.class); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(User.class); template.setValueSerializer(serializer); return template; diff --git a/src/main/java/com/iemr/flw/utils/sessionobject/SessionObject.java b/src/main/java/com/iemr/flw/utils/sessionobject/SessionObject.java index d84a1684..c18da820 100644 --- a/src/main/java/com/iemr/flw/utils/sessionobject/SessionObject.java +++ b/src/main/java/com/iemr/flw/utils/sessionobject/SessionObject.java @@ -81,7 +81,6 @@ private void updateConcurrentSessionObject(String key, String value, Boolean ext JsonElement jsnElmnt = jsnParser.parse(value); jsnOBJ = jsnElmnt.getAsJsonObject(); if (jsnOBJ.has("userName") && jsnOBJ.get("userName") != null) { - jwtUtil.setUserNameFromStorage(jsnOBJ.get("userName").getAsString()); objectStore.updateObject(jsnOBJ.get("userName").getAsString().trim().toLowerCase(), key, extendExpirationTime, sessionExpiryTime); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8546550d..84cca481 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -62,12 +62,13 @@ spring.jpa.defer-datasource-initialization=true fhir-url= # TM Config -tm-url= +tm-url=https://amritdemo.piramalswasthya.org/tm-api springdoc.api-docs.enabled=true springdoc.swagger-ui.enabled=true + spring.redis.host=localhost spring.main.allow-bean-definition-overriding=true spring.redis.password= spring.redis.port=6379 -notificationurl=https://uatamrit.piramalswasthya.org/common-api/firebaseNotification/sendNotification \ No newline at end of file +notificationurl=https://uatamrit.piramalswasthya.org/common-api/firebaseNotification/sendNotification