diff --git a/android/app/src/main/java/io/mosip/registration_client/api_services/RegistrationApi.java b/android/app/src/main/java/io/mosip/registration_client/api_services/RegistrationApi.java index 5fe49881f..8379f2aed 100644 --- a/android/app/src/main/java/io/mosip/registration_client/api_services/RegistrationApi.java +++ b/android/app/src/main/java/io/mosip/registration_client/api_services/RegistrationApi.java @@ -24,6 +24,7 @@ import io.mosip.registration.clientmanager.constant.Components; import io.mosip.registration.clientmanager.dto.registration.RegistrationDto; import io.mosip.registration.clientmanager.dto.uispec.FieldSpecDto; +import io.mosip.registration.clientmanager.exception.ClientCheckedException; import io.mosip.registration.clientmanager.service.TemplateService; import io.mosip.registration.clientmanager.spi.AuditManagerService; import io.mosip.registration.clientmanager.spi.RegistrationService; @@ -47,11 +48,14 @@ public RegistrationApi(RegistrationService registrationService, TemplateService } @Override - public void startRegistration(@NonNull List languages, @NonNull String flowType, @NonNull String process, @NonNull RegistrationDataPigeon.Result result) { + public void startRegistration(@NonNull List languages, @NonNull String flowType, @NonNull String process, + Double latitude, Double longitude, @NonNull RegistrationDataPigeon.Result result) { auditManagerService.audit(AuditEvent.REGISTRATION_START, Components.REGISTRATION); String response = ""; try { - this.registrationDto = registrationService.startRegistration(languages, flowType, process); + this.registrationDto = registrationService.startRegistration(languages, flowType, process, latitude, longitude); + } catch (ClientCheckedException e) { + response = e.getErrorCode(); } catch (Exception e) { response = e.getMessage(); Log.e(getClass().getSimpleName(), "Registration start failed", e); diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/config/AppModule.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/config/AppModule.java index aa17ab068..a9f413251 100644 --- a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/config/AppModule.java +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/config/AppModule.java @@ -48,6 +48,7 @@ import io.mosip.registration.clientmanager.service.PreRegistrationDataSyncDaoImpl; import io.mosip.registration.clientmanager.service.PreRegistrationDataSyncServiceImpl; import io.mosip.registration.clientmanager.service.RegistrationServiceImpl; +import io.mosip.registration.clientmanager.service.PreCheckValidatorServiceImpl; import io.mosip.registration.clientmanager.service.TemplateService; import io.mosip.registration.clientmanager.service.UserOnboardService; import io.mosip.registration.clientmanager.service.external.PreRegZipHandlingService; @@ -62,6 +63,7 @@ import io.mosip.registration.clientmanager.spi.PreRegistrationDataSyncService; import io.mosip.registration.clientmanager.spi.RegistrationService; import io.mosip.registration.clientmanager.spi.SyncRestService; +import io.mosip.registration.clientmanager.spi.PreCheckValidatorService; import io.mosip.registration.clientmanager.util.DateUtil; import io.mosip.registration.clientmanager.util.SyncRestUtil; import io.mosip.registration.clientmanager.util.UserInterfaceHelperService; @@ -207,10 +209,11 @@ RegistrationService provideRegistrationService(PacketWriterService packetWriterS LocationValidationService locationValidationService, Provider preRegistrationDataSyncServiceProvider, Biometrics095Service biometricService, - PacketService packetService) { + PacketService packetService, + PreCheckValidatorService preCheckValidatorService) { return new RegistrationServiceImpl(appContext, packetWriterService, registrationRepository, masterDataService, identitySchemaRepository, clientCryptoManagerService, - keyStoreRepository, globalParamRepository, auditManagerService, registrationCenterRepository,locationValidationService, preRegistrationDataSyncServiceProvider, biometricService, packetService); + keyStoreRepository, globalParamRepository, auditManagerService, registrationCenterRepository,locationValidationService, preRegistrationDataSyncServiceProvider, biometricService, packetService, preCheckValidatorService); } @Provides @@ -310,4 +313,18 @@ PreRegZipHandlingService PreRegZipHandlingService(ApplicantValidDocumentDao appl PreRegistrationList PreRegistrationList() { return new PreRegistrationList(); } + + @Provides + @Singleton + PreCheckValidatorService providePreCheckValidatorService(SyncJobDefRepository syncJobDefRepository, + GlobalParamRepository globalParamRepository, + JobManagerService jobManagerService, + JobTransactionService jobTransactionService, + LocationValidationService locationValidationService, + MasterDataService masterDataService, + RegistrationCenterRepository registrationCenterRepository) { + return new PreCheckValidatorServiceImpl(appContext, syncJobDefRepository, globalParamRepository, + jobManagerService, jobTransactionService, locationValidationService, masterDataService, + registrationCenterRepository); + } } \ No newline at end of file diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/constant/RegistrationConstants.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/constant/RegistrationConstants.java index 5ae5a189a..966fd27d9 100644 --- a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/constant/RegistrationConstants.java +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/constant/RegistrationConstants.java @@ -118,6 +118,9 @@ public class RegistrationConstants { public static final String JOB_TRIGGER_POINT_USER = "User"; public static final String GPS_DEVICE_ENABLE_FLAG = "mosip.registration.gps_device_enable_flag"; public static final String DIST_FRM_MACHINE_TO_CENTER = "mosip.registration.distance.from.machine.to.center"; + public static final String GEO_CAP_FREQ = "mosip.registration.geo.capture.frequency"; + public static final String OPT_TO_REG_OUTSIDE_LOCATION = "OPT_TO_REG_OUTSIDE_LOCATION"; + public static final String OPT_TO_REG_LAST_CAPTURED_TIME = "OPT_TO_REG_LAST_CAPTURED_TIME"; public static final String OPERATOR_ONBOARDING_BIO_ATTRIBUTES = "mosip.registration.operator.onboarding.bioattributes"; public static final String SERVER_ACTIVE_PROFILE = "mosip.registration.server_profile"; public static final String ONBOARD_YOURSELF_URL = "mosip.registration.onboard_yourself_url"; @@ -149,4 +152,10 @@ public class RegistrationConstants { public static final String DEFAULT_HOST_NAME = "mosip.registration.audit_default_host_name"; public static final String REG_PAK_MAX_CNT_APPRV_LIMIT = "mosip.registration.reg_pak_max_cnt_apprv_limit"; public static final String PACKET_STORE_LOCATION = "mosip.registration.registration_packet_store_location"; + + // Sync status validation constants + public static final String MOSIP_REGISTRATION = "mosip.registration."; + public static final String DOT = "."; + public static final String FREQUENCY = "frequency"; + public static final String OPT_TO_REG_TIME_SYNC_EXCEED = "OPT_TO_REG_TIME_SYNC_EXCEED"; } diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImpl.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImpl.java new file mode 100644 index 000000000..ea98a6284 --- /dev/null +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImpl.java @@ -0,0 +1,292 @@ +package io.mosip.registration.clientmanager.service; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import io.mosip.registration.clientmanager.R; +import io.mosip.registration.clientmanager.constant.RegistrationConstants; +import io.mosip.registration.clientmanager.entity.SyncJobDef; +import io.mosip.registration.clientmanager.exception.ClientCheckedException; +import io.mosip.registration.clientmanager.dto.CenterMachineDto; +import io.mosip.registration.clientmanager.entity.RegistrationCenter; +import io.mosip.registration.clientmanager.repository.GlobalParamRepository; +import io.mosip.registration.clientmanager.repository.RegistrationCenterRepository; +import io.mosip.registration.clientmanager.repository.SyncJobDefRepository; +import io.mosip.registration.clientmanager.spi.JobManagerService; +import io.mosip.registration.clientmanager.spi.JobTransactionService; +import io.mosip.registration.clientmanager.spi.LocationValidationService; +import io.mosip.registration.clientmanager.spi.MasterDataService; +import io.mosip.registration.clientmanager.spi.PreCheckValidatorService; + +/** + * Validates pre-check requirements (sync status and GPS location). + * + * @author Sachin S P + */ +@Singleton +public class PreCheckValidatorServiceImpl implements PreCheckValidatorService { + + private static final String TAG = PreCheckValidatorServiceImpl.class.getSimpleName(); + + private Context context; + private SyncJobDefRepository syncJobDefRepository; + private GlobalParamRepository globalParamRepository; + private JobManagerService jobManagerService; + private JobTransactionService jobTransactionService; + private LocationValidationService locationValidationService; + private MasterDataService masterDataService; + private RegistrationCenterRepository registrationCenterRepository; + + @Inject + public PreCheckValidatorServiceImpl( + Context context, + SyncJobDefRepository syncJobDefRepository, + GlobalParamRepository globalParamRepository, + JobManagerService jobManagerService, + JobTransactionService jobTransactionService, + LocationValidationService locationValidationService, + MasterDataService masterDataService, + RegistrationCenterRepository registrationCenterRepository) { + this.context = context; + this.syncJobDefRepository = syncJobDefRepository; + this.globalParamRepository = globalParamRepository; + this.jobManagerService = jobManagerService; + this.jobTransactionService = jobTransactionService; + this.locationValidationService = locationValidationService; + this.masterDataService = masterDataService; + this.registrationCenterRepository = registrationCenterRepository; + } + + /** + * Validates sync job frequencies. + * + * @throws ClientCheckedException if validation fails + */ + @Override + public void validateSyncStatus() throws Exception { + try { + validatingSyncJobsConfig(); + } catch (ClientCheckedException e) { + Log.e(TAG, "Sync status validation failed", e); + throw e; + } catch (Exception e) { + Log.e(TAG, "Unexpected error during sync status validation", e); + throw new ClientCheckedException( + RegistrationConstants.OPT_TO_REG_TIME_SYNC_EXCEED, + "Sync validation error: " + e.getMessage()); + } + } + + /** + * Validates sync jobs are within frequency limits. + * Only checks jobs with sync history. + * + * @throws ClientCheckedException if any job is overdue + */ + private void validatingSyncJobsConfig() throws Exception { + List activeJobs = syncJobDefRepository.getActiveSyncJobs(); + if (activeJobs == null || activeJobs.isEmpty()) { + return; + } + + Map jobFrequencyMap = getSyncJobFrequencies(activeJobs); + if (jobFrequencyMap.isEmpty()) { + return; + } + int syncFailureCount = 0; + StringBuilder errorDetails = new StringBuilder(); + + for (SyncJobDef syncJobDef : activeJobs) { + String jobId = syncJobDef.getId(); + String apiName = syncJobDef.getApiName(); + + if (jobId == null || apiName == null) { + Log.w(TAG, "Skipping job with null id or apiName"); + continue; + } + + String configuredFrequencyStr = jobFrequencyMap.get(jobId); + if (configuredFrequencyStr == null || configuredFrequencyStr.trim().isEmpty()) { + continue; + } + + try { + int configuredFrequency = Integer.parseInt(configuredFrequencyStr.trim()); + int serviceJobId = jobManagerService.generateJobServiceId(jobId); + long lastSyncTimeMillis = jobTransactionService.getLastSyncTime(serviceJobId); + + if (lastSyncTimeMillis == 0) { + // Job has never been synced - skip validation + continue; + } + + Date lastSyncDate = new Date(lastSyncTimeMillis); + int actualDays = getActualDays(lastSyncDate); + + if (actualDays > configuredFrequency) { + syncFailureCount++; + errorDetails.append("- ").append(apiName) + .append(": Last sync was ").append(actualDays) + .append(" days ago (limit: ").append(configuredFrequency).append(" days)\n"); + } + + } catch (NumberFormatException e) { + Log.e(TAG, "Invalid frequency value for job: " + jobId + " (" + apiName + "): " + configuredFrequencyStr, e); + syncFailureCount++; + errorDetails.append("- ").append(apiName) + .append(": Invalid frequency configuration value: ").append(configuredFrequencyStr).append("\n"); + } catch (Exception e) { + Log.e(TAG, "Error validating job: " + jobId + " (" + apiName + ")", e); + syncFailureCount++; + errorDetails.append("- ").append(apiName) + .append(": Validation error: ").append(e.getMessage()).append("\n"); + } + } + if (syncFailureCount > 0) { + String errorMessage = "Registration blocked: " + syncFailureCount + + " sync job(s) are overdue:\n" + errorDetails.toString(); + Log.e(TAG, errorMessage); + throw new ClientCheckedException(RegistrationConstants.OPT_TO_REG_TIME_SYNC_EXCEED, errorMessage); + } + } + + /** + * Gets sync job frequencies from config. + * + * @param activeJobs List of active sync jobs + * @return Map of jobId to frequency value + */ + private Map getSyncJobFrequencies(List activeJobs) { + Map jobsMap = new HashMap<>(); + + for (SyncJobDef syncJobDef : activeJobs) { + String jobId = syncJobDef.getId(); + String apiName = syncJobDef.getApiName(); + + if (apiName == null || apiName.trim().isEmpty()) { + continue; + } + + String propertyName = RegistrationConstants.MOSIP_REGISTRATION + + apiName + + RegistrationConstants.DOT + + RegistrationConstants.FREQUENCY; + + String configuredValue = globalParamRepository.getCachedStringGlobalParam(propertyName); + + if (configuredValue != null && !configuredValue.trim().isEmpty() + && !configuredValue.equalsIgnoreCase("null")) { + jobsMap.put(jobId, configuredValue.trim()); + } + } + + return jobsMap; + } + + /** + * Calculates days since last sync. + * + * @param lastSyncDate Last sync date + * @return Days since last sync + */ + private int getActualDays(Date lastSyncDate) { + if (lastSyncDate == null) { + return 0; + } + + long millisecondsDifference = new Date().getTime() - lastSyncDate.getTime(); + long daysDifference = millisecondsDifference / (24 * 60 * 60 * 1000); + return (int) daysDifference; + } + + /** + * Validates machine distance from registration center. + * + * @param machineLongitude Machine longitude + * @param machineLatitude Machine latitude + * @throws ClientCheckedException if machine is outside allowed distance + */ + @Override + public void validateCenterToMachineDistance(Double machineLongitude, Double machineLatitude) throws Exception { + String enableFlag = globalParamRepository.getCachedStringGpsDeviceEnableFlag(); + if (enableFlag == null || !"Y".equalsIgnoreCase(enableFlag)) { + return; + } + + // If GPS is enabled, machine coordinates are required + if (machineLongitude == null || machineLatitude == null) { + Log.e(TAG, "GPS validation enabled but machine coordinates not available"); + throw new ClientCheckedException( + RegistrationConstants.OPT_TO_REG_OUTSIDE_LOCATION, + context.getString(R.string.err_003)); + } + + CenterMachineDto centerMachineDto = masterDataService.getRegistrationCenterMachineDetails(); + if (centerMachineDto == null) { + Log.e(TAG, "GPS validation enabled but center details not found"); + throw new ClientCheckedException(context, R.string.err_004); + } + + List centers = registrationCenterRepository.getRegistrationCenter( + centerMachineDto.getCenterId()); + + if (centers == null || centers.isEmpty()) { + Log.e(TAG, "GPS validation enabled but center not found"); + throw new ClientCheckedException(context, R.string.err_004); + } + + RegistrationCenter center = centers.get(0); + String centerLatStr = center.getLatitude(); + String centerLonStr = center.getLongitude(); + + if (centerLatStr == null || centerLonStr == null || + centerLatStr.isEmpty() || centerLonStr.isEmpty()) { + Log.e(TAG, "Center coordinates not available"); + throw new ClientCheckedException(context, R.string.err_004); + } + + try { + double centerLatitude = Double.parseDouble(centerLatStr); + double centerLongitude = Double.parseDouble(centerLonStr); + + double distanceKm = locationValidationService.getDistance( + machineLongitude, machineLatitude, + centerLongitude, centerLatitude); + + double distanceMeters = distanceKm * 1000; + + String maxDistanceStr = globalParamRepository.getCachedStringMachineToCenterDistance(); + if (maxDistanceStr == null || maxDistanceStr.isEmpty()) { + Log.e(TAG, "Max allowed distance configuration not found"); + throw new ClientCheckedException(context, R.string.err_004); + } + + double maxAllowedDistance = Double.parseDouble(maxDistanceStr); + + if (distanceMeters > maxAllowedDistance) { + Log.e(TAG, String.format( + "Distance validation failed - Machine: %.6f,%.6f | Center: %.6f,%.6f | Distance: %.2f m (limit: %.2f m)", + machineLatitude, machineLongitude, centerLatitude, centerLongitude, + distanceMeters, maxAllowedDistance)); + throw new ClientCheckedException( + RegistrationConstants.OPT_TO_REG_OUTSIDE_LOCATION, + context.getString(R.string.err_003)); + } + + } catch (NumberFormatException e) { + Log.e(TAG, "Invalid number format in center coordinates or max distance configuration", e); + throw new ClientCheckedException(context, R.string.err_004); + } + } + +} + diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java index 86e595448..3b33c4983 100644 --- a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/service/RegistrationServiceImpl.java @@ -70,6 +70,7 @@ import io.mosip.registration.clientmanager.spi.MasterDataService; import io.mosip.registration.clientmanager.spi.RegistrationService; import io.mosip.registration.clientmanager.spi.PacketService; +import io.mosip.registration.clientmanager.spi.PreCheckValidatorService; import io.mosip.registration.clientmanager.entity.PreRegistrationList; import io.mosip.registration.clientmanager.spi.PreRegistrationDataSyncService; import javax.inject.Provider; @@ -117,6 +118,7 @@ public class RegistrationServiceImpl implements RegistrationService { private LocationValidationService locationValidationService; private Provider preRegistrationDataSyncServiceProvider; private PacketService packetService; + private PreCheckValidatorService preCheckValidatorService; public static final String BOOLEAN_FALSE = "false"; private Biometrics095Service biometricService; @@ -134,7 +136,8 @@ public RegistrationServiceImpl(Context context, PacketWriterService packetWriter LocationValidationService locationValidationService, Provider preRegistrationDataSyncServiceProvider, Biometrics095Service biometricService, - PacketService packetService) { + PacketService packetService, + PreCheckValidatorService preCheckValidatorService) { this.context = context; this.registrationDto = null; this.packetWriterService = packetWriterService; @@ -150,6 +153,7 @@ public RegistrationServiceImpl(Context context, PacketWriterService packetWriter this.preRegistrationDataSyncServiceProvider = preRegistrationDataSyncServiceProvider; this.biometricService = biometricService; this.packetService = packetService; + this.preCheckValidatorService = preCheckValidatorService; } @Override @@ -163,7 +167,7 @@ public void rejectRegistration(Registration registration) { } @Override - public RegistrationDto startRegistration(@NonNull List languages, String flowType, String process) throws Exception { + public RegistrationDto startRegistration(@NonNull List languages, String flowType, String process, Double latitude, Double longitude) throws Exception { if (registrationDto != null) { registrationDto.cleanup(); } @@ -196,6 +200,16 @@ public RegistrationDto startRegistration(@NonNull List languages, String } this.registrationDto = new RegistrationDto(rid, flowType, process, version, languages, bioThresholds, rid); + this.registrationDto.setGeoLocation(longitude, latitude); + + // Validate GPS location if flag is enabled (even if coordinates are null) + try { + preCheckValidatorService.validateCenterToMachineDistance(longitude, latitude); + } catch (ClientCheckedException e) { + Log.e(TAG, "Location validation failed", e); + throw e; + } + SharedPreferences.Editor editor = this.context.getSharedPreferences(this.context.getString(R.string.app_name), Context.MODE_PRIVATE).edit(); editor.putString(SessionManager.RID, this.registrationDto.getRId()); @@ -218,9 +232,6 @@ public void submitRegistrationDto(String makerName) throws Exception { throw new ClientCheckedException(context, R.string.err_004); } - // Validate location before submission - validateLocation(); - if (this.registrationDto.getAdditionalInfoRequestId() != null) { String newAppId = this.registrationDto.getAdditionalInfoRequestId().split("-")[0]; this.registrationDto.setApplicationId(newAppId); @@ -529,88 +540,6 @@ private List> getLabelValueDTOListString(Map return labelValueMap; } - /** - * Validate machine location against registration center - * @throws Exception if location is outside allowed distance - */ - private void validateLocation() throws Exception { - try { - - String enableFlag = globalParamRepository.getCachedStringGpsDeviceEnableFlag(); - boolean gpsValidationDisabled = "Y".equalsIgnoreCase(enableFlag); - if (gpsValidationDisabled) { - Log.w(TAG, "GPS distance validation disabled by config, skipping"); - return; - } - - GeoLocationDto geoLocation = this.registrationDto.getGeoLocationDto(); - if (geoLocation == null) { - Log.w(TAG, "Geo location not available, skipping validation"); - return; - } - - // Get center coordinates - CenterMachineDto centerMachineDto = masterDataService.getRegistrationCenterMachineDetails(); - if (centerMachineDto == null) { - Log.w(TAG, "Center details not found, skipping distance validation"); - return; - } - - List centers = registrationCenterRepository.getRegistrationCenter( - centerMachineDto.getCenterId()); - - if (centers == null || centers.isEmpty()) { - Log.w(TAG, "Center not found, skipping distance validation"); - return; - } - - RegistrationCenter center = centers.get(0); - String centerLatStr = center.getLatitude(); - String centerLonStr = center.getLongitude(); - - if (centerLatStr == null || centerLonStr == null || - centerLatStr.isEmpty() || centerLonStr.isEmpty()) { - Log.e(TAG, "Center coordinates not available"); - throw new ClientCheckedException(context, R.string.err_004); - } - - try { - double centerLatitude = Double.parseDouble(centerLatStr); - double centerLongitude = Double.parseDouble(centerLonStr); - - // Calculate distance - double distance = locationValidationService.getDistance( - geoLocation.getLongitude(), geoLocation.getLatitude(), - centerLongitude, centerLatitude); - - // Get max allowed distance from config - String maxDistanceStr = globalParamRepository.getCachedStringMachineToCenterDistance(); - if (maxDistanceStr == null || maxDistanceStr.isEmpty()) { - Log.e(TAG, "Max allowed distance configuration not found"); - throw new ClientCheckedException(context, R.string.err_004); - } - - double maxAllowedDistance = Double.parseDouble(maxDistanceStr); - - // Validate distance - if (distance > maxAllowedDistance) { - Log.e(TAG, "Distance not matched with allowed range"); - throw new ClientCheckedException(context, R.string.err_004); - } - - Log.i(TAG, "Location validated successfully"); - - } catch (NumberFormatException e) { - Log.e(TAG, "Invalid center coordinates format", e); - // Continue with submission even if coordinates are invalid - } - } catch (ClientCheckedException e) { - throw e; - } catch (Exception e) { - Log.e(TAG, "Location validation failed: " + e.getMessage(), e); - // Continue with submission even if validation fails - } - } public List> getAudits() { List> audits = new ArrayList<>(); @@ -653,6 +582,9 @@ private void doPreChecksBeforeRegistration(CenterMachineDto centerMachineDto) th if (centerMachineDto == null || !centerMachineDto.getCenterStatus() || !centerMachineDto.getMachineStatus()) throw new ClientCheckedException(context, R.string.err_007); + // validate sync status - checks if all sync jobs ran within configured time limits + preCheckValidatorService.validateSyncStatus(); + // registered packet approval time breach check if (packetService != null && packetService.isRegisteredPacketApprovalTimeBreached()) { throw new ClientCheckedException("PAK_APPRVL_MAX_TIME"); diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/spi/PreCheckValidatorService.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/spi/PreCheckValidatorService.java new file mode 100644 index 000000000..27bd203d5 --- /dev/null +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/spi/PreCheckValidatorService.java @@ -0,0 +1,27 @@ +package io.mosip.registration.clientmanager.spi; + +/** + * Validates pre-check requirements (sync status and GPS location). + * + * @author Sachin S P + */ +public interface PreCheckValidatorService { + + /** + * Validates sync job frequencies. + * + * @throws Exception if validation fails + */ + void validateSyncStatus() throws Exception; + + /** + * Validates machine distance from registration center using GPS. + * Validation is skipped if GPS is disabled. If GPS is enabled, both coordinates must be non-null. + * + * @param machineLongitude Machine longitude (required if GPS enabled) + * @param machineLatitude Machine latitude (required if GPS enabled) + * @throws Exception if GPS is enabled and coordinates are null, or if machine is outside allowed distance + */ + void validateCenterToMachineDistance(Double machineLongitude, Double machineLatitude) throws Exception; +} + diff --git a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/spi/RegistrationService.java b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/spi/RegistrationService.java index 79daf9996..c7cb1680f 100644 --- a/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/spi/RegistrationService.java +++ b/android/clientmanager/src/main/java/io/mosip/registration/clientmanager/spi/RegistrationService.java @@ -13,7 +13,7 @@ public interface RegistrationService { void rejectRegistration(Registration registration); - RegistrationDto startRegistration(List languages, String flowType, String process) throws Exception; + RegistrationDto startRegistration(List languages, String flowType, String process, Double latitude, Double longitude) throws Exception; RegistrationDto getRegistrationDto() throws Exception; diff --git a/android/clientmanager/src/main/res/values/strings.xml b/android/clientmanager/src/main/res/values/strings.xml index fdcc03d4e..fe2c3a94c 100644 --- a/android/clientmanager/src/main/res/values/strings.xml +++ b/android/clientmanager/src/main/res/values/strings.xml @@ -10,6 +10,7 @@ Language is mandatory to begin registration Required master data not found No Schema found + Your client machine location is outside the registration center. Please note that registration can be done only from within the registration center Registration not started ! Failed to create registration packet Minimum required space is not available diff --git a/android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImplTest.java b/android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImplTest.java new file mode 100644 index 000000000..358aa4672 --- /dev/null +++ b/android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/PreCheckValidatorServiceImplTest.java @@ -0,0 +1,565 @@ +package io.mosip.registration.clientmanager.service; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import android.content.Context; +import android.content.SharedPreferences; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnitRunner; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.mosip.registration.clientmanager.R; +import io.mosip.registration.clientmanager.constant.RegistrationConstants; +import io.mosip.registration.clientmanager.dto.CenterMachineDto; +import io.mosip.registration.clientmanager.entity.RegistrationCenter; +import io.mosip.registration.clientmanager.entity.SyncJobDef; +import io.mosip.registration.clientmanager.exception.ClientCheckedException; +import io.mosip.registration.clientmanager.repository.GlobalParamRepository; +import io.mosip.registration.clientmanager.repository.RegistrationCenterRepository; +import io.mosip.registration.clientmanager.repository.SyncJobDefRepository; +import io.mosip.registration.clientmanager.spi.JobManagerService; +import io.mosip.registration.clientmanager.spi.JobTransactionService; +import io.mosip.registration.clientmanager.spi.LocationValidationService; +import io.mosip.registration.clientmanager.spi.MasterDataService; + +/** + * Unit tests for PreCheckValidatorServiceImpl. + * + * @author Sachin S P + */ +@RunWith(MockitoJUnitRunner.class) +public class PreCheckValidatorServiceImplTest { + + @Mock + private Context mockContext; + + @Mock + private SyncJobDefRepository mockSyncJobDefRepository; + + @Mock + private GlobalParamRepository mockGlobalParamRepository; + + @Mock + private JobManagerService mockJobManagerService; + + @Mock + private JobTransactionService mockJobTransactionService; + + @Mock + private LocationValidationService mockLocationValidationService; + + @Mock + private MasterDataService mockMasterDataService; + + @Mock + private RegistrationCenterRepository mockRegistrationCenterRepository; + + @Mock + private SharedPreferences mockSharedPreferences; + + @Mock + private SharedPreferences.Editor mockEditor; + + @InjectMocks + private PreCheckValidatorServiceImpl preCheckValidatorService; + + private static final String JOB_ID_1 = "MDS_J00001"; + private static final String JOB_ID_2 = "PDS_J00003"; + private static final String API_NAME_1 = "masterSyncJob"; + private static final String API_NAME_2 = "preRegistrationDataSyncJob"; + private static final String CENTER_ID = "CENTER_001"; + private static final int SERVICE_JOB_ID_1 = 1; + private static final int SERVICE_JOB_ID_2 = 3; + + @Before + public void setUp() { + MockitoAnnotations.openMocks(this); + when(mockContext.getString(R.string.app_name)).thenReturn("RegistrationClient"); + when(mockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mockSharedPreferences); + when(mockSharedPreferences.edit()).thenReturn(mockEditor); + when(mockEditor.putLong(anyString(), anyLong())).thenReturn(mockEditor); + } + + // ========== validateSyncStatus() Tests ========== + + @Test + public void testValidateSyncStatus_Success_AllJobsWithinLimit() throws Exception { + // Setup: Create active jobs + List activeJobs = createActiveJobs(); + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(activeJobs); + + // Setup: Configure frequencies + when(mockGlobalParamRepository.getCachedStringGlobalParam( + RegistrationConstants.MOSIP_REGISTRATION + API_NAME_1 + RegistrationConstants.DOT + RegistrationConstants.FREQUENCY)) + .thenReturn("190"); + when(mockGlobalParamRepository.getCachedStringGlobalParam( + RegistrationConstants.MOSIP_REGISTRATION + API_NAME_2 + RegistrationConstants.DOT + RegistrationConstants.FREQUENCY)) + .thenReturn("190"); + + // Setup: Last sync times (within limit - 1 day ago) + when(mockJobManagerService.generateJobServiceId(JOB_ID_1)).thenReturn(SERVICE_JOB_ID_1); + when(mockJobManagerService.generateJobServiceId(JOB_ID_2)).thenReturn(SERVICE_JOB_ID_2); + + long oneDayAgo = System.currentTimeMillis() - (24 * 60 * 60 * 1000L); + when(mockJobTransactionService.getLastSyncTime(SERVICE_JOB_ID_1)).thenReturn(oneDayAgo); + when(mockJobTransactionService.getLastSyncTime(SERVICE_JOB_ID_2)).thenReturn(oneDayAgo); + + // Execute + preCheckValidatorService.validateSyncStatus(); + + // Verify: No exception thrown + verify(mockSyncJobDefRepository).getActiveSyncJobs(); + } + + @Test(expected = ClientCheckedException.class) + public void testValidateSyncStatus_Failure_JobOverdue() throws Exception { + // Setup: Create active jobs + List activeJobs = createActiveJobs(); + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(activeJobs); + + // Setup: Configure frequency (1 day limit) + when(mockGlobalParamRepository.getCachedStringGlobalParam( + RegistrationConstants.MOSIP_REGISTRATION + API_NAME_1 + RegistrationConstants.DOT + RegistrationConstants.FREQUENCY)) + .thenReturn("1"); + + // Setup: Last sync time (2 days ago - overdue) + when(mockJobManagerService.generateJobServiceId(JOB_ID_1)).thenReturn(SERVICE_JOB_ID_1); + long twoDaysAgo = System.currentTimeMillis() - (2 * 24 * 60 * 60 * 1000L); + when(mockJobTransactionService.getLastSyncTime(SERVICE_JOB_ID_1)).thenReturn(twoDaysAgo); + + // Execute - should throw exception + preCheckValidatorService.validateSyncStatus(); + } + + @Test + public void testValidateSyncStatus_NoActiveJobs() throws Exception { + // Setup: No active jobs + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(new ArrayList<>()); + + // Execute + preCheckValidatorService.validateSyncStatus(); + + // Verify: No exception, validation skipped + verify(mockSyncJobDefRepository).getActiveSyncJobs(); + } + + @Test + public void testValidateSyncStatus_JobWithoutSyncHistory_Skipped() throws Exception { + // Setup: Create active jobs + List activeJobs = createActiveJobs(); + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(activeJobs); + + // Setup: Configure frequency + when(mockGlobalParamRepository.getCachedStringGlobalParam( + RegistrationConstants.MOSIP_REGISTRATION + API_NAME_1 + RegistrationConstants.DOT + RegistrationConstants.FREQUENCY)) + .thenReturn("190"); + + // Setup: No sync history (returns 0) - job should be skipped + when(mockJobManagerService.generateJobServiceId(JOB_ID_1)).thenReturn(SERVICE_JOB_ID_1); + when(mockJobTransactionService.getLastSyncTime(SERVICE_JOB_ID_1)).thenReturn(0L); + + // Execute - should not throw exception, job without history is skipped + preCheckValidatorService.validateSyncStatus(); + + // Verify: No exception - job without history is skipped + verify(mockSyncJobDefRepository).getActiveSyncJobs(); + } + + @Test + public void testValidateSyncStatus_NoFrequencyConfigured_Skipped() throws Exception { + // Setup: Create active jobs + List activeJobs = createActiveJobs(); + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(activeJobs); + + // Setup: No frequency configured (returns null) + when(mockGlobalParamRepository.getCachedStringGlobalParam(anyString())).thenReturn(null); + + // Execute + preCheckValidatorService.validateSyncStatus(); + + // Verify: No exception - job without frequency is skipped + verify(mockSyncJobDefRepository).getActiveSyncJobs(); + } + + @Test(expected = ClientCheckedException.class) + public void testValidateSyncStatus_MultipleJobsOverdue() throws Exception { + // Setup: Create multiple active jobs + List activeJobs = new ArrayList<>(); + SyncJobDef job1 = new SyncJobDef(); + job1.setId(JOB_ID_1); + job1.setApiName(API_NAME_1); + job1.setIsActive(true); + + SyncJobDef job2 = new SyncJobDef(); + job2.setId(JOB_ID_2); + job2.setApiName(API_NAME_2); + job2.setIsActive(true); + + activeJobs.add(job1); + activeJobs.add(job2); + + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(activeJobs); + + // Setup: Configure frequencies (1 day limit) + when(mockGlobalParamRepository.getCachedStringGlobalParam( + RegistrationConstants.MOSIP_REGISTRATION + API_NAME_1 + RegistrationConstants.DOT + RegistrationConstants.FREQUENCY)) + .thenReturn("1"); + when(mockGlobalParamRepository.getCachedStringGlobalParam( + RegistrationConstants.MOSIP_REGISTRATION + API_NAME_2 + RegistrationConstants.DOT + RegistrationConstants.FREQUENCY)) + .thenReturn("1"); + + // Setup: Both jobs overdue (2 days ago) + when(mockJobManagerService.generateJobServiceId(JOB_ID_1)).thenReturn(SERVICE_JOB_ID_1); + when(mockJobManagerService.generateJobServiceId(JOB_ID_2)).thenReturn(SERVICE_JOB_ID_2); + + long twoDaysAgo = System.currentTimeMillis() - (2 * 24 * 60 * 60 * 1000L); + when(mockJobTransactionService.getLastSyncTime(SERVICE_JOB_ID_1)).thenReturn(twoDaysAgo); + when(mockJobTransactionService.getLastSyncTime(SERVICE_JOB_ID_2)).thenReturn(twoDaysAgo); + + // Execute - should throw exception + try { + preCheckValidatorService.validateSyncStatus(); + } catch (ClientCheckedException e) { + // Verify error code + assertEquals(RegistrationConstants.OPT_TO_REG_TIME_SYNC_EXCEED, e.getErrorCode()); + assertTrue(e.getMessage().contains("2 sync job(s) are overdue")); + throw e; + } + } + + // ========== validateCenterToMachineDistance() Tests ========== + + @Test + public void testValidateCenterToMachineDistance_GPSDisabled_Skipped() throws Exception { + // Setup: GPS validation disabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("Y"); + + // Execute + preCheckValidatorService.validateCenterToMachineDistance(77.5946, 12.9716); + + // Verify: Validation skipped + verify(mockGlobalParamRepository).getCachedStringGpsDeviceEnableFlag(); + verify(mockLocationValidationService, never()).getDistance(anyDouble(), anyDouble(), anyDouble(), anyDouble()); + } + + @Test + public void testValidateCenterToMachineDistance_LocationNull_Skipped() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("N"); + + // Execute with null location + preCheckValidatorService.validateCenterToMachineDistance(null, null); + + // Verify: Validation skipped + verify(mockLocationValidationService, never()).getDistance(anyDouble(), anyDouble(), anyDouble(), anyDouble()); + } + + @Test + public void testValidateCenterToMachineDistance_WithinDistance_Success() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("N"); + + // Setup: Center details + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId(CENTER_ID); + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + + RegistrationCenter center = new RegistrationCenter(); + center.setId(CENTER_ID); + center.setLangCode("eng"); + center.setLatitude("12.9716"); + center.setLongitude("77.5946"); + List centers = new ArrayList<>(); + centers.add(center); + when(mockRegistrationCenterRepository.getRegistrationCenter(CENTER_ID)).thenReturn(centers); + + // Setup: Distance calculation (within limit - 100 meters) + when(mockLocationValidationService.getDistance(78.5946, 13.9716, 77.5946, 12.9716)) + .thenReturn(0.1); // 0.1 km = 100 meters + + // Setup: Max allowed distance (500 meters) + when(mockGlobalParamRepository.getCachedStringMachineToCenterDistance()).thenReturn("500"); + + // Execute + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + + // Verify: No exception thrown + verify(mockLocationValidationService).getDistance(78.5946, 13.9716, 77.5946, 12.9716); + } + + @Test(expected = ClientCheckedException.class) + public void testValidateCenterToMachineDistance_OutsideDistance_ThrowsException() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("N"); + + // Setup: Center details + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId(CENTER_ID); + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + + RegistrationCenter center = new RegistrationCenter(); + center.setId(CENTER_ID); + center.setLangCode("eng"); + center.setLatitude("12.9716"); + center.setLongitude("77.5946"); + List centers = new ArrayList<>(); + centers.add(center); + when(mockRegistrationCenterRepository.getRegistrationCenter(CENTER_ID)).thenReturn(centers); + + // Setup: Distance calculation (outside limit - 1000 meters) + when(mockLocationValidationService.getDistance(78.5946, 13.9716, 77.5946, 12.9716)) + .thenReturn(1.0); // 1.0 km = 1000 meters + + // Setup: Max allowed distance (500 meters) + when(mockGlobalParamRepository.getCachedStringMachineToCenterDistance()).thenReturn("500"); + + // Execute - should throw exception + try { + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + } catch (ClientCheckedException e) { + // Verify error code + assertEquals(RegistrationConstants.OPT_TO_REG_OUTSIDE_LOCATION, e.getErrorCode()); + throw e; + } + } + + @Test(expected = ClientCheckedException.class) + public void testValidateCenterToMachineDistance_CenterDetailsNotFound_ThrowsException() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("Y"); + + // Setup: Center details not found + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(null); + + // Execute - should throw exception + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + } + + @Test(expected = ClientCheckedException.class) + public void testValidateCenterToMachineDistance_CenterNotFound_ThrowsException() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("Y"); + + // Setup: Center details found but center not found in repository + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId(CENTER_ID); + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + when(mockRegistrationCenterRepository.getRegistrationCenter(CENTER_ID)).thenReturn(null); + + // Execute - should throw exception + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + } + + @Test(expected = ClientCheckedException.class) + public void testValidateCenterToMachineDistance_EmptyCentersList_ThrowsException() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("Y"); + + // Setup: Center details found but empty centers list + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId(CENTER_ID); + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + when(mockRegistrationCenterRepository.getRegistrationCenter(CENTER_ID)).thenReturn(new ArrayList<>()); + + // Execute - should throw exception + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + } + + @Test(expected = ClientCheckedException.class) + public void testValidateCenterToMachineDistance_CenterCoordinatesMissing_ThrowsException() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("N"); + + // Setup: Center details + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId(CENTER_ID); + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + + RegistrationCenter center = new RegistrationCenter(); + center.setLatitude(null); // Missing coordinates + center.setLongitude(null); + List centers = new ArrayList<>(); + centers.add(center); + when(mockRegistrationCenterRepository.getRegistrationCenter(CENTER_ID)).thenReturn(centers); + + // Execute - should throw exception + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + } + + @Test(expected = ClientCheckedException.class) + public void testValidateCenterToMachineDistance_MaxDistanceConfigMissing_ThrowsException() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("N"); + + // Setup: Center details + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId(CENTER_ID); + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + + RegistrationCenter center = new RegistrationCenter(); + center.setId(CENTER_ID); + center.setLangCode("eng"); + center.setLatitude("12.9716"); + center.setLongitude("77.5946"); + List centers = new ArrayList<>(); + centers.add(center); + when(mockRegistrationCenterRepository.getRegistrationCenter(CENTER_ID)).thenReturn(centers); + + // Setup: Distance calculation + when(mockLocationValidationService.getDistance(78.5946, 13.9716, 77.5946, 12.9716)) + .thenReturn(0.1); + + // Setup: Max distance config missing + when(mockGlobalParamRepository.getCachedStringMachineToCenterDistance()).thenReturn(null); + + // Execute - should throw exception + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + } + + @Test + public void testValidateCenterToMachineDistance_InvalidCoordinateFormat_ThrowsException() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("N"); + + // Setup: Center details + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId(CENTER_ID); + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + + RegistrationCenter center = new RegistrationCenter(); + center.setId(CENTER_ID); + center.setLangCode("eng"); + center.setLatitude("invalid"); // Invalid format + center.setLongitude("77.5946"); + List centers = new ArrayList<>(); + centers.add(center); + when(mockRegistrationCenterRepository.getRegistrationCenter(CENTER_ID)).thenReturn(centers); + + // Execute - should throw exception + try { + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + fail("Expected ClientCheckedException for invalid coordinate format"); + } catch (ClientCheckedException e) { + // Expected + } + } + + @Test + public void testValidateSyncStatus_JobWithNullId_Skipped() throws Exception { + // Setup: Create job with null ID + List activeJobs = new ArrayList<>(); + SyncJobDef job = new SyncJobDef(); + job.setId(null); + job.setApiName(API_NAME_1); + job.setIsActive(true); + activeJobs.add(job); + + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(activeJobs); + + // Execute + preCheckValidatorService.validateSyncStatus(); + + // Verify: No exception, job skipped + verify(mockSyncJobDefRepository).getActiveSyncJobs(); + } + + @Test + public void testValidateSyncStatus_JobWithNullApiName_Skipped() throws Exception { + // Setup: Create job with null apiName + List activeJobs = new ArrayList<>(); + SyncJobDef job = new SyncJobDef(); + job.setId(JOB_ID_1); + job.setApiName(null); + job.setIsActive(true); + activeJobs.add(job); + + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(activeJobs); + + // Execute + preCheckValidatorService.validateSyncStatus(); + + // Verify: No exception, job skipped + verify(mockSyncJobDefRepository).getActiveSyncJobs(); + } + + @Test(expected = ClientCheckedException.class) + public void testValidateSyncStatus_InvalidFrequencyValue_ThrowsException() throws Exception { + // Setup: Create active jobs + List activeJobs = createActiveJobs(); + when(mockSyncJobDefRepository.getActiveSyncJobs()).thenReturn(activeJobs); + + // Setup: Invalid frequency value (non-numeric) + when(mockGlobalParamRepository.getCachedStringGlobalParam( + RegistrationConstants.MOSIP_REGISTRATION + API_NAME_1 + RegistrationConstants.DOT + RegistrationConstants.FREQUENCY)) + .thenReturn("invalid"); + + // Execute - should throw exception due to invalid frequency value + preCheckValidatorService.validateSyncStatus(); + } + + @Test + public void testValidateCenterToMachineDistance_ExactDistanceLimit_Passes() throws Exception { + // Setup: GPS enabled + when(mockGlobalParamRepository.getCachedStringGpsDeviceEnableFlag()).thenReturn("N"); + + // Setup: Center details + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId(CENTER_ID); + when(mockMasterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + + RegistrationCenter center = new RegistrationCenter(); + center.setId(CENTER_ID); + center.setLangCode("eng"); + center.setLatitude("12.9716"); + center.setLongitude("77.5946"); + List centers = new ArrayList<>(); + centers.add(center); + when(mockRegistrationCenterRepository.getRegistrationCenter(CENTER_ID)).thenReturn(centers); + + // Setup: Distance exactly at limit (500 meters) + when(mockLocationValidationService.getDistance(78.5946, 13.9716, 77.5946, 12.9716)) + .thenReturn(0.5); // 0.5 km = 500 meters + + // Setup: Max allowed distance (500 meters) + when(mockGlobalParamRepository.getCachedStringMachineToCenterDistance()).thenReturn("500"); + + // Execute - should pass (distance == limit, not > limit) + preCheckValidatorService.validateCenterToMachineDistance(78.5946, 13.9716); + + // Verify: No exception thrown + verify(mockLocationValidationService).getDistance(78.5946, 13.9716, 77.5946, 12.9716); + } + + // ========== Helper Methods ========== + + private List createActiveJobs() { + List jobs = new ArrayList<>(); + + SyncJobDef job1 = new SyncJobDef(); + job1.setId(JOB_ID_1); + job1.setApiName(API_NAME_1); + job1.setIsActive(true); + jobs.add(job1); + + SyncJobDef job2 = new SyncJobDef(); + job2.setId(JOB_ID_2); + job2.setApiName(API_NAME_2); + job2.setIsActive(true); + jobs.add(job2); + + return jobs; + } +} + diff --git a/android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/RegistrationServiceImplTest.java b/android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/RegistrationServiceImplTest.java index d9417cb2f..6d07b46b1 100644 --- a/android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/RegistrationServiceImplTest.java +++ b/android/clientmanager/src/test/java/io/mosip/registration/clientmanager/service/RegistrationServiceImplTest.java @@ -20,6 +20,7 @@ import io.mosip.registration.clientmanager.spi.PacketService; import io.mosip.registration.clientmanager.spi.PreRegistrationDataSyncService; import io.mosip.registration.clientmanager.spi.RegistrationService; +import io.mosip.registration.clientmanager.spi.PreCheckValidatorService; import io.mosip.registration.keymanager.repository.KeyStoreRepository; import io.mosip.registration.keymanager.spi.ClientCryptoManagerService; import io.mosip.registration.packetmanager.spi.PacketWriterService; @@ -61,6 +62,7 @@ import static org.mockito.ArgumentMatchers.anyDouble; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -102,6 +104,8 @@ public class RegistrationServiceImplTest { private PreRegistrationDataSyncService preRegistrationDataSyncService; @Mock private PacketService packetService; + @Mock + private PreCheckValidatorService preCheckValidatorService; @Before public void setUp() { @@ -113,7 +117,7 @@ public void setUp() { when(preRegistrationDataSyncServiceProvider.get()).thenReturn(preRegistrationDataSyncService); registrationService = new RegistrationServiceImpl(mockApplicationContext, packetWriterService, registrationRepository, masterDataService, identitySchemaRepository, clientCryptoManagerService, - keyStoreRepository, globalParamRepository, auditManagerService,registrationCenterRepository,locationValidationService, preRegistrationDataSyncServiceProvider, biometricService, packetService); + keyStoreRepository, globalParamRepository, auditManagerService,registrationCenterRepository,locationValidationService, preRegistrationDataSyncServiceProvider, biometricService, packetService, preCheckValidatorService); } @Test(expected = ClientCheckedException.class) @@ -138,7 +142,7 @@ public void getRegistrationDtoAfterStartingRegistration() throws Exception { File mockFile = mock(File.class); when(mockFile.getUsableSpace()).thenReturn(100l*(1024 * 1024)); when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); - RegistrationDto registrationDto = registrationService.startRegistration(Arrays.asList("eng"), "NEW", "NEW"); + RegistrationDto registrationDto = registrationService.startRegistration(Arrays.asList("eng"), "NEW", "NEW", null, null); RegistrationDto result = registrationService.getRegistrationDto(); Assert.assertNotNull(registrationDto); @@ -172,7 +176,7 @@ public void startAndSubmitRegistration() throws Exception { when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); List selectedLanguages = new ArrayList<>(); selectedLanguages.add("eng"); - RegistrationDto registrationDto = registrationService.startRegistration(selectedLanguages, "NEW", "NEW"); + RegistrationDto registrationDto = registrationService.startRegistration(selectedLanguages, "NEW", "NEW", null, null); RegistrationDto result = registrationService.getRegistrationDto(); Assert.assertNotNull(registrationDto); @@ -200,7 +204,7 @@ public void startAndSubmitRegistration() throws Exception { public void startRegistrationWithoutMasterSync_throwException() throws Exception { List selectedLanguages = new ArrayList<>(); selectedLanguages.add("eng"); - registrationService.startRegistration(selectedLanguages, "NEW", "NEW"); + registrationService.startRegistration(selectedLanguages, "NEW", "NEW", null, null); } @Test(expected = ClientCheckedException.class) @@ -215,7 +219,7 @@ public void startRegistrationWithoutIDSchema_throwException() throws Exception { centerMachineDto.setMachineStatus(true); centerMachineDto.setMachineRefId("10001_110001"); when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); - registrationService.startRegistration(selectedLanguages, "NEW", "NEW"); + registrationService.startRegistration(selectedLanguages, "NEW", "NEW", null, null); } @Test(expected = ClientCheckedException.class) @@ -232,7 +236,7 @@ public void startRegistrationWithoutPolicyKey_throwException() throws Exception when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.4); when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn(null); - registrationService.startRegistration(selectedLanguages, "NEW", "NEW"); + registrationService.startRegistration(selectedLanguages, "NEW", "NEW", null, null); } @Test(expected = ClientCheckedException.class) @@ -249,7 +253,7 @@ public void startRegistrationInactiveCenter_throwException() throws Exception { when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.4); when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn(null); - registrationService.startRegistration(selectedLanguages, "NEW", "NEW"); + registrationService.startRegistration(selectedLanguages, "NEW", "NEW", null, null); } @Test(expected = ClientCheckedException.class) @@ -266,7 +270,7 @@ public void startRegistrationInactiveMachine_throwException() throws Exception { when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.4); when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn(null); - registrationService.startRegistration(selectedLanguages, "NEW", "NEW"); + registrationService.startRegistration(selectedLanguages, "NEW", "NEW", null, null); } @Test(expected = ClientCheckedException.class) @@ -287,7 +291,7 @@ public void clearRegistration() throws Exception { when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); List languages = new ArrayList<>(); languages.add("eng"); - RegistrationDto registrationDto = registrationService.startRegistration(languages, "NEW", "NEW"); + RegistrationDto registrationDto = registrationService.startRegistration(languages, "NEW", "NEW", null, null); RegistrationDto result = registrationService.getRegistrationDto(); Assert.assertNotNull(registrationDto); @@ -346,7 +350,7 @@ public void testGetAdditionalInfo_StringAndList() throws Exception { when(mockFile.getUsableSpace()).thenReturn(100L * (1024 * 1024)); when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); - registrationService.startRegistration(new ArrayList<>(Collections.singletonList("eng")), "NEW", "NEW"); + registrationService.startRegistration(new ArrayList<>(Collections.singletonList("eng")), "NEW", "NEW", null, null); Method setRegistrationDto = registrationService.getClass().getDeclaredMethod("getRegistrationDto"); setRegistrationDto.setAccessible(true); @@ -1166,7 +1170,7 @@ public void testStartRegistration_CleanupCalled() throws Exception { when(mockFile.getUsableSpace()).thenReturn(100L * (1024 * 1024)); when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); - RegistrationDto result = registrationService.startRegistration(languages, "NEW", "NEW"); + RegistrationDto result = registrationService.startRegistration(languages, "NEW", "NEW", null, null); assertNotNull(result); // cleanup() should have been called on dummyDto Mockito.verify(dummyDto).cleanup(); @@ -1846,4 +1850,195 @@ public void testDoPreChecksBeforeRegistration_NullCenterMachineDto() throws Exce assertTrue(cause instanceof ClientCheckedException); } } + + // ========== GPS Location Validation in startRegistration() Tests ========== + + @Test + public void testStartRegistration_WithNullGPS_Success() throws Exception { + // Setup + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId("10001"); + centerMachineDto.setMachineId("110001"); + centerMachineDto.setCenterStatus(true); + centerMachineDto.setMachineStatus(true); + centerMachineDto.setMachineRefId("10001_110001"); + when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.3); + when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn("dummy_cert"); + when(globalParamRepository.getCachedIntegerGlobalParam(Mockito.anyString())).thenReturn(3); + File mockFile = mock(File.class); + when(mockFile.getUsableSpace()).thenReturn(100L * (1024 * 1024)); + when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); + + // Execute with null GPS + RegistrationDto result = registrationService.startRegistration( + Arrays.asList("eng"), "NEW", "NEW", null, null); + + // Verify: Registration succeeds, no validation called + assertNotNull(result); + assertNull(result.getGeoLocationDto()); + verify(preCheckValidatorService, never()).validateCenterToMachineDistance(any(), any()); + } + + @Test + public void testStartRegistration_WithGPS_ValidationPasses_Success() throws Exception { + // Setup + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId("10001"); + centerMachineDto.setMachineId("110001"); + centerMachineDto.setCenterStatus(true); + centerMachineDto.setMachineStatus(true); + centerMachineDto.setMachineRefId("10001_110001"); + when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.3); + when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn("dummy_cert"); + when(globalParamRepository.getCachedIntegerGlobalParam(Mockito.anyString())).thenReturn(3); + File mockFile = mock(File.class); + when(mockFile.getUsableSpace()).thenReturn(100L * (1024 * 1024)); + when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); + + // Setup: Validation passes (no exception thrown) + // Note: PreCheckValidatorService.validateCenterToMachineDistance doesn't throw when validation passes + + // Execute with GPS coordinates + Double latitude = 12.9716; + Double longitude = 77.5946; + RegistrationDto result = registrationService.startRegistration( + Arrays.asList("eng"), "NEW", "NEW", latitude, longitude); + + // Verify: Registration succeeds, GPS set, validation called + assertNotNull(result); + assertNotNull(result.getGeoLocationDto()); + assertEquals(latitude, result.getGeoLocationDto().getLatitude(), 0.0001); + assertEquals(longitude, result.getGeoLocationDto().getLongitude(), 0.0001); + verify(preCheckValidatorService).validateCenterToMachineDistance(longitude, latitude); + } + + @Test(expected = ClientCheckedException.class) + public void testStartRegistration_WithGPS_ValidationFails_ThrowsException() throws Exception { + // Setup + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId("10001"); + centerMachineDto.setMachineId("110001"); + centerMachineDto.setCenterStatus(true); + centerMachineDto.setMachineStatus(true); + centerMachineDto.setMachineRefId("10001_110001"); + when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.3); + when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn("dummy_cert"); + when(globalParamRepository.getCachedIntegerGlobalParam(Mockito.anyString())).thenReturn(3); + File mockFile = mock(File.class); + when(mockFile.getUsableSpace()).thenReturn(100L * (1024 * 1024)); + when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); + + // Setup: Validation fails - throw exception + Double latitude = 13.9716; + Double longitude = 78.5946; + ClientCheckedException validationException = new ClientCheckedException( + mockApplicationContext, android.R.string.unknownName, "OPT_TO_REG_OUTSIDE_LOCATION"); + Mockito.doThrow(validationException).when(preCheckValidatorService) + .validateCenterToMachineDistance(longitude, latitude); + + // Execute - should throw exception + try { + registrationService.startRegistration( + Arrays.asList("eng"), "NEW", "NEW", latitude, longitude); + } catch (ClientCheckedException e) { + // Verify: Validation was called + verify(preCheckValidatorService).validateCenterToMachineDistance(longitude, latitude); + throw e; + } + } + + @Test + public void testStartRegistration_WithGPS_SyncValidatorNull_SkipsValidation() throws Exception { + // Setup: Create service without PreCheckValidatorService (null) + RegistrationService serviceWithoutValidator = new RegistrationServiceImpl( + mockApplicationContext, packetWriterService, + registrationRepository, masterDataService, identitySchemaRepository, + clientCryptoManagerService, keyStoreRepository, globalParamRepository, + auditManagerService, registrationCenterRepository, locationValidationService, + preRegistrationDataSyncServiceProvider, biometricService, packetService, null); + + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId("10001"); + centerMachineDto.setMachineId("110001"); + centerMachineDto.setCenterStatus(true); + centerMachineDto.setMachineStatus(true); + centerMachineDto.setMachineRefId("10001_110001"); + when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.3); + when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn("dummy_cert"); + when(globalParamRepository.getCachedIntegerGlobalParam(Mockito.anyString())).thenReturn(3); + File mockFile = mock(File.class); + when(mockFile.getUsableSpace()).thenReturn(100L * (1024 * 1024)); + when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); + + // Execute with GPS but validator is null + Double latitude = 12.9716; + Double longitude = 77.5946; + RegistrationDto result = serviceWithoutValidator.startRegistration( + Arrays.asList("eng"), "NEW", "NEW", latitude, longitude); + + // Verify: Registration succeeds, GPS set, no validation exception + assertNotNull(result); + assertNotNull(result.getGeoLocationDto()); + assertEquals(latitude, result.getGeoLocationDto().getLatitude(), 0.0001); + assertEquals(longitude, result.getGeoLocationDto().getLongitude(), 0.0001); + // PreCheckValidatorService is null, so validation should be skipped + } + + @Test + public void testStartRegistration_WithGPS_LatitudeNull_SkipsValidation() throws Exception { + // Setup + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId("10001"); + centerMachineDto.setMachineId("110001"); + centerMachineDto.setCenterStatus(true); + centerMachineDto.setMachineStatus(true); + centerMachineDto.setMachineRefId("10001_110001"); + when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.3); + when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn("dummy_cert"); + when(globalParamRepository.getCachedIntegerGlobalParam(Mockito.anyString())).thenReturn(3); + File mockFile = mock(File.class); + when(mockFile.getUsableSpace()).thenReturn(100L * (1024 * 1024)); + when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); + + // Execute with null latitude (partial GPS) + RegistrationDto result = registrationService.startRegistration( + Arrays.asList("eng"), "NEW", "NEW", null, 77.5946); + + // Verify: Registration succeeds, no GPS set, no validation called + assertNotNull(result); + assertNull(result.getGeoLocationDto()); + verify(preCheckValidatorService, never()).validateCenterToMachineDistance(any(), any()); + } + + @Test + public void testStartRegistration_WithGPS_LongitudeNull_SkipsValidation() throws Exception { + // Setup + CenterMachineDto centerMachineDto = new CenterMachineDto(); + centerMachineDto.setCenterId("10001"); + centerMachineDto.setMachineId("110001"); + centerMachineDto.setCenterStatus(true); + centerMachineDto.setMachineStatus(true); + centerMachineDto.setMachineRefId("10001_110001"); + when(masterDataService.getRegistrationCenterMachineDetails()).thenReturn(centerMachineDto); + when(identitySchemaRepository.getLatestSchemaVersion()).thenReturn(1.3); + when(keyStoreRepository.getCertificateData("10001_110001")).thenReturn("dummy_cert"); + when(globalParamRepository.getCachedIntegerGlobalParam(Mockito.anyString())).thenReturn(3); + File mockFile = mock(File.class); + when(mockFile.getUsableSpace()).thenReturn(100L * (1024 * 1024)); + when(mockApplicationContext.getExternalCacheDir()).thenReturn(mockFile); + + // Execute with null longitude (partial GPS) + RegistrationDto result = registrationService.startRegistration( + Arrays.asList("eng"), "NEW", "NEW", 12.9716, null); + + // Verify: Registration succeeds, no GPS set, no validation called + assertNotNull(result); + assertNull(result.getGeoLocationDto()); + verify(preCheckValidatorService, never()).validateCenterToMachineDistance(any(), any()); + } } \ No newline at end of file diff --git a/assets/l10n/app_ar.arb b/assets/l10n/app_ar.arb index 9ae5a0df3..8e3f85415 100644 --- a/assets/l10n/app_ar.arb +++ b/assets/l10n/app_ar.arb @@ -302,7 +302,7 @@ "logout_success": "لقد تم تسجيل بنجاح!", "logout_failure": "حدث خطأ ما، يرجى المحاولة مرة أخرى بعد مرور بعض الوقت", "go_to_home": "اذهب إلى المنزل", - "errors": "{messages, select, REG_TRY_AGAIN{فشل تسجيل الدخول. حاول مرة أخرى!} REG_INVALID_REQUEST{كلمة المرور غير صحيحة!} REG_MACHINE_NOT_FOUND{لم يتم تسجيل هذا الجهاز بعد. يرجى التواصل مع المسؤول للحصول على المساعدة!} REG_NETWORK_ERROR{فشل تسجيل الدخول. تحقق من اتصال الشبكة!} REG_CRED_EXPIRED{لم يتم العثور على بيانات الاعتماد أو انتهت صلاحيتها. يرجى محاولة تسجيل الدخول عبر الإنترنت!} REG_MACHINE_INACTIVE{الآلة غير نشطة!} REG_CENTER_INACTIVE{المركز غير نشط!} REG_LOGIN_LOCKED{تم الوصول إلى الحد الأقصى لمحاولة تسجيل الدخول. حاول مرة أخرى لاحقا!} KER_SYN_AUTH_001{تعذر الحصول على رمز المصادقة!} PAK_APPRVL_MAX_TIME{الإجراء المطلوب: لقد تجاوزت الحزم المسجلة المعلقة وقت الموافقة المسموح به. يرجى مسح التراكم للمتابعة.} PAK_UPLOAD_MAX_TIME{الإجراء المطلوب: تحميل الحزم أو تصديرها إلى الخادم قبل متابعة التسجيل.} PAK_UPLOAD_MAX_COUNT{الإجراء المطلوب: تم الوصول إلى الحد الأقصى للحزمة. الرجاء تصدير أو تحميل الحزم الموجودة قبل إنشاء تسجيلات جديدة.} PAK_DISK_SPACE_LOW{الحد الأدنى من المساحة المطلوبة غير متوفر لإنشاء الحزمة.} REG_PKT_APPRVL_CNT_EXCEED{تم الوصول إلى الحد الأقصى لعدد حزم التسجيل المعلقة للموافقة على العميل. يرجى الموافقة على الحزم أو رفضها قبل متابعة هذا التسجيل.} other{'Some error occurred!'}}", + "errors": "{messages, select, REG_TRY_AGAIN{فشل تسجيل الدخول. حاول مرة أخرى!} REG_INVALID_REQUEST{كلمة المرور غير صحيحة!} REG_MACHINE_NOT_FOUND{لم يتم تسجيل هذا الجهاز بعد. يرجى التواصل مع المسؤول للحصول على المساعدة!} REG_NETWORK_ERROR{فشل تسجيل الدخول. تحقق من اتصال الشبكة!} REG_CRED_EXPIRED{لم يتم العثور على بيانات الاعتماد أو انتهت صلاحيتها. يرجى محاولة تسجيل الدخول عبر الإنترنت!} REG_MACHINE_INACTIVE{الآلة غير نشطة!} REG_CENTER_INACTIVE{المركز غير نشط!} REG_LOGIN_LOCKED{تم الوصول إلى الحد الأقصى لمحاولة تسجيل الدخول. حاول مرة أخرى لاحقا!} KER_SYN_AUTH_001{تعذر الحصول على رمز المصادقة!} PAK_APPRVL_MAX_TIME{الإجراء المطلوب: لقد تجاوزت الحزم المسجلة المعلقة وقت الموافقة المسموح به. يرجى مسح التراكم للمتابعة.} PAK_UPLOAD_MAX_TIME{الإجراء المطلوب: تحميل الحزم أو تصديرها إلى الخادم قبل متابعة التسجيل.} PAK_UPLOAD_MAX_COUNT{الإجراء المطلوب: تم الوصول إلى الحد الأقصى للحزمة. الرجاء تصدير أو تحميل الحزم الموجودة قبل إنشاء تسجيلات جديدة.} PAK_DISK_SPACE_LOW{الحد الأدنى من المساحة المطلوبة غير متوفر لإنشاء الحزمة.} REG_PKT_APPRVL_CNT_EXCEED{تم الوصول إلى الحد الأقصى لعدد حزم التسجيل المعلقة للموافقة على العميل. يرجى الموافقة على الحزم أو رفضها قبل متابعة هذا التسجيل.} OPT_TO_REG_TIME_SYNC_EXCEED{تجاوز الوقت منذ آخر مزامنة الحد الأقصى المسموح به. يرجى المزامنة من الخادم قبل المتابعة مع هذا التسجيل.} OPT_TO_REG_OUTSIDE_LOCATION{موقع جهاز العميل الخاص بك خارج مركز التسجيل. يرجى ملاحظة أنه يمكن إجراء التسجيل فقط من داخل مركز التسجيل} other{'Some error occurred!'}}", "@errors": { "description": "Error messages", "placeholders": { diff --git a/assets/l10n/app_en.arb b/assets/l10n/app_en.arb index 5463fe9a3..aaa4b15f6 100644 --- a/assets/l10n/app_en.arb +++ b/assets/l10n/app_en.arb @@ -302,7 +302,7 @@ "logout_success": "You have been successfully logged out!", "logout_failure": "Something went wrong, please try again after some time", "go_to_home": "Go To Home", - "errors": "{messages, select, REG_TRY_AGAIN{Login Failed. Try Again!} REG_INVALID_REQUEST{Password incorrect!} REG_MACHINE_NOT_FOUND{This device has not been onboarded yet. Please reach out to your administrator for assistance!} REG_NETWORK_ERROR{Login failed. Check network connection!} REG_CRED_EXPIRED{Credentials not found or are expired. Please try online login!} REG_MACHINE_INACTIVE{Machine is not active!} REG_CENTER_INACTIVE{Center is not active!} REG_LOGIN_LOCKED{Maximum login attempt limit reached. Try again later!} KER_SYN_AUTH_001{Unable to get Authentication Token!} PAK_APPRVL_MAX_TIME{Action required: Pending registered packets have exceeded the allowed approval time. Please clear the backlog to continue.} PAK_UPLOAD_MAX_TIME{Action required: Upload or export the packets to the server before proceeding with registration.} PAK_UPLOAD_MAX_COUNT{Action required: Packet limit reached. Please export or upload existing packets before creating new registrations.} PAK_DISK_SPACE_LOW{Minimum required space is not available to create the packet.} REG_PKT_APPRVL_CNT_EXCEED{Maximum number of registration packets pending approval on client reached. Please approve or reject packets before proceeding with this registration.} other{'Some error occurred!'}}", + "errors": "{messages, select, REG_TRY_AGAIN{Login Failed. Try Again!} REG_INVALID_REQUEST{Password incorrect!} REG_MACHINE_NOT_FOUND{This device has not been onboarded yet. Please reach out to your administrator for assistance!} REG_NETWORK_ERROR{Login failed. Check network connection!} REG_CRED_EXPIRED{Credentials not found or are expired. Please try online login!} REG_MACHINE_INACTIVE{Machine is not active!} REG_CENTER_INACTIVE{Center is not active!} REG_LOGIN_LOCKED{Maximum login attempt limit reached. Try again later!} KER_SYN_AUTH_001{Unable to get Authentication Token!} PAK_APPRVL_MAX_TIME{Action required: Pending registered packets have exceeded the allowed approval time. Please clear the backlog to continue.} PAK_UPLOAD_MAX_TIME{Action required: Upload or export the packets to the server before proceeding with registration.} PAK_UPLOAD_MAX_COUNT{Action required: Packet limit reached. Please export or upload existing packets before creating new registrations.} PAK_DISK_SPACE_LOW{Minimum required space is not available to create the packet.} REG_PKT_APPRVL_CNT_EXCEED{Maximum number of registration packets pending approval on client reached. Please approve or reject packets before proceeding with this registration.} OPT_TO_REG_TIME_SYNC_EXCEED{Time since last sync exceeded maximum limit. Please sync from server before proceeding with this registration.} OPT_TO_REG_OUTSIDE_LOCATION{Your client machine location is outside the registration center. Please note that registration can be done only from within the registration centre} other{'Some error occurred!'}}", "@errors": { "description": "Error messages", "placeholders": { diff --git a/assets/l10n/app_fr.arb b/assets/l10n/app_fr.arb index 566dfe778..58854ab8a 100644 --- a/assets/l10n/app_fr.arb +++ b/assets/l10n/app_fr.arb @@ -302,7 +302,7 @@ "logout_success": "Vous avez été déconnecté avec succès!", "logout_failure": "Quelque chose s'est mal passé, veuillez réessayer après un certain temps", "go_to_home": "Aller à la maison", - "errors": "{messages, select, REG_TRY_AGAIN{Echec de la connexion.. Réessayez!} REG_INVALID_REQUEST{Mot de passe incorrect!} REG_MACHINE_NOT_FOUND{Cet appareil n’a pas encore été intégré. Veuillez contacter votre administrateur pour obtenir de l’aide !} REG_NETWORK_ERROR{Échec de la connexion. Vérifiez la connexion réseau!} REG_CRED_EXPIRED{Les informations d’identification sont introuvables ou ont expiré. S’il vous plaît essayer la connexion en ligne!} REG_MACHINE_INACTIVE{La machine n'est pas active!} REG_CENTER_INACTIVE{Le centre n'est pas actif!} REG_LOGIN_LOCKED{Limite maximale de tentatives de connexion atteinte. Réessayez plus tard!} KER_SYN_AUTH_001{Impossible d’obtenir le jeton d’authentification!} PAK_APPRVL_MAX_TIME{Action requise : les paquets enregistrés en attente ont dépassé le délai d'approbation autorisé. Veuillez éliminer l'arriéré pour continuer.} PAK_UPLOAD_MAX_TIME{Action requise : Téléchargez ou exportez les paquets vers le serveur avant de procéder à l'enregistrement.} PAK_UPLOAD_MAX_COUNT{Action requise : limite de paquets atteinte. Veuillez exporter ou télécharger les paquets existants avant de créer de nouvelles inscriptions.} PAK_DISK_SPACE_LOW{L'espace minimum requis n'est pas disponible pour créer le paquet.} REG_PKT_APPRVL_CNT_EXCEED{Le nombre maximum de paquets d'enregistrement en attente d'approbation sur le client a été atteint. Veuillez approuver ou rejeter les paquets avant de procéder à cette inscription.} other{'Some error occurred!'}}", + "errors": "{messages, select, REG_TRY_AGAIN{Echec de la connexion.. Réessayez!} REG_INVALID_REQUEST{Mot de passe incorrect!} REG_MACHINE_NOT_FOUND{Cet appareil n’a pas encore été intégré. Veuillez contacter votre administrateur pour obtenir de l’aide !} REG_NETWORK_ERROR{Échec de la connexion. Vérifiez la connexion réseau!} REG_CRED_EXPIRED{Les informations d’identification sont introuvables ou ont expiré. S’il vous plaît essayer la connexion en ligne!} REG_MACHINE_INACTIVE{La machine n'est pas active!} REG_CENTER_INACTIVE{Le centre n'est pas actif!} REG_LOGIN_LOCKED{Limite maximale de tentatives de connexion atteinte. Réessayez plus tard!} KER_SYN_AUTH_001{Impossible d’obtenir le jeton d’authentification!} PAK_APPRVL_MAX_TIME{Action requise : les paquets enregistrés en attente ont dépassé le délai d'approbation autorisé. Veuillez éliminer l'arriéré pour continuer.} PAK_UPLOAD_MAX_TIME{Action requise : Téléchargez ou exportez les paquets vers le serveur avant de procéder à l'enregistrement.} PAK_UPLOAD_MAX_COUNT{Action requise : limite de paquets atteinte. Veuillez exporter ou télécharger les paquets existants avant de créer de nouvelles inscriptions.} PAK_DISK_SPACE_LOW{L'espace minimum requis n'est pas disponible pour créer le paquet.} REG_PKT_APPRVL_CNT_EXCEED{Le nombre maximum de paquets d'enregistrement en attente d'approbation sur le client a été atteint. Veuillez approuver ou rejeter les paquets avant de procéder à cette inscription.} OPT_TO_REG_TIME_SYNC_EXCEED{Le temps écoulé depuis la dernière synchronisation a dépassé la limite maximale. Veuillez synchroniser depuis le serveur avant de poursuivre cet enregistrement.} OPT_TO_REG_OUTSIDE_LOCATION{Votre emplacement de machine cliente est en dehors du centre d'enregistrement. Veuillez noter que l'enregistrement ne peut être effectué qu'à l'intérieur du centre d'enregistrement} other{'Some error occurred!'}}", "@errors": { "description": "Error messages", "placeholders": { diff --git a/assets/l10n/app_hi.arb b/assets/l10n/app_hi.arb index 751d0ff46..8bfff36b7 100644 --- a/assets/l10n/app_hi.arb +++ b/assets/l10n/app_hi.arb @@ -302,7 +302,7 @@ "logout_success": "आप सफलता पूर्वक लॉगआउट कर चुके हैं!", "logout_failure": "कुछ गलती हो गई है, कृपया कुछ समय बाद पुनः प्रयास करें", "go_to_home": "होम पर जाएं", -"errors": "{messages, select, REG_TRY_AGAIN{लॉगिन विफल रहा। फिर कोशिश करो!} REG_INVALID_REQUEST{पासवर्ड गलत है!} REG_MACHINE_NOT_FOUND{इस डिवाइस का ऑनबोर्डिंग अभी तक नहीं हुआ है। सहायता के लिए कृपया अपने प्रशासक से संपर्क करें!} REG_NETWORK_ERROR{लॉगिन विफल रहा। नेटवर्क कनेक्शन की जाँच करें!} REG_CRED_EXPIRED{क्रेडेंशियल्स नहीं मिले या समय सीमा समाप्त हो गई है. ऑनलाइन लॉगिन का प्रयास करें!} REG_MACHINE_INACTIVE{मशीन सक्रिय नहीं है!} REG_CENTER_INACTIVE{केंद्र सक्रिय नहीं है!} REG_LOGIN_LOCKED{अधिकतम लॉगिन प्रयास सीमा पूरी हो गई. बाद में पुन: प्रयास!} KER_SYN_AUTH_001{प्रमाणीकरण टोकन प्राप्त करने में असमर्थ!} PAK_APPRVL_MAX_TIME{कार्रवाई आवश्यक: लंबित पंजीकृत पैकेट स्वीकृत अनुमोदन समय से अधिक हो गए हैं। कृपया जारी रखने के लिए बैकलॉग साफ़ करें।} PAK_UPLOAD_MAX_TIME{कार्रवाई आवश्यक: पंजीकरण के साथ आगे बढ़ने से पहले पैकेट को सर्वर पर अपलोड या निर्यात करें।} PAK_UPLOAD_MAX_COUNT{कार्रवाई आवश्यक: पैकेट की सीमा पूरी हो गई. कृपया नए पंजीकरण बनाने से पहले मौजूदा पैकेट निर्यात या अपलोड करें।} PAK_DISK_SPACE_LOW{पैकेट बनाने के लिए न्यूनतम आवश्यक स्थान उपलब्ध नहीं है।} REG_PKT_APPRVL_CNT_EXCEED{क्लाइंट पर अनुमोदन के लिए लंबित पंजीकरण पैकेट की अधिकतम संख्या पूरी हो गई है। कृपया इस पंजीकरण के साथ आगे बढ़ने से पहले पैकेट को स्वीकृत या अस्वीकार करें।} other{'Some error occurred!'}}", + "errors": "{messages, select, REG_TRY_AGAIN{लॉगिन विफल रहा। फिर कोशिश करो!} REG_INVALID_REQUEST{पासवर्ड गलत है!} REG_MACHINE_NOT_FOUND{इस डिवाइस का ऑनबोर्डिंग अभी तक नहीं हुआ है। सहायता के लिए कृपया अपने प्रशासक से संपर्क करें!} REG_NETWORK_ERROR{लॉगिन विफल रहा। नेटवर्क कनेक्शन की जाँच करें!} REG_CRED_EXPIRED{क्रेडेंशियल्स नहीं मिले या समय सीमा समाप्त हो गई है. ऑनलाइन लॉगिन का प्रयास करें!} REG_MACHINE_INACTIVE{मशीन सक्रिय नहीं है!} REG_CENTER_INACTIVE{केंद्र सक्रिय नहीं है!} REG_LOGIN_LOCKED{अधिकतम लॉगिन प्रयास सीमा पूरी हो गई. बाद में पुन: प्रयास!} KER_SYN_AUTH_001{प्रमाणीकरण टोकन प्राप्त करने में असमर्थ!} PAK_APPRVL_MAX_TIME{कार्रवाई आवश्यक: लंबित पंजीकृत पैकेट स्वीकृत अनुमोदन समय से अधिक हो गए हैं। कृपया जारी रखने के लिए बैकलॉग साफ़ करें।} PAK_UPLOAD_MAX_TIME{कार्रवाई आवश्यक: पंजीकरण के साथ आगे बढ़ने से पहले पैकेट को सर्वर पर अपलोड या निर्यात करें।} PAK_UPLOAD_MAX_COUNT{कार्रवाई आवश्यक: पैकेट की सीमा पूरी हो गई. कृपया नए पंजीकरण बनाने से पहले मौजूदा पैकेट निर्यात या अपलोड करें।} PAK_DISK_SPACE_LOW{पैकेट बनाने के लिए न्यूनतम आवश्यक स्थान उपलब्ध नहीं है।} REG_PKT_APPRVL_CNT_EXCEED{क्लाइंट पर अनुमोदन के लिए लंबित पंजीकरण पैकेट की अधिकतम संख्या पूरी हो गई है। कृपया इस पंजीकरण के साथ आगे बढ़ने से पहले पैकेट को स्वीकृत या अस्वीकार करें।} OPT_TO_REG_TIME_SYNC_EXCEED{अंतिम सिंक के बाद से समय अधिकतम सीमा से अधिक हो गया है। कृपया इस पंजीकरण के साथ आगे बढ़ने से पहले सर्वर से सिंक करें।} OPT_TO_REG_OUTSIDE_LOCATION{आपका क्लाइंट मशीन स्थान पंजीकरण केंद्र के बाहर है। कृपया ध्यान दें कि पंजीकरण केवल पंजीकरण केंद्र के भीतर से किया जा सकता है} other{'Some error occurred!'}}", "@errors": { "description": "Error messages", "placeholders": { diff --git a/assets/l10n/app_kn.arb b/assets/l10n/app_kn.arb index 920fd5c59..3349896cc 100644 --- a/assets/l10n/app_kn.arb +++ b/assets/l10n/app_kn.arb @@ -302,7 +302,7 @@ "logout_success": "ನೀವು ಯಶಸ್ವಿಯಾಗಿ ಲಾಗ್ ಔಟ್ ಆಗಿರುವಿರಿ!", "logout_failure": "ಏನೋ ತಪ್ಪಾಗಿದೆ, ದಯವಿಟ್ಟು ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", "go_to_home": "ಮನೆಗೆ ಹೋಗು", -"errors": "{messages, select, REG_TRY_AGAIN{ಲಾಗಿನ್ ವಿಫಲವಾಗಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸು!} REG_INVALID_REQUEST{ಪಾಸ್ ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ!} REG_MACHINE_NOT_FOUND{ಈ ಸಾಧನವನ್ನು ಇನ್ನೂ ಆನ್‌ಬೋರ್ಡ್ ಮಾಡಿಲ್ಲ. ಸಹಾಯಕ್ಕಾಗಿ ದಯವಿಟ್ಟು ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ!} REG_NETWORK_ERROR{ಲಾಗಿನ್ ವಿಫಲವಾಗಿದೆ. ನೆಟ್ವರ್ಕ್ ಸಂಪರ್ಕ ಪರಿಶೀಲಿಸಿ!} REG_CRED_EXPIRED{ರುಜುವಾತುಗಳು ಸಿಗಲಿಲ್ಲ ಅಥವಾ ಅವಧಿ ಮೀರಿದವು. ದಯವಿಟ್ಟು ಆನ್ ಲೈನ್ ಲಾಗಿನ್ ಪ್ರಯತ್ನಿಸಿ!} REG_MACHINE_INACTIVE{ಯಂತ್ರ ಸಕ್ರಿಯವಾಗಿಲ್ಲ!} REG_CENTER_INACTIVE{ಕೇಂದ್ರವು ಸಕ್ರಿಯವಾಗಿಲ್ಲ!} REG_LOGIN_LOCKED{ಗರಿಷ್ಠ ಲಾಗಿನ್ ಪ್ರಯತ್ನದ ಮಿತಿಯನ್ನು ತಲುಪಿದೆ. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ!} KER_SYN_AUTH_001{ದೃಢೀಕರಣ ಟೋಕನ್ ಪಡೆಯಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ!} PAK_APPRVL_MAX_TIME{ಕ್ರಮದ ಅಗತ್ಯವಿದೆ: ಬಾಕಿ ಉಳಿದಿರುವ ನೋಂದಾಯಿತ ಪ್ಯಾಕೆಟ್‌ಗಳು ಅನುಮತಿಸಲಾದ ಅನುಮೋದನೆ ಸಮಯವನ್ನು ಮೀರಿದೆ. ಮುಂದುವರಿಸಲು ದಯವಿಟ್ಟು ಬ್ಯಾಕ್‌ಲಾಗ್ ಅನ್ನು ತೆರವುಗೊಳಿಸಿ.} PAK_UPLOAD_MAX_TIME{ಕ್ರಮದ ಅಗತ್ಯವಿದೆ: ನೋಂದಣಿಯೊಂದಿಗೆ ಮುಂದುವರಿಯುವ ಮೊದಲು ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಸರ್ವರ್‌ಗೆ ಅಪ್‌ಲೋಡ್ ಮಾಡಿ ಅಥವಾ ರಫ್ತು ಮಾಡಿ.} PAK_UPLOAD_MAX_COUNT{ಕ್ರಮದ ಅಗತ್ಯವಿದೆ: ಪ್ಯಾಕೆಟ್ ಮಿತಿಯನ್ನು ತಲುಪಿದೆ. ಹೊಸ ನೋಂದಣಿಗಳನ್ನು ರಚಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ರಫ್ತು ಮಾಡಿ ಅಥವಾ ಅಪ್‌ಲೋಡ್ ಮಾಡಿ.} PAK_DISK_SPACE_LOW{ಪ್ಯಾಕೆಟ್ ರಚಿಸಲು ಅಗತ್ಯವಿರುವ ಕನಿಷ್ಟ ಸ್ಥಳಾವಕಾಶ ಲಭ್ಯವಿಲ್ಲ.} REG_PKT_APPRVL_CNT_EXCEED{ಕ್ಲೈಂಟ್‌ನಲ್ಲಿ ಅನುಮೋದನೆಗಾಗಿ ಬಾಕಿ ಉಳಿದಿರುವ ನೋಂದಣಿ ಪ್ಯಾಕೆಟ್‌ಗಳ ಗರಿಷ್ಠ ಸಂಖ್ಯೆಯನ್ನು ತಲುಪಿದೆ. ಈ ನೋಂದಣಿಯೊಂದಿಗೆ ಮುಂದುವರಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಅನುಮೋದಿಸಿ ಅಥವಾ ತಿರಸ್ಕರಿಸಿ.} other{'Some error occurred!'}}", + "errors": "{messages, select, REG_TRY_AGAIN{ಲಾಗಿನ್ ವಿಫಲವಾಗಿದೆ. ಮತ್ತೆ ಪ್ರಯತ್ನಿಸು!} REG_INVALID_REQUEST{ಪಾಸ್ ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ!} REG_MACHINE_NOT_FOUND{ಈ ಸಾಧನವನ್ನು ಇನ್ನೂ ಆನ್‌ಬೋರ್ಡ್ ಮಾಡಿಲ್ಲ. ಸಹಾಯಕ್ಕಾಗಿ ದಯವಿಟ್ಟು ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ!} REG_NETWORK_ERROR{ಲಾಗಿನ್ ವಿಫಲವಾಗಿದೆ. ನೆಟ್ವರ್ಕ್ ಸಂಪರ್ಕ ಪರಿಶೀಲಿಸಿ!} REG_CRED_EXPIRED{ರುಜುವಾತುಗಳು ಸಿಗಲಿಲ್ಲ ಅಥವಾ ಅವಧಿ ಮೀರಿದವು. ದಯವಿಟ್ಟು ಆನ್ ಲೈನ್ ಲಾಗಿನ್ ಪ್ರಯತ್ನಿಸಿ!} REG_MACHINE_INACTIVE{ಯಂತ್ರ ಸಕ್ರಿಯವಾಗಿಲ್ಲ!} REG_CENTER_INACTIVE{ಕೇಂದ್ರವು ಸಕ್ರಿಯವಾಗಿಲ್ಲ!} REG_LOGIN_LOCKED{ಗರಿಷ್ಠ ಲಾಗಿನ್ ಪ್ರಯತ್ನದ ಮಿತಿಯನ್ನು ತಲುಪಿದೆ. ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ!} KER_SYN_AUTH_001{ದೃಢೀಕರಣ ಟೋಕನ್ ಪಡೆಯಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ!} PAK_APPRVL_MAX_TIME{ಕ್ರಮದ ಅಗತ್ಯವಿದೆ: ಬಾಕಿ ಉಳಿದಿರುವ ನೋಂದಾಯಿತ ಪ್ಯಾಕೆಟ್‌ಗಳು ಅನುಮತಿಸಲಾದ ಅನುಮೋದನೆ ಸಮಯವನ್ನು ಮೀರಿದೆ. ಮುಂದುವರಿಸಲು ದಯವಿಟ್ಟು ಬ್ಯಾಕ್‌ಲಾಗ್ ಅನ್ನು ತೆರವುಗೊಳಿಸಿ.} PAK_UPLOAD_MAX_TIME{ಕ್ರಮದ ಅಗತ್ಯವಿದೆ: ನೋಂದಣಿಯೊಂದಿಗೆ ಮುಂದುವರಿಯುವ ಮೊದಲು ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಸರ್ವರ್‌ಗೆ ಅಪ್‌ಲೋಡ್ ಮಾಡಿ ಅಥವಾ ರಫ್ತು ಮಾಡಿ.} PAK_UPLOAD_MAX_COUNT{ಕ್ರಮದ ಅಗತ್ಯವಿದೆ: ಪ್ಯಾಕೆಟ್ ಮಿತಿಯನ್ನು ತಲುಪಿದೆ. ಹೊಸ ನೋಂದಣಿಗಳನ್ನು ರಚಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ರಫ್ತು ಮಾಡಿ ಅಥವಾ ಅಪ್‌ಲೋಡ್ ಮಾಡಿ.} PAK_DISK_SPACE_LOW{ಪ್ಯಾಕೆಟ್ ರಚಿಸಲು ಅಗತ್ಯವಿರುವ ಕನಿಷ್ಟ ಸ್ಥಳಾವಕಾಶ ಲಭ್ಯವಿಲ್ಲ.} REG_PKT_APPRVL_CNT_EXCEED{ಕ್ಲೈಂಟ್‌ನಲ್ಲಿ ಅನುಮೋದನೆಗಾಗಿ ಬಾಕಿ ಉಳಿದಿರುವ ನೋಂದಣಿ ಪ್ಯಾಕೆಟ್‌ಗಳ ಗರಿಷ್ಠ ಸಂಖ್ಯೆಯನ್ನು ತಲುಪಿದೆ. ಈ ನೋಂದಣಿಯೊಂದಿಗೆ ಮುಂದುವರಿಸುವ ಮೊದಲು ದಯವಿಟ್ಟು ಪ್ಯಾಕೆಟ್‌ಗಳನ್ನು ಅನುಮೋದಿಸಿ ಅಥವಾ ತಿರಸ್ಕರಿಸಿ.} OPT_TO_REG_TIME_SYNC_EXCEED{ಕೊನೆಯ ಸಿಂಕ್‌ನಿಂದ ಸಮಯವು ಗರಿಷ್ಠ ಮಿತಿಯನ್ನು ಮೀರಿದೆ. ಈ ನೋಂದಣಿಯೊಂದಿಗೆ ಮುಂದುವರಿಯುವ ಮೊದಲು ದಯವಿಟ್ಟು ಸರ್ವರ್‌ನಿಂದ ಸಿಂಕ್ ಮಾಡಿ.} OPT_TO_REG_OUTSIDE_LOCATION{ನಿಮ್ಮ ಕ್ಲೈಂಟ್ ಯಂತ್ರದ ಸ್ಥಳವು ನೋಂದಣಿ ಕೇಂದ್ರದ ಹೊರಗಿದೆ. ನೋಂದಣಿಯನ್ನು ನೋಂದಣಿ ಕೇಂದ್ರದೊಳಗೆ ಮಾತ್ರ ಮಾಡಬಹುದು ಎಂಬುದನ್ನು ದಯವಿಟ್ಟು ಗಮನಿಸಿ} other{'Some error occurred!'}}", "@errors": { "description": "Error messages", "placeholders": { diff --git a/assets/l10n/app_ta.arb b/assets/l10n/app_ta.arb index eee216deb..e224d48cf 100644 --- a/assets/l10n/app_ta.arb +++ b/assets/l10n/app_ta.arb @@ -311,7 +311,7 @@ "logout_success": "நீங்கள் வெற்றிகரமாக வெளியேறிவிட்டீர்கள்!", "logout_failure": "ஏதோ தவறாகிவிட்டது, சிறிது நேரம் கழித்து மீண்டும் முயற்சிக்கவும்", "go_to_home": "வீட்டிற்கு போ", -"errors": "{messages, select, REG_TRY_AGAIN{உள்நுழைவு தோல்வியுற்றது. மீண்டும் முயற்சி செய்!} REG_INVALID_REQUEST{கடவுச்சொல் தவறானது!} REG_MACHINE_NOT_FOUND{இந்த சாதனம் இன்னும் பதிவுசெய்யப்படவில்லை. உதவிக்காக உங்கள் நிர்வாகியை தொடர்புகொள்ளுங்கள்!} REG_NETWORK_ERROR{உள்நுழைவு தோல்வியுற்றது. நெட்வொர்க் இணைப்பை சரிபார்க்கவும்!} REG_CRED_EXPIRED{நற்சான்றிதழ்கள் காணப்படவில்லை அல்லது காலாவதியாகவில்லை. ஆன்லைன் உள்நுழைவை முயற்சிக்கவும்!} REG_MACHINE_INACTIVE{இயந்திரம் செயலில் இல்லை!} REG_CENTER_INACTIVE{மையம் செயல்படவில்லை!} REG_LOGIN_LOCKED{அதிகபட்ச உள்நுழைவு முயற்சி வரம்பை அடைந்தது. பிறகு முயற்சிக்கவும்!} KER_SYN_AUTH_001{அங்கீகார டோக்கனை பெற முடியவில்லை!} PAK_APPRVL_MAX_TIME{நடவடிக்கை தேவை: நிலுவையிலுள்ள பதிவு செய்யப்பட்ட பாக்கெட்டுகள் அனுமதிக்கப்பட்ட அனுமதி நேரத்தை மீறியுள்ளன. தொடர, பின்னிணைப்பை அழிக்கவும்.} PAK_UPLOAD_MAX_TIME{நடவடிக்கை தேவை: பதிவைத் தொடர்வதற்கு முன், சர்வரில் பாக்கெட்டுகளைப் பதிவேற்றவும் அல்லது ஏற்றுமதி செய்யவும்.} PAK_UPLOAD_MAX_COUNT{நடவடிக்கை தேவை: பாக்கெட் வரம்பை அடைந்தது. புதிய பதிவுகளை உருவாக்கும் முன் ஏற்கனவே உள்ள பாக்கெட்டுகளை ஏற்றுமதி செய்யவும் அல்லது பதிவேற்றவும்.} PAK_DISK_SPACE_LOW{பாக்கெட்டை உருவாக்க தேவையான குறைந்தபட்ச இடம் இல்லை.} REG_PKT_APPRVL_CNT_EXCEED{கிளையண்டில் ஒப்புதலுக்காக காத்திருக்கும் பதிவு பாக்கெட்களின் அதிகபட்ச எண்ணிக்கை அடைந்தது. இந்த பதிவைத் தொடர்வதற்கு முன் பாக்கெட்களை ஒப்புதல் அல்லது நிராகரிக்கவும்.} other{'Some error occurred!'}}", + "errors": "{messages, select, REG_TRY_AGAIN{உள்நுழைவு தோல்வியுற்றது. மீண்டும் முயற்சி செய்!} REG_INVALID_REQUEST{கடவுச்சொல் தவறானது!} REG_MACHINE_NOT_FOUND{இந்த சாதனம் இன்னும் பதிவுசெய்யப்படவில்லை. உதவிக்காக உங்கள் நிர்வாகியை தொடர்புகொள்ளுங்கள்!} REG_NETWORK_ERROR{உள்நுழைவு தோல்வியுற்றது. நெட்வொர்க் இணைப்பை சரிபார்க்கவும்!} REG_CRED_EXPIRED{நற்சான்றிதழ்கள் காணப்படவில்லை அல்லது காலாவதியாகவில்லை. ஆன்லைன் உள்நுழைவை முயற்சிக்கவும்!} REG_MACHINE_INACTIVE{இயந்திரம் செயலில் இல்லை!} REG_CENTER_INACTIVE{மையம் செயல்படவில்லை!} REG_LOGIN_LOCKED{அதிகபட்ச உள்நுழைவு முயற்சி வரம்பை அடைந்தது. பிறகு முயற்சிக்கவும்!} KER_SYN_AUTH_001{அங்கீகார டோக்கனை பெற முடியவில்லை!} PAK_APPRVL_MAX_TIME{நடவடிக்கை தேவை: நிலுவையிலுள்ள பதிவு செய்யப்பட்ட பாக்கெட்டுகள் அனுமதிக்கப்பட்ட அனுமதி நேரத்தை மீறியுள்ளன. தொடர, பின்னிணைப்பை அழிக்கவும்.} PAK_UPLOAD_MAX_TIME{நடவடிக்கை தேவை: பதிவைத் தொடர்வதற்கு முன், சர்வரில் பாக்கெட்டுகளைப் பதிவேற்றவும் அல்லது ஏற்றுமதி செய்யவும்.} PAK_UPLOAD_MAX_COUNT{நடவடிக்கை தேவை: பாக்கெட் வரம்பை அடைந்தது. புதிய பதிவுகளை உருவாக்கும் முன் ஏற்கனவே உள்ள பாக்கெட்டுகளை ஏற்றுமதி செய்யவும் அல்லது பதிவேற்றவும்.} PAK_DISK_SPACE_LOW{பாக்கெட்டை உருவாக்க தேவையான குறைந்தபட்ச இடம் இல்லை.} REG_PKT_APPRVL_CNT_EXCEED{கிளையண்டில் ஒப்புதலுக்காக காத்திருக்கும் பதிவு பாக்கெட்களின் அதிகபட்ச எண்ணிக்கை அடைந்தது. இந்த பதிவைத் தொடர்வதற்கு முன் பாக்கெட்களை ஒப்புதல் அல்லது நிராகரிக்கவும்.} OPT_TO_REG_TIME_SYNC_EXCEED{கடைசி ஒத்திசைவிலிருந்து நேரம் அதிகபட்ச வரம்பை மீறியுள்ளது. இந்த பதிவைத் தொடர்வதற்கு முன் தயவுசெய்து சர்வரிலிருந்து ஒத்திசைக்கவும்.} OPT_TO_REG_OUTSIDE_LOCATION{உங்கள் கிளையன் இயந்திர இடம் பதிவு மையத்திற்கு வெளியே உள்ளது. பதிவு பதிவு மையத்திற்குள் மட்டுமே செய்யப்படலாம் என்பதை தயவுசெய்து கவனிக்கவும்} other{'Some error occurred!'}}", "@errors": { "description": "Error messages", "placeholders": { diff --git a/lib/platform_android/registration_service_impl.dart b/lib/platform_android/registration_service_impl.dart index cbce62dea..5462ae987 100644 --- a/lib/platform_android/registration_service_impl.dart +++ b/lib/platform_android/registration_service_impl.dart @@ -12,12 +12,12 @@ import 'package:registration_client/platform_spi/registration_service.dart'; class RegistrationServiceImpl implements RegistrationService { @override - Future startRegistration( - List langauages, String flowType, String process) async { + Future startRegistration(List languages, String flowType, + String process, double? latitude, double? longitude) async { String registrationStartResponse = ''; try { registrationStartResponse = await RegistrationDataApi() - .startRegistration(langauages, flowType, process); + .startRegistration(languages, flowType, process, latitude, longitude); } on PlatformException { registrationStartResponse = "Something went wrong!"; debugPrint('RegApi call failed'); diff --git a/lib/platform_spi/registration_service.dart b/lib/platform_spi/registration_service.dart index 866db15ce..ef24310f0 100644 --- a/lib/platform_spi/registration_service.dart +++ b/lib/platform_spi/registration_service.dart @@ -9,8 +9,8 @@ import 'package:registration_client/pigeon/registration_data_pigeon.dart'; import 'package:registration_client/platform_android/registration_service_impl.dart'; abstract class RegistrationService { - Future startRegistration( - List languages, String flopwType, String process); + Future startRegistration(List languages, String flowType, + String process, double? latitude, double? longitude); Future evaluateMVELVisible(String fieldData); Future evaluateMVELRequired(String fieldData); Future getPreviewTemplate( diff --git a/lib/provider/global_provider.dart b/lib/provider/global_provider.dart index 16914d4f2..6b5dae46d 100644 --- a/lib/provider/global_provider.dart +++ b/lib/provider/global_provider.dart @@ -5,6 +5,7 @@ * */ +import 'dart:async'; import 'dart:developer'; import 'package:flutter/services.dart'; @@ -941,8 +942,14 @@ class GlobalProvider with ChangeNotifier { } // Fetch location if permission is granted - return await Geolocator.getCurrentPosition( - desiredAccuracy: LocationAccuracy.high, - ); + // Add timeout to prevent indefinite hanging + try { + return await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.high, + timeLimit: const Duration(seconds: 10), + ); + } on TimeoutException { + return null; + } } } diff --git a/lib/provider/registration_task_provider.dart b/lib/provider/registration_task_provider.dart index 2eee264cc..6d3211e3d 100644 --- a/lib/provider/registration_task_provider.dart +++ b/lib/provider/registration_task_provider.dart @@ -134,10 +134,10 @@ class RegistrationTaskProvider with ChangeNotifier { notifyListeners(); } - startRegistration( - List languages, String flowType, String process) async { + startRegistration(List languages, String flowType, String process, + {double? latitude, double? longitude}) async { _registrationStartError = await registrationService.startRegistration( - languages, flowType, process); + languages, flowType, process, latitude, longitude); notifyListeners(); } diff --git a/lib/ui/process_ui/generic_process.dart b/lib/ui/process_ui/generic_process.dart index 9e5521a3c..a8ee190cb 100644 --- a/lib/ui/process_ui/generic_process.dart +++ b/lib/ui/process_ui/generic_process.dart @@ -100,23 +100,6 @@ class _GenericProcessState extends State }, )); _registrationScreenLoadedAudit(); - WidgetsBinding.instance.addPostFrameCallback((_) async { - await _fetchLocation(); - }); - } - - bool _locationFetched = false; - - Future _fetchLocation() async { - if (_locationFetched) return; - _locationFetched = true; - - Position? position = await globalProvider.fetchLocation(); - if (position != null) { - registrationTaskProvider.setCurrentLocation(position.latitude, position.longitude); - } else { - debugPrint("Location unavailable — permission denied or service off."); - } } @override diff --git a/lib/ui/process_ui/widgets/language_selector.dart b/lib/ui/process_ui/widgets/language_selector.dart index c57256cb8..28e4445c9 100644 --- a/lib/ui/process_ui/widgets/language_selector.dart +++ b/lib/ui/process_ui/widgets/language_selector.dart @@ -82,13 +82,29 @@ class _LanguageSelectorState extends State { globalProvider.fieldDisplayValues = {}; await globalProvider.fieldValues(widget.newProcess); + // Capture GPS location before starting registration to validate distance + double? latitude; + double? longitude; + try { + final position = await globalProvider.fetchLocation() + .timeout(const Duration(seconds: 10), onTimeout: () => null); + if (position != null) { + latitude = position.latitude; + longitude = position.longitude; + } + } catch (e) { + debugPrint("GPS location capture failed: $e"); + } + List langList = _getRegistrationLanguageList(); await registrationTaskProvider.startRegistration( langList, widget.newProcess.flow! == "UPDATE" ? "Update" : widget.newProcess.flow!, - widget.newProcess.id!); + widget.newProcess.id!, + latitude: latitude, + longitude: longitude); registrationTaskProvider.addDemographicField("preferredLang", globalProvider.fieldInputValue["preferredLang"].toString()); diff --git a/pigeon/registration_data.dart b/pigeon/registration_data.dart index 0632b3379..2ea818aa9 100644 --- a/pigeon/registration_data.dart +++ b/pigeon/registration_data.dart @@ -13,8 +13,8 @@ class RegistrationSubmitResponse { @HostApi() abstract class RegistrationDataApi { @async - String startRegistration( - List languages, String flowType, String process); + String startRegistration(List languages, String flowType, + String process, double? latitude, double? longitude); @async bool evaluateMVELVisible(String fieldData);