Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
b608f2f
fix(user): append village ID into villageName so duplicate names are …
vishwab1 Sep 9, 2026
8a4360b
chore: bump version to 3.8.4
vishwab1 Sep 11, 2026
9780236
Merge pull request #340 from PSMRI/vb/fix-release-village-3.8.3
vishwab1 Sep 11, 2026
911e2be
trace: add diagnostic logging to getBeneficiaryData for count-mismatc…
vishwab1 Sep 15, 2026
139c3cd
fix: order duplicate-row lookups in getBeneficiaryData so .get(0) is …
vishwab1 Sep 15, 2026
870068a
Revert "trace: add diagnostic logging to getBeneficiaryData for count…
vishwab1 Sep 15, 2026
90e1f0a
Dropping duplicate columns in table tb_stoptb_general_examination
sehjotsinghunthinkable Sep 15, 2026
7ee803e
Merge pull request #343 from PSMRI/vb/3.8.4-getbendata-trace
SauravBizbRolly Sep 15, 2026
5e1a670
Adding migration applier and removing column migration file
sehjotsinghunthinkable Sep 22, 2026
fb8bc1a
feat: add four new columns to TB screening form
chetansaroya Sep 22, 2026
fa9f17b
Merge pull request #350 from chetansaroya/feature/add-tb-screening-fi…
vishwab1 Sep 22, 2026
35e62f8
feat: add dynamic form migrator and contact tracing migration
chetansaroya Sep 24, 2026
14aec93
Merge branch 'release-3.9.1' of https://github.com/PSMRI/FLW-API into…
chetansaroya Sep 24, 2026
ab769f1
feat: change the flw-api version to 3.9.1
chetansaroya Sep 24, 2026
03a5cfb
feat: update Stop TB service implementation
chetansaroya Sep 24, 2026
22dca92
feat: add dynamic form migrator with new form version creation
chetansaroya Sep 24, 2026
42d3114
feat: refactored code
chetansaroya Sep 24, 2026
ca82fc8
feat: changed flw-api version to 3.12.0
chetansaroya Sep 24, 2026
0665571
Merge pull request #356 from chetansaroya/feature/delete-duplicate-co…
vishwab1 Sep 24, 2026
5b94361
chore: bump pom version to 3.9.1
vishwab1 Sep 25, 2026
1b1cf23
Merge pull request #357 from PSMRI/chore/pom-version-3.9.1
SauravBizbRolly Sep 25, 2026
599d092
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 28, 2026
e38f64d
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 28, 2026
1e4a9f7
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 29, 2026
b2923cd
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 29, 2026
63898b5
Merge pull request #361 from sehjotsinghunthinkable/feature/workflow-…
vishwab1 Sep 29, 2026
127f842
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 29, 2026
85e6ab5
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 30, 2026
1f5dedb
Merge pull request #362 from sehjotsinghunthinkable/feature/workflow-…
vishwab1 Sep 30, 2026
3e60eab
feat: stop-584 dynamic form backward compatibility changes
chetansaroya Oct 5, 2026
68143c5
Merge pull request #364 from chetansaroya/feature/latest-form-version…
vishwab1 Oct 5, 2026
dee5611
fix(diagnostic): stop the poll scheduler from nulling vanSerialNo
vishwab1 Oct 6, 2026
290265f
fix(diagnostic): stamp vanSerialNo right after the order is first saved
vishwab1 Oct 6, 2026
ff278e5
Merge pull request #365 from PSMRI/vb/fix-diagnostic-vanserialno
SauravBizbRolly Oct 6, 2026
50dc8ba
feat: stop-542 extra fields consumer changes
chetansaroya Oct 6, 2026
f61b09a
Revert "feat: stop-542 extra fields consumer changes"
chetansaroya Oct 6, 2026
87d909f
feat: stop-542 extra fields consumer changes
chetansaroya Oct 6, 2026
04b46c7
feat(stoptb): save OPD prescription to standard tables and dispense s…
vishwab1 Oct 8, 2026
f634cd0
fix(stoptb): close dispensing gaps found in review
vishwab1 Oct 8, 2026
ef5697b
feat(stoptb): General OPD on AMRIT standard tables only
vishwab1 Oct 8, 2026
db518a2
feat(stoptb): calculate tablet/capsule quantity when the app sends none
vishwab1 Oct 8, 2026
0869e7e
fix(stoptb): OPD save validations from final review
vishwab1 Oct 8, 2026
5a0e2d4
feat(stoptb): default quantity 1 for non-tablet medicines when the ap…
vishwab1 Oct 8, 2026
234c936
feat(stoptb): getAll drugs list with form; SOS quantity default
vishwab1 Oct 8, 2026
5067950
Merge pull request #366 from chetansaroya/fix/STOP-542
vishwab1 Oct 9, 2026
b939647
Merge release-3.12.0 into vb/stoptb-drug-dispense
vishwab1 Oct 9, 2026
b23c8e0
updated version to 3.9.2
chetansaroya Oct 9, 2026
4398d78
Merge pull request #371 from chetansaroya/fix/pom
vishwab1 Oct 9, 2026
60968a7
Merge release-3.9.2 into vb/stoptb-drug-dispense
vishwab1 Oct 9, 2026
1c4baa2
Removing gpsLatitude and gpsLongitude, and setting values into latitu…
sehjotsinghunthinkable Oct 9, 2026
8c2b335
Adding locking for multiple order creation
sehjotsinghunthinkable Oct 9, 2026
688aafa
Adding locking for multiple order creation
sehjotsinghunthinkable Oct 9, 2026
bf7c1d9
Merge pull request #372 from sehjotsinghunthinkable/feature/duplicate…
SauravBizbRolly Oct 12, 2026
f7c8f03
fix(stoptb): fill missing service line on the day's visit
vishwab1 Oct 12, 2026
97c6672
Merge latest release-3.12.0 into vb/stoptb-drug-dispense
vishwab1 Oct 12, 2026
bee2f14
Adding locking for multiple order creation
sehjotsinghunthinkable Oct 13, 2026
43f1ca1
Merge pull request #375 from sehjotsinghunthinkable/feature/locking-s…
vishwab1 Oct 13, 2026
295d553
fix(stoptb): MMU dose-based quantity; no batch re-upload after dispense
vishwab1 Oct 16, 2026
eeb2a1d
fix(stoptb): send the batch's new stock to central after an OPD dispense
vishwab1 Oct 20, 2026
277db7a
Merge pull request #381 from PSMRI/vb/stoptb-3.12.0
SauravBizbRolly Oct 21, 2026
8d18e8d
feat(stoptb): save OPD prescription to standard tables and dispense s…
vishwab1 Oct 8, 2026
f403952
fix(stoptb): close dispensing gaps found in review
vishwab1 Oct 8, 2026
5ad0b40
feat(stoptb): General OPD on AMRIT standard tables only
vishwab1 Oct 8, 2026
727cfdd
feat(stoptb): calculate tablet/capsule quantity when the app sends none
vishwab1 Oct 8, 2026
2046861
fix(stoptb): OPD save validations from final review
vishwab1 Oct 8, 2026
3bb529f
feat(stoptb): default quantity 1 for non-tablet medicines when the ap…
vishwab1 Oct 8, 2026
b050820
feat(stoptb): getAll drugs list with form; SOS quantity default
vishwab1 Oct 8, 2026
f3a8a1d
Dropping duplicate columns in table tb_stoptb_general_examination
sehjotsinghunthinkable Sep 15, 2026
d5f07a2
Adding migration applier and removing column migration file
sehjotsinghunthinkable Sep 22, 2026
9d0e7cc
feat: add dynamic form migrator and contact tracing migration
chetansaroya Sep 24, 2026
e9d49bb
feat: change the flw-api version to 3.9.1
chetansaroya Sep 24, 2026
65825aa
feat: update Stop TB service implementation
chetansaroya Sep 24, 2026
4dc14b6
feat: add dynamic form migrator with new form version creation
chetansaroya Sep 24, 2026
bddbd41
feat: refactored code
chetansaroya Sep 24, 2026
3fb7d2a
feat: changed flw-api version to 3.12.0
chetansaroya Sep 24, 2026
b80b4a6
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 28, 2026
4b6da82
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 28, 2026
2272563
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 29, 2026
f746af1
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 29, 2026
d55f00c
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 29, 2026
3e3159e
Updated the device integration according to updated workflow
sehjotsinghunthinkable Sep 30, 2026
272a97c
feat: stop-584 dynamic form backward compatibility changes
chetansaroya Oct 5, 2026
ad6493a
feat: stop-542 extra fields consumer changes
chetansaroya Oct 6, 2026
cc06192
Revert "feat: stop-542 extra fields consumer changes"
chetansaroya Oct 6, 2026
5cbbf04
feat: stop-542 extra fields consumer changes
chetansaroya Oct 6, 2026
b554369
fix(stoptb): fill missing service line on the day's visit
vishwab1 Oct 12, 2026
c595908
Removing gpsLatitude and gpsLongitude, and setting values into latitu…
sehjotsinghunthinkable Oct 9, 2026
9e4fab9
Adding locking for multiple order creation
sehjotsinghunthinkable Oct 9, 2026
bd72175
Adding locking for multiple order creation
sehjotsinghunthinkable Oct 9, 2026
863d8c2
fix(stoptb): MMU dose-based quantity; no batch re-upload after dispense
vishwab1 Oct 16, 2026
032c0f0
fix(stoptb): send the batch's new stock to central after an OPD dispense
vishwab1 Oct 20, 2026
396b2fc
Changes for STOP-711
sehjotsinghunthinkable Oct 22, 2026
71199b3
Merge remote-tracking branch 'upstream/release-3.12.0' into feature/S…
sehjotsinghunthinkable Oct 22, 2026
94350a1
Merge pull request #384 from sehjotsinghunthinkable/feature/STOP-710
vishwab1 Oct 22, 2026
bb8e4c1
Making changes for STOP-735
sehjotsinghunthinkable Oct 28, 2026
8f75143
Merge pull request #391 from sehjotsinghunthinkable/feature/device-in…
vishwab1 Oct 28, 2026
faec388
feat(stoptb): /stoptb/sync/changes feed on the hub change log
drtechie Oct 29, 2026
beb4d39
feat(stoptb): let the app choose which record types the changes feed …
drtechie Oct 29, 2026
8143a75
fix(stoptb): treat t_prescription as a source of the OPD record
drtechie Oct 29, 2026
891aeb6
fix(stoptb): bound beneficiaries per feed page and bind tokens to rec…
drtechie Oct 29, 2026
ccb9d11
docs(stoptb): the change log now comes from AMRIT-DB main migrations …
drtechie Oct 29, 2026
cd298ff
Efficency on Stoptbapp (#394)
vishwab1 Oct 29, 2026
358a5b0
fix(stoptb): never move the feed past a change whose transaction is s…
drtechie Oct 29, 2026
428c926
fix(diagnostics): polls that change nothing don't rewrite the order o…
drtechie Oct 29, 2026
3eaaf71
feat(stoptb): send a beneficiary's older records when they come into …
drtechie Oct 29, 2026
4b9c544
feat(stoptb): changes feed only serves the user's own villages, all o…
drtechie Oct 29, 2026
2f07c73
fix(diagnostic): don't treat a failed result update as a lost race
drtechie Oct 29, 2026
926547c
feat(stoptb): save OPD prescription without dispensing by default (#395)
vishwab1 Oct 29, 2026
62b438a
Merge pull request #393 from PSMRI/feature/stoptb-sync-changes-feed
vishwab1 Oct 29, 2026
960b1ea
Merge branch 'main' into merge_to_main_release-3.12.0
sehjotsinghunthinkable Nov 2, 2026
24a3ad8
Merge remote-tracking branch 'origin/main' into merge_to_main_release…
sehjotsinghunthinkable Nov 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.iemr.common.flw</groupId>
<artifactId>flw-api</artifactId>
<version>3.11.0</version>
<version>3.12.0</version>
<packaging>war</packaging>

<name>FLW-API</name>
Expand Down
2 changes: 2 additions & 0 deletions src/main/environment/common_ci.properties
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/i
diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/
diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/
diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/
diagnostic.emrlite.xray.cancel-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/cancel/
diagnostic.emrlite.xray.username=@env.DIAGNOSTIC_EMRLITE_XRAY_USERNAME@
diagnostic.emrlite.xray.password=@env.DIAGNOSTIC_EMRLITE_XRAY_PASSWORD@

Expand All @@ -74,6 +75,7 @@ diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/ap
diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/
diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/
diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/
diagnostic.emrlite.truenat.cancel-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/cancel/
diagnostic.emrlite.truenat.username=@env.DIAGNOSTIC_EMRLITE_TRUENAT_USERNAME@
diagnostic.emrlite.truenat.password=@env.DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD@

Expand Down
2 changes: 2 additions & 0 deletions src/main/environment/common_docker.properties
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/i
diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/
diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/
diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/
diagnostic.emrlite.xray.cancel-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/cancel/
diagnostic.emrlite.xray.username=${DIAGNOSTIC_EMRLITE_XRAY_USERNAME}
diagnostic.emrlite.xray.password=${DIAGNOSTIC_EMRLITE_XRAY_PASSWORD}

Expand All @@ -80,6 +81,7 @@ diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/ap
diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/
diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/
diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/
diagnostic.emrlite.truenat.cancel-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/cancel/
diagnostic.emrlite.truenat.username=${DIAGNOSTIC_EMRLITE_TRUENAT_USERNAME}
diagnostic.emrlite.truenat.password=${DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD}

Expand Down
77 changes: 36 additions & 41 deletions src/main/environment/common_example.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ server.port=8081
# FHIR Config
fhir-url=http://localhost:8093/

# TM Config
tm-url=http://localhost:8089/
##--------------------------------------------## Primary db-------------------------------------------------------------------

Expand All @@ -24,11 +23,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
# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup
stoptb.van.id=0

cors.allowed-origins=http://localhost:*

source-address=
Expand All @@ -44,56 +49,46 @@ abha.client.secret=<your-abha-client-secret>
abha.token.url=<abha-token-url>
abha.xcmid=<sbx-or-prod>





# Diagnostic providers

# Provider names: use the values supported by your application
diagnostic.provider.xray=<XRAY_PROVIDER>
diagnostic.provider.truenat=<TRUENAT_PROVIDER>

# EMR Lite - Xray (base URL without trailing slash)
diagnostic.emrlite.xray.base-url=https://<EMRLITE_HOST>
# GovThealth API Config
govthealth.user.details.url=${GOVTHEALTH_USER_DETAILS_URL}
govthealth.user.id=${GOVTHEALTH_USER_ID}
govthealth.password=${GOVTHEALTH_PASSWORD}

# ── Diagnostic Device Integration ────────────────────────────────────────────
# diagnostic.provider.xray / diagnostic.provider.truenat select the vendor per orderType family
# (XRAY_CHEST vs MTB/MTB_PLUS/MDR_RIF), each must be one of com.iemr.flw.masterEnum.DiagnosticProviderCode
diagnostic.provider.xray=${DIAGNOSTIC_PROVIDER_XRAY}
diagnostic.provider.truenat=${DIAGNOSTIC_PROVIDER_TRUENAT}

# EMR Lite - xray group (same base-url as truenat for now; split so a distinct vendor/tenant can be
# swapped in for either group later without a code change)
diagnostic.emrlite.xray.base-url=${DIAGNOSTIC_EMRLITE_XRAY_BASE_URL}
diagnostic.emrlite.xray.login-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/login/
diagnostic.emrlite.xray.refresh-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/getAccessToken/
diagnostic.emrlite.xray.order-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/
diagnostic.emrlite.xray.result-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/result/
diagnostic.emrlite.xray.ping-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/ping/
diagnostic.emrlite.xray.username=<XRAY_USERNAME>
diagnostic.emrlite.xray.password=<XRAY_PASSWORD>
diagnostic.emrlite.xray.cancel-url=${diagnostic.emrlite.xray.base-url}/api/v1/integrations/orders/cancel/
diagnostic.emrlite.xray.username=${DIAGNOSTIC_EMRLITE_XRAY_USERNAME}
diagnostic.emrlite.xray.password=${DIAGNOSTIC_EMRLITE_XRAY_PASSWORD}

# EMR Lite - Truenat
diagnostic.emrlite.truenat.base-url=https://<EMRLITE_HOST>
# EMR Lite - truenat group (MTB/MTB_PLUS/MDR_RIF); same value as xray for now
diagnostic.emrlite.truenat.base-url=${DIAGNOSTIC_EMRLITE_TRUENAT_BASE_URL}
diagnostic.emrlite.truenat.login-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/login/
diagnostic.emrlite.truenat.refresh-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/getAccessToken/
diagnostic.emrlite.truenat.order-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/
diagnostic.emrlite.truenat.result-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/result/
diagnostic.emrlite.truenat.ping-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/ping/
diagnostic.emrlite.truenat.username=<TRUENAT_USERNAME>
diagnostic.emrlite.truenat.password=<TRUENAT_PASSWORD>

# Token TTL: replace with vendor-configured durations in seconds
diagnostic.emrlite.refresh-ttl-seconds=86400
diagnostic.emrlite.truenat.cancel-url=${diagnostic.emrlite.truenat.base-url}/api/v1/integrations/orders/cancel/
diagnostic.emrlite.truenat.username=${DIAGNOSTIC_EMRLITE_TRUENAT_USERNAME}
diagnostic.emrlite.truenat.password=${DIAGNOSTIC_EMRLITE_TRUENAT_PASSWORD}

# Example: polling every 60 seconds
diagnostic.poll.xray.tick-ms=60000
diagnostic.poll.truenat.tick-ms=60000
diagnostic.emrlite.token-ttl-seconds=${DIAGNOSTIC_EMRLITE_TOKEN_TTL_SECONDS}
diagnostic.emrlite.refresh-ttl-seconds=${DIAGNOSTIC_EMRLITE_REFRESH_TTL_SECONDS}

# Example: daily expiry at 11:59 PM in scheduler timezone
diagnostic.poll.expiry-cron=0 59 23 * * *
diagnostic.poll.xray.tick-ms=${DIAGNOSTIC_POLL_XRAY_TICK_MS}
diagnostic.poll.truenat.tick-ms=${DIAGNOSTIC_POLL_TRUENAT_TICK_MS}
# Daily cutoff (cron expression) after which all outstanding PENDING/IN_PROGRESS orders are marked EXPIRED
diagnostic.poll.expiry-cron=${DIAGNOSTIC_POLL_EXPIRY_CRON}

# Local folder (Windows: use forward slashes)
diagnostic.documents.storage-root=C:/amrit/diagnostic-documents
stoptb.enforce.vanid=false
# Stop TB: this deployment's van/camp ID, replacing the old Redis camp:vanID lookup
stoptb.van.id=0



# GovThealth API Config
govthealth.user.details.url=@env.GOVTHEALTH_USER_DETAILS_URL@
govthealth.user.id=@env.GOVTHEALTH_USER_ID@
govthealth.password=@env.GOVTHEALTH_PASSWORD@
common-api-base-url=
diagnostic.documents.storage-root=${DIAGNOSTIC_DOCUMENTS_STORAGE_ROOT}
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ public DiagnosticOrderController(DiagnosticOrderService diagnosticOrderService)

@PostMapping("/order/push")
@Operation(summary = "Push a diagnostic order to the configured provider")
public String pushOrder(@RequestBody @Valid DiagnosticOrderRequestDto request) {
public String pushOrder(@RequestBody @Valid DiagnosticOrderRequestDto request,
@RequestHeader("JwtToken") String jwtToken) {
OutputResponse response = new OutputResponse();
try {
DiagnosticOrder order = diagnosticOrderService.createAndPushOrder(request);
DiagnosticOrder order = diagnosticOrderService.createAndPushOrderByUser(request, jwtToken);
response.setResponse(new Gson().toJson(order));
} catch (Exception e) {
logger.error("Error in pushOrder: {}", e.getMessage());
Expand Down Expand Up @@ -128,14 +129,17 @@ public String pollOrder(@RequestParam Long beneficiaryId, @RequestParam String o
}

@PostMapping("/order/manualResult")
@Operation(summary = "Manually submit a diagnostic result for a beneficiary's latest order of the given "
+ "type, for use when no vendor device is integrated. Stored as-is; tbPresence, tbConfidence, and "
+ "drugResistancePresence are left null since nothing derives them. Rejected if that order is "
+ "already COMPLETED.")
public String submitManualResult(@RequestBody @Valid ManualDiagnosticResultRequestDto request) {
@Operation(summary = "Exactly one of resultSummary/reasonToClose is required. resultSummary: manually submit "
+ "a diagnostic result for a beneficiary's latest order of the given type, for use when no vendor "
+ "device is integrated. Stored as-is; tbPresence, tbConfidence, and drugResistancePresence are left "
+ "null since nothing derives them. Rejected if that order is already COMPLETED. reasonToClose: close "
+ "the order instead (same behavior as reasonToClose on /order/push), sourcing patient/orderEvent "
+ "from the beneficiary's existing order for this type.")
public String submitManualResult(@RequestBody @Valid ManualDiagnosticResultRequestDto request,
@RequestHeader("JwtToken") String jwtToken) {
OutputResponse response = new OutputResponse();
try {
DiagnosticOrderResultDto result = diagnosticOrderService.submitManualResult(request);
DiagnosticOrderResultDto result = diagnosticOrderService.submitManualResult(request, jwtToken);
response.setResponse(new GsonBuilder().serializeNulls().create().toJson(result));
} catch (Exception e) {
logger.error("Error in submitManualResult: {}", e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
package com.iemr.flw.controller;

import com.iemr.flw.dto.iemr.DynamicFormDTO;
import com.iemr.flw.dto.iemr.LatestFormVersionDTO;
import com.iemr.flw.service.DynamicFormDefinitionService;
import com.iemr.flw.utils.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -35,6 +36,8 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
* REST controller for dynamic form definition management.
* All write operations use POST; all read operations use GET.
Expand Down Expand Up @@ -97,4 +100,10 @@ public ResponseEntity<ApiResponse> deactivateForm(
return ResponseEntity.ok(new ApiResponse(true, "Form deactivated", null));
}

@Operation(summary = "Get the latest version of each active form (formId, formUuid, formName, currentVersionNumber)")
@RequestMapping(value = "/getLatestFormVersions", method = RequestMethod.GET)
public ResponseEntity<ApiResponse> getLatestFormVersions() {
List<LatestFormVersionDTO> result = formService.getLatestFormVersions();
return ResponseEntity.ok(new ApiResponse(true, "Latest form versions fetched successfully", result));
}
}
13 changes: 9 additions & 4 deletions src/main/java/com/iemr/flw/controller/StopTBController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.iemr.flw.service.StopTBPrescriptionService;
import com.iemr.flw.service.StopTBService;
import com.iemr.flw.utils.response.OutputResponse;
import io.swagger.v3.oas.annotations.Operation;
Expand Down Expand Up @@ -51,7 +52,7 @@ public String getAllGeneralExaminations(@RequestBody Map<String, Object> body) {
if (raw == null) throw new Exception("providerServiceMapID is required");
Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null;
Map<String, Object> data = stopTBService.getAllGeneralExaminations(Integer.parseInt(raw.toString()), villageID);
response.setResponse(gson.toJson(data));
response.setResponse(gson.toJsonTree(data));
} catch (Exception e) {
logger.error("Error in getAllGeneralExaminations: " + e);
response.setError(5000, "Error fetching general examinations: " + e.getMessage());
Expand Down Expand Up @@ -84,7 +85,7 @@ public String getAllNurseTBScreenings(@RequestBody Map<String, Object> body) {
if (raw == null) throw new Exception("providerServiceMapID is required");
Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null;
Map<String, Object> data = stopTBService.getAllNurseTBScreenings(Integer.parseInt(raw.toString()), villageID);
response.setResponse(gson.toJson(data));
response.setResponse(gson.toJsonTree(data));
} catch (Exception e) {
logger.error("Error in getAllNurseTBScreenings: " + e);
response.setError(5000, "Error fetching TB screenings: " + e.getMessage());
Expand All @@ -101,6 +102,10 @@ public String saveGeneralOpd(@RequestBody List<Map<String, Object>> dataList) {
try {
List<Map<String, Object>> result = stopTBService.saveGeneralOpd(dataList);
response.setResponse(gson.toJson(result));
} catch (StopTBPrescriptionService.InsufficientStockException e) {
// Nothing was saved; the app shows this and lets the nurse lower the quantity.
logger.warn("saveGeneralOpd rejected: " + e.getMessage());
response.setError(5000, e.getMessage());
} catch (Exception e) {
logger.error("Error in saveGeneralOpd: " + e);
response.setError(5000, "Error saving general OPD: " + e.getMessage());
Expand All @@ -117,7 +122,7 @@ public String getAllGeneralOpd(@RequestBody Map<String, Object> body) {
if (raw == null) throw new Exception("providerServiceMapID is required");
Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null;
Map<String, Object> data = stopTBService.getAllGeneralOpd(Integer.parseInt(raw.toString()), villageID);
response.setResponse(gson.toJson(data));
response.setResponse(gson.toJsonTree(data));
} catch (Exception e) {
logger.error("Error in getAllGeneralOpd: " + e);
response.setError(5000, "Error fetching general OPD records: " + e.getMessage());
Expand Down Expand Up @@ -150,7 +155,7 @@ public String getAllDiagnostics(@RequestBody Map<String, Object> body) {
if (raw == null) throw new Exception("providerServiceMapID is required");
Integer villageID = body.get("villageID") != null ? Integer.parseInt(body.get("villageID").toString()) : null;
Map<String, Object> data = stopTBService.getAllDiagnostics(Integer.parseInt(raw.toString()), villageID);
response.setResponse(gson.toJson(data));
response.setResponse(gson.toJsonTree(data));
} catch (Exception e) {
logger.error("Error in getAllDiagnostics: " + e);
response.setError(5000, "Error fetching diagnostics records: " + e.getMessage());
Expand Down
77 changes: 77 additions & 0 deletions src/main/java/com/iemr/flw/controller/StopTBSyncController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.iemr.flw.controller;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.iemr.flw.service.StopTBSyncService;
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.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/stoptb/sync")
public class StopTBSyncController {

private final Logger logger = LoggerFactory.getLogger(StopTBSyncController.class);

private final Gson gson = new GsonBuilder().serializeNulls().create();

@Autowired
private StopTBSyncService stopTBSyncService;

@Autowired
private JwtUtil jwtUtil;

/**
* Headers: JwtToken (required; the user's role mappings decide the allowed service and villages).
* Body: { token: string|null, providerServiceMapID: int, villageIds: [int] (empty = all of the user's
* villages), types: [string], limit: int }.
* types: the record types the app applies (all when omitted); changing it requires a new snapshot.
* Response: { supported, serverId, snapshot, items: [{type, op, key, version, data}], nextToken, hasMore }.
* Call again with nextToken while hasMore is true. On a server without the change log (AMRIT-DB before V132) the
* response is { supported: false } and the app keeps using the getAll endpoints.
*/
@PostMapping("/changes")
@Operation(summary = "STOP-TB records changed since the token (first call: everything in the villages)")
public String getChanges(@RequestBody Map<String, Object> body,
@RequestHeader(value = "Authorization", required = false) String authorization,
@RequestHeader(value = "JwtToken", required = false) String jwtToken) {
OutputResponse response = new OutputResponse();
try {
// The user decides which villages may be synced, so the JWT is required here even
// where the request filter would let a mobile request through without one.
if (jwtToken == null || jwtToken.isBlank()) throw new IllegalArgumentException("JwtToken header is required");
Integer userId = jwtUtil.extractUserId(jwtToken);
Object token = body.get("token");
Integer psm = body.get("providerServiceMapID") != null
? Integer.parseInt(body.get("providerServiceMapID").toString()) : null;
List<Integer> villageIds = new ArrayList<>();
if (body.get("villageIds") instanceof List) {
for (Object v : (List<?>) body.get("villageIds")) {
if (v != null) villageIds.add((int) Double.parseDouble(v.toString()));
}
}
List<String> types = new ArrayList<>();
if (body.get("types") instanceof List) {
for (Object t : (List<?>) body.get("types")) {
if (t != null) types.add(t.toString());
}
}
Integer limit = body.get("limit") != null ? (int) Double.parseDouble(body.get("limit").toString()) : null;
Map<String, Object> data = stopTBSyncService.getChanges(
userId, token != null ? token.toString() : null, psm, villageIds, types, limit, authorization);
response.setResponse(gson.toJson(data));
} catch (Exception e) {
logger.error("Error in sync/changes: " + e);
response.setError(5000, "Error fetching changes: " + e.getMessage());
}
return response.toString();
}
}
Loading
Loading